本来我是没想过总结这些东西的,会感觉比较入门。但是之前同学去腾讯面试问到了这个问题(react或vue的组件通信),我帮他整理,顺便写demo的过程中,会有一些新的体会,多总结还是有利于进步的呀。
父子组件
父 → 子
parent组件传给child组件,符合react的单向数据流理念,自上到下传递props。
// 父组件 class Parent extends Component { constructor() { super(); this.state = { value: '', } } handleChange = e => { this.value = e.target.value; } handleClick = () => { this.setState({ value: this.value, }) } render() { return ( <div> 我是parent <input onChange={this.handleChange} /> <div className="button" onClick={this.handleClick}>通知</div> <div> <Child value={this.state.value} /> </div> </div> ); } }
// 子组件 class Child extends Component { render() { const { value } = this.props; return ( <div> 我是Child,得到传下来的值:{value} </div> ); } }
父组件做的就是定义好 state ,定义好事件函数,input onChange 的时候,去缓存 value 值,然后点击 button 的时候,改变 state , 子组件只负责展示 value 。
子 → 父
child 组件通知 parent 组件, 主要是依靠 parent 传下来的 callback 函数执行,改变 parent 组件的状态,或者把 child 自己的 state 通知 parent 。分两种情况:
state 定义在 parent 组件
// parent class Parent extends Component { constructor() { super(); this.state = { value: '', } } setValue = value => { this.setState({ value, }) } render() { return ( <div> <div>我是parent, Value是:{this.state.value}</div> <Child setValue={this.setValue} /> </div> ); } }
class Child extends Component { handleChange = e => { this.value = e.target.value; } handleClick = () => { const { setValue } = this.props; setValue(this.value); } render() { return ( <div> 我是Child <div className="card"> state 定义在 parent <input onChange={this.handleChange} /> <div className="button" onClick={this.handleClick}>通知</div> </div> </div> ); } }
parent 组件把改变 state 的 setValue 函数传给 child ,child 组件自己处理内部的状态(这里是表单的value值),当 child 组件分发消息的时候, 执行 parent 的 setValue 函数,从而改变了 parent 的 state,state发生变化, parent 组件执行 re-render 。
state 定义在 child 组件
// parent class Parent extends Component { onChange = value => { console.log(value, '来自 child 的 value 变化'); } render() { return ( <div> <div>我是parent <Child onChange={this.onChange} /> </div> ); } }
class Child extends Component { constructor() { super(); this.state = { childValue: '' } } childValChange = e => { this.childVal = e.target.value; } childValDispatch = () => { const { onChange } = this.props; this.setState({ childValue: this.childVal, }, () => { onChange(this.state.childValue) }) } render() { return ( <div> 我是Child <div className="card"> state 定义在 child <input onChange={this.childValChange} /> <div className="button" onClick={this.childValDispatch}>通知</div> </div> </div> ); } }
有时候 state 是需要定义在 child 组件的,比如弹窗, CheckBox 这种开关性质的,逻辑是重复的,state 定义在组件内部更好维护, 复用性更好。但是 child 的 state 是需要告知我的 parent 组件的, 同样还是执行 parent 传下来的 change 函数。
兄弟组件
有时候可能出现页面中的某两部分通信,比如省市的级联选择,点击 button 改变颜色等等,组件并不是父子级,没有嵌套关系的时候。这种时候通常是依赖共有的顶级 Container 处理或者第三方的状态管理器。其实原理都是相通的,兄弟 A 的 value 发生变化,分发的时候把 value 值告诉一个中间者 C ,C 会自动告知 B,实现 B 的自动render 。
利用共有的Container
// container class Container extends Component { constructor() { super(); this.state = { value: '', } } setValue = value => { this.setState({ value, }) } render() { return ( <div> <A setValue={this.setValue}/> <B value={this.state.value} /> </div> ); } }
// 兄弟A class A extends Component { handleChange = (e) => { this.value = e.target.value; } handleClick = () => { const { setValue } = this.props; setValue(this.value); } render() { return ( <div className="card"> 我是Brother A, <input onChange={this.handleChange} /> <div className="button" onClick={this.handleClick}>通知</div> </div> ) } }
// 兄弟B const B = props => ( <div className="card"> 我是Brother B, value是: {props.value} </div> ); export default B;