💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 父组件向子组件通信 react 的数据流是单向的,最常见的就是通过 `props` 由父组件向子组件传值。 子组件中使用 `props` 属性接收传递来的数据: ``` class Child extends Component { render() { {/*这里从props中拿到*/} return <div> price: {this.props.price} </div>; } } ``` # 子组件向父组件通信 子组件向父组件通讯,同样也需要父组件向子组件传递 props 进行通讯,只是父组件传递的,是作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到父组件的作用域中。 父组件: ``` return ( <div> <div>price: {this.state.price}</div> {/* 向子组件中传入一个函数 */} <Child getPrice={this.getItemPrice.bind(this)} /> </div> ); ``` 子组件: ``` class Child extends Component { clickGoods(e) { // 在此函数中传入值 this.props.getPrice(e); } render() { return ( <div> <button onClick={this.clickGoods.bind(this, 100)}>goods1</button> <button onClick={this.clickGoods.bind(this, 1000)}>goods2</button> </div> ); } } ``` # 发布者与订阅者模式(context) React 的 props 都是由父组件传递给子组件的,一旦遇到孙组件,就需要一层层的传递下去。而 context 提供了一种组件之间通讯的新的方式(16.3版本之后),可以共享一些数据,其它的组件都能从 context 中读取数据(类似于有个数据源,组件可以订阅这个数据源)。 ## `React.createContext()`方法 我们可以使用createContext来创建一个context,它可以接收一个变量或者对象做为参数(当对象为参数的时候,react使用object.is()去比较,有些影响性能)。这个传入的值做为context的默认值 ~~~ const PriceContext = React.createContext('price') ~~~ 这样就创建了一个Context ## `Provider`组件 Provider就是用来创建数据源的。它是给所有的子组件提供数据源的跟组件。它接受一个value作为props,用来传递值,它会改变context的默认值。一个provider可以包含多个Consumer组件。如果Provider组件嵌套的话, ~~~ <PriceContext.Provider value={100}> </PriceContext.Provider> ~~~ ## `Consumer`组件 Consumer表示接受数据的组件,它接受一个函数做为子元素。这个函数会接收context传递的值,返回一个react的组件。Consumer组件必须包含在Provider里面。 ~~~ <PriceContext.Consumer> { /*这里是一个函数*/ } { price => <div>price:{price}</div> } </PriceContext.Consumer> ~~~ # 非嵌套组件间通信 即没有任何包含关系的组件,包括兄弟组件以及不在同一个父级中的非兄弟组件。 1. 利用二者共同父组件的 context 对象通信 (兄弟组件) ``` import React from 'react'; import ReactDOM from 'react-dom'; import 'font-awesome/css/font-awesome.min.css'; import './index.css'; import './index.scss'; class Child_1 extends React.Component { constructor(props) { super(props); } handleClick() { this.props.changeChild_2Color('blue'); } render() { return ( <div> <h1>Child_1:{this.props.bgColor}</h1> <p> <button onClick={(e) => { this.handleClick(e) }}>改变Child_2背景色bgColor </button> </p> </div> ); } } class Child_2 extends React.Component { constructor(props) { super(props); } render() { return ( <div style={{backgroundColor: this.props.bgColor}}> <h1>child_2背景色:{this.props.bgColor}</h1> </div> ); } } class Father extends React.Component { constructor(props) { console.log('constructor---props:', props); super(props); this.state = { child_2BgColor: '#999' }; console.log('constructor---props:', props); } // 子组件调用该函数改变 state ,所以用到的子组件会被更新渲染! onChild_2BgColorChange(color) { this.setState({ child_2BgColor: color }); } render(props) { console.log('render---props:', props); return ( <div> <Child_1 changeChild_2Color={(color) => { this.onChild_2BgColorChange(color) }}/> <Child_2 bgColor={this.state.child_2BgColor}/> </div> ) } } class App extends React.Component { render() { return ( <div className=""> <Father> <p><span>App Span</span></p> <p><a href="">link</a></p> </Father> <hr/> </div> ); } } ReactDOM.render( <div> {/*<Component></Component>*/} <App></App> </div>, document.getElementById('app') ); ``` 使用二者共同父级进行中转**会增加子组件和父组件间的耦合度**,如果组件层次比较深,找到二者共同父组件会相对麻烦。 2. 使用自定义事件 (流行的库之类) 发布者-订阅者模式也叫观察者模式,大量使用在各类框架类库的设计中。发布者发布事件,订阅者监听事件并作出反应,我们可以引入一小个模块,使用观察者模式进行改造。 在componentDidMount事件中,如果组件挂载完成,订阅事件; 在组件卸载的时候,在componentwillUnmount事件中取消对事件的订阅。 例如:使用自定义事件方式需要使用 `events` 库: ``` npm install -S events ``` # 借助其他方式 还可以使用 `localstorage`,状态管理库(redux|mobx),或者是一些订阅发布的库 events 、[pubsub-js](https://npm.io/package/pubsub-js)。 # 参考 > [React组件间通信](https://juejin.im/post/5cbea2535188250a52246717)