谈及 React 时,就会想到一个很重要的思想,就是组件化思想。它将可以重用的部分进行组件化开发,形成一个个相对独立的组件,那么组件化后,你也会提出些疑问,组件与组件之间,将怎样进行信息的传递呢? 下面来介绍下组件之间传递信息的方法。
组件之间传递信息方式,总体可分为以下 5 种:
1.(父组件)向(子组件)传递信息
2.(父组件)向更深层的(子组件) 进行传递信息 >> 利用(context)
3.(子组件)向(父组件)传递信息
4. 没有任何嵌套关系的组件之间传值(比如:兄弟组件之间传值)
5. 利用 react-redux 进行组件之间的状态信息共享
下面结合实例详细说明种传递信息的方式。
以下的例子都是比较经典的例子,看过后加入了我的个人见解,希望对你们有所帮助。
一.(父组件)向(子组件)传递信息 >>> 主要是通过 prop 进行传值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var MyContainer = React.createClass({ getInitialState: function () { return { checked: false }; }, render: function() { return ( <ToggleButton text="Toggle me" checked={this.state.checked} /> ); } });
var ToggleButton = React.createClass({ render: function () { var checked = this.props.checked, text = this.props.text; return ( <label>{text}: <input type="checkbox" checked={checked} /></label> ); } })
|
以上这个例子,子组件通过 prop 拿到了 text 值以及 checked 的属性值;那么当子组件要拿到祖父级组件的信息,也是可以通过 prop 进行逐层的获取。来看下下面的例子。
官方文档的示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| var Button = React.createClass({ render: function() { return ( <utton style={{background: this.props.color}}> {this.props.children} </utton> ); } }); var Message = React.createClass({ render: function() { return ( <div> {this.props.text} <Button color={this.props.color}>Delete</Button> </div> ); } }); var MessageList = React.createClass({ render: function() { var color = "purple"; var children = this.props.messages.map(function(message) { return <Message text={message.text} color={color} />; });
return <div>{children}</div>; } });
|
以上的例子中第一层组件(MessageList)想要将 color 值传递到第三层组件(Button),通过第二层组件(Message)进行了传递。进而实现了。但是这种方式,并不是很优雅,如果传递的层级更多时,中间的层级都需要来传递,数据的传递变的更加繁琐。所以我们就会想到,是否可以”越级”获取数据。这时候就需要使用 context。能帮你 “越级” 传递数据到组件中你想传递到的深层次组件中。
二.(父组件)向更深层的(子组件) 进行传递信息
利用(context)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| var Button = React.createClass({ contextTypes: { color: React.PropTypes.string }, render: function () { return ( <button style={{background: this.context.color}}> {this.props.children} </button> ); } });
var Message = React.createClass({ render: function () { return ( <div> {this.props.text} <Button>Delete</Button> </div> ); } });
var MessageList = React.createClass({ // 父组件要定义 childContextTypes 和 getChildContext() childContextTypes: { color: React.PropTypes.string }, getChildContext: function () { return {color: "purple"}; }, render: function () { var children = this.props.messages.map(function (message) { return <Message text={message.text}/>; }); return <div>{children}</div>; } });
|
以上代码中通过添加 childContextTypes 和 getChildContext() 到 第一层组件 MessageList ( context 的提供者),React 自动向下传递数据然后在组件中的任意组件(也就是说任意子组件,在此示例代码中也就是 Button )都能通过定义 contextTypes(必须指定 context 的数据类型) 访问 context 中的数据。这样就不需要通过第二层组件进行传递了。
指定数据并要将数据传递下去的父组件要定义 childContextTypes 和 getChildContext() ;想要接收到数据的子组件 必须定义 contextTypes 来使用传递过来的 context
三.(子组件)向(父组件)传递信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| var MyContainer = React.createClass({ getInitialState: function () { return { checked: false }; }, onChildChanged: function (newState) { this.setState({ checked: newState }); }, render: function () { var isChecked = this.state.checked ? 'yes' : 'no'; return ( <div> <div>Are you checked: {isChecked}</div> <ToggleButton text="Toggle me" initialChecked={this.state.checked} callbackParent={this.onChildChanged} /> </div> ); } });
// 子组件 var ToggleButton = React.createClass({ getInitialState: function () { return { checked: this.props.initialChecked }; }, onTextChange: function () { var newState = !this.state.checked; this.setState({ checked: newState });
// 这里将子组件的信息传递给了父组件 this.props.callbackParent(newState); }, render: function () { // 从(父组件)获取的值 var text = this.props.text; // 组件自身的状态数据 var checked = this.state.checked; //onchange 事件用于单选框与复选框改变后触发的事件。 return ( <label>{text}: <input type="checkbox" checked={checked} onChange={this.onTextChange}/></label> ); } });
|
以上例子中,在父组件绑定 callbackParent={this.onChildChanged},在子组件利用 this.props.callbackParent(newState), 触发了父级的的 this.onChildChanged 方法,进而将子组件的数据(newState)传递到了父组件。
这样做其实是依赖 props 来传递事件的引用,并通过回调的方式来实现的。
四. 没有任何嵌套关系的组件之间传值(比如:兄弟组件之间传值)
如果组件之间没有任何嵌套关系,组件嵌套层次比较深,我们该怎样去传递信息呢?
下面来看一个例子
这个例子需要引入一个 PubSubJS 库,通过这个库你可以订阅的信息,发布消息以及消息退订。
PubSubJS 具体可参考下面的内容
http://blog.csdn.net/u011439689/article/details/5195599
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| var ProductList = React.createClass({ render: function () { return ( <div> <ProductSelection/> <Product name="product 1"/> <Product name="product 2"/> <Product name="product 3"/> </div> ); } }); // 用于展示点击的产品信息容器 var ProductSelection = React.createClass({ getInitialState: function () { return { selection: 'none' }; }, componentDidMount: function () { // 通过 PubSub 库订阅一个信息 this.pubsub_token = PubSub.subscribe('products', function (topic, product) { this.setState({ selection: product }); }.bind(this)); }, componentWillUnmount: function () { // 当组件将要卸载的时候,退订信息 PubSub.unsubscribe(this.pubsub_token); }, render: function () { return ( <p>You have selected the product : {this.state.selection}</p> ); } });
var Product = React.createClass({ onclick: function () { PubSub.publish('products', this.props.name); }, render: function () { return <div onClick={this.onclick}>{this.props.name}</div>; } });
|
ProductSelection 和 Product 本身是没有嵌套关系的,而是兄弟层级的关系。但通过在 ProductSelection 组件中订阅一个消息,在 Product 组件中又发布了这个消息,使得两个组件又产生了联系,进行传递的信息。
所以根据我个人的理解,当两个组件没有嵌套关系的时候,也要通过全局的一些事件等,让他们联系到一起,进而达到传递信息的目的。
五. 利用 react-redux 进行组件之间的状态信息共享
如果是比较大型的项目,可以使用 react-redux,这方面的资料可以参考阮一峰的网络日志。地址:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux
本文地址 https://shaoshilei.com/2018-05/react-component-transform.html