在我的情况下,我尝试创建一个简单的表单组件 - 主要用于"测试"reactjs并使用它.
为此,我使用2个组件.第一个Component是Parent,即"Form"组件.第二个Component是表单的字段 - 例如简单的文本字段.这是它看起来像的标记:
在MyFormSchema中,我拥有"输入"类型的每个子项所需的所有信息.对于这种情况,我在我的"表单"组件中完成了这个:
Form.jsx
Form = React.createClass({ renderChildren() { return React.Children.map(this.props.children, (child)=>{ if (child.type && child.type.prototype && child.type.prototype.constructor.displayName === 'Input') { let additionalProps = { fieldSchema: this.props.schema.pick(child.props.name), onChange: this.onChange }; return React.cloneElement(child, additionalProps); } return child; }); }, render() { return(); } });
我在这里做的是"克隆"每个"输入"子项并根据模式添加一些新的道具.
所以第一个问题是:
这真的是reactJs的正确战争吗?当我没有"克隆"每个元素并添加新属性时,我必须直接在我的视图中添加属性,对吧?有点像但是我试图阻止这个因为我需要的所有信息我已经在我的表格模式中作为道具.
在玩完这个后我发现,这个.props.children只有第一级孩子.但是当我在我的Form
组件中嵌套我的子项时,我的组件正在用Input
被操作的组件替换组件将不再起作用.
例:
当我这样做时,我现在正在做这个代码将不再起作用,因为在this.props.children中我只有[AnotherComponent,Input [name = age]]并且缺少Input [name = name].所以我认为我这样做的方式是错误的.但我不确定.
所以主要的问题是:
就像在我的例子中一样:ReactJs在所有孩子(也包括嵌套者)中继承道具(或者什么)的正确方法是什么 - 或者这是不可能的"反应"方式,我真的必须通过所有必要的道具给所有孩子?
编辑:
当我在谈论"向所有孩子传递所有必要的道具"时,我的意思是这样的:
在这个例子中,我将传递我想要由父级动态添加的所有必要的道具.在我上面的例子中,下一个问题是:"this"因为其父AnotherComponent而不能用于名称输入.所以我必须引用父母 - 当然:它可能,但我认为这将是一个丑陋的方式.
你可以这样使用react-addons-clone-with-props包:
import React, { Component } from 'react'; import cloneWithProps from 'react-addons-clone-with-props'; // ... class Form extends Component { recursivelyMapChildren(children) { return React.Children.map(children, child => { if (!React.isValidElement(child)) { return child; } return React.cloneElement(child, { ...child.props, children: this.recursiveCloneChildren(child.props.children) }); }) } render() { return (); } }
代码的作用:
通过预定义的children
prop 获取所有子组件(请参阅docs).
使用React.Children.map
方法递归映射子集合,将lambda函数应用于每个元素.
将映射的(即更新的,但未变异的!)子元素保存为mappedChildren
常量.
将它们放在form
DOM元素中.
它看起来很简单,应该是这样.
但是你必须记住,当代码保持干净透明时,React很棒.当您明确传递道具时
当你意外地改变底层逻辑时,会有更少的东西被破坏.
深度传递道具有三种正确的方法:
1)实际上实际上将它们从每个组件传递到下一个组件(这是最可读的(就代码逻辑而言),但是一旦你有太多的道具传递并且你的树中有很多级别,就会变得笨拙.
例:
import React from 'react'; var GrandParent = React.createClass({ render () { return (); } }); var Parent = React.createClass({ render () { return ( ); } }); var Child = React.createClass({ render () { return ( {'Our family name is ' + props.familyName}
); } });
2)使用Flux风格的商店(我更喜欢Reflux,虽然Redux现在风靡一时)保持共同状态.然后,所有组件都可以访问该商店.至少对我来说,这是目前首选的方法.它很清楚,它可以保持业务逻辑不受组件的影响.
示例(使用Reflux):
import React from 'react'; import Reflux from 'reflux'; var MyStore = Reflux.createStore({ // This will be called in every component that connects to the store getInitialState () { return { // Contents of MyFormSchema here }; } }); var Input = React.createClass({ propTypes: { name: React.PropTypes.string.isRequired }, mixins: [Reflux.connect(MyStore)], render () { // I don't know what MyFormSchema so I'm generalizing here, but lets pretend its a map that uses the name of each field a key and then has properties of that field within the map stored at the key/value return ( ); } });
3)使用React的上下文功能.正如您在查看文档时所看到的那样,此功能仍处于开发阶段,可能会在未来版本的React中进行更改甚至删除.因此,虽然它可能是将组件树中的道具传递下来的最简单方法,但我个人却远离它,直到它变成了最终的功能.
我不打算为这个写一个例子,因为文档非常清楚.但是,请务必向下滚动文档页面并查看父子耦合,这就是您现在正在做的事情.
另一个解决方案是,为什么不是像现在那样将prop传递给Form,而是简单地使用's 渲染个体,而不是使用单个组件渲染Form
它Input
的s .Input
Form
render()