详解React中的组件通信问题(2)

组件 A 中的表单 value 值,告知了父级 Container 组件(通过 setValue 函数改变 state),组件 B 依赖于 Container 传下来的 state,会做出同步更新。这里的中间者是 Container。

利用Context

上面的方式,如果嵌套少还可以,如果嵌套特别多,比如一级导航栏下的二级导航栏下的某个按钮,要改变页面中 content 区域的 table 里的某个列的值...他们同属于一个 page 。这样传递 props 就会很痛苦,每一层组件都要传递一次。

// 顶级公共组件
class Context extends Component {

constructor() { super(); this.state = { value: '', }; } setValue = value => { this.setState({ value, }) } getChildContext() { // 必需 return { value: this.state.value, setValue: this.setValue, }; } render() { return ( <div> <AParent /> <BParent /> </div> ); } } // 必需 Context.childContextTypes = { value: PropTypes.string, setValue: PropTypes.func, };

// A 的 parent class AParent extends Component { render() { return ( <div className="card"> <A /> </div> ); } } // A class A extends Component { handleChange = (e) => { this.value = e.target.value; } handleClick = () => { const { setValue } = this.context; setValue(this.value); } render() { return ( <div> 我是parentA 下的 A, <input onChange={this.handleChange} /> <div className="button" onClick={this.handleClick}>通知</div> </div> ); } } // 必需 A.contextTypes = { setValue: PropTypes.func, };

// B 的 parent class BParent extends Component { render() { return ( <div className="card"> <B /> </div> ); } } // B class B extends Component { render() { return ( <div> 我是parentB 下的 B, value是: {this.context.value} </div> ); } } B.contextTypes = { value: PropTypes.string, };

组件 A 仍是 消息的发送者,组件 B 是接收者, 中间者是 Context 公有 Container 组件。context是官方文档的一个 API ,通过 getChildContext 函数定义 context 中的值,并且还要求 childContextTypes 是必需的。这样属于这个 Container 组件的子组件,通过 this.context 就可以取到定义的值,并且起到跟 state 同样的效果。中间者其实还是 Container,只不过利用了上下文这样的 API ,省去了 props 的传递。另外:这个功能是实验性的,未来可能会有所改动。

发布订阅

这种一个地方发送消息,另一个地方接收做出变化的需求,很容易想到的就是观察者模式了。具体的实现会有很多种,这里我们自己写了一个 EventEmitter 的类(其实就是仿照 node 中的 EventEmitter 类),如果不了解观察者,可以看我的另一篇文章 观察者模式 。

// 发布订阅类 class EventEmitter { _event = {} // on 函数用于绑定 on(eventName, handle) { let listeners = this._event[eventName]; if(!listeners || !listeners.length) { this._event[eventName] = [handle]; return; } listeners.push(handle); } // off 用于移除 off(eventName, handle) { let listeners = this._event[eventName]; this._event[eventName] = listeners.filter(l => l !== handle); } // emit 用于分发消息 emit(eventName, ...args) { const listeners = this._event[eventName]; if(listeners && listeners.length) { for(const l of listeners) { l(...args); } } } } const event = new EventEmitter; export { event };

// Container import A from './a'; import B from './b'; const Listener = () => { return ( <div> <A /> <B /> </div> ); }; export default Listener;

// 兄弟组件 A import { event } from './eventEmitter'; class A extends Component { handleChange = e => { this.value = e.target.value; } handleClick = () => { event.emit('dispatch', this.value); } render() { return ( <div className="card"> 我是Brother A, <input onChange={this.handleChange} /> <div className="button" onClick={this.handleClick}>通知</div> </div> ) } }

// 兄弟组件 B import { event } from './eventEmitter'; class B extends Component { state = { value: '' } componentDidMount() { event.on('dispatch', this.valueChange); } componentWillUnmount() { event.off('dispatch', this.valueChange); } valueChange = value => { this.setState({ value, }) } render() { return ( <div className="card"> 我是Brother B, value是: {this.state.value} </div> ); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyjyxj.html