React 的四种常见通信场景

652 阅读9分钟

React 通信:

父组件传给子组件:

  • 看例子前,先说一个通俗的理解,就是子组件在父组件中,自己的标签内定义一个键值对,值可以是父组件的参数,然后在子组件中,this.props.属性名字,就可以获取到这个值
//这个是父组件
export default class App extends Component{

    render(){
        return(
            <div>
                <Sub title = "今年过节不收礼" />
            </div>
        )
    }
}
//这里是子组件
const Sub = (props) => {
    return(
        <h1>
            { props.title }
        </h1>
    )
}

小结:在父组件中,子组件可以在自己的标签中,键值对的形式添加待传递的值,然后子组件内部,使用this.props.属性名字获取,

子组件向父组件传值

  • 父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可以向父组件通信 ,有点像jsonp的那种感觉
//父组件
export default class App extends Component{
    callback(msg){
        console.log(msg);
    }
    render(){
        return(
            <div>
                <Sub callback = { this.callback.bind(this) } />
            </div>
        )
    }
}
//子组件
const Sub = (props) => {
    const cb = (msg) => {
        return () => {
            props.callback(msg)
        }
    }
    return(
        <div>
            <button onClick = { cb("我们通信把") }>点击我</button>
        </div>
    )
}

小结:过程就是父组件将一个回调函数传给子组件,然后子组件调用把要传的值放进函数参数,这个回调函数最终在父组件中执行,然后父组件通过操作argument,获取值

跨级组件通信

  • 跨级组件就是父组件向子组件的子组件传值,当然也可以更深
  • 我们可以一层层的父传子,但是这样有点傻,而且难以维护,所以有了context对象
  • context 相当于一个全局变量,是一个大容器,我们可以把要通信的内容放在这个容器中,这样一来,不管嵌套有多深,都可以随意取用。
  • 整体步骤:父组件中定义要传的属性类型,和属性的键值对--->子组件定义要接受的属性类型,和属性的名字,this.context.属性名字取值
// 父组件
export default class App extends Component{
  // 父组件声明自己支持 context,并且准备传两个属性,color和callback回调函数
  static childContextTypes = {
      color:PropTypes.string,
      callback:PropTypes.func,
  }
  // 父组件提供一个函数,用来返回相应的 context 对象,要传的color和callback回调函数在里面
  getChildContext(){
      return{
          color:"red",
          callback:this.callback.bind(this)
      }
  }
  callback(msg){
      console.log(msg)
  }
  render(){
      return(
          <div>
              <Sub></Sub>
          </div>
      );
  }
} 
// 子组件
const Sub = (props) =>{
  return(
      <div>
          <SubSub />
      </div>
  );
}
//最小子组件
export default class SubSub extends Component{
  // 子组件声明自己需要使用 context,并且定义需要属性的名字和类型
  static contextTypes = {
      color:PropTypes.string,
      callback:PropTypes.func,
  }
  render(){
      // 直接this.context.属性名字使用
      const style = { color:this.context.color }
      const cb = (msg) => {
          return () => {
              this.context.callback(msg);
          }
      }
      return(
          <div style = { style }>
              SUBSUB
              <button onClick = { cb("我胡汉三又回来了!") }>点击我</button>
          </div>
      );
  }
}

小结:注意要使用context时候,先声明自己要传的值得名称和属性,然后定义一个对象,里面有要传的内容,然后取的时候声明自己要取的值得名称和属性,然后直接this.context.属性名来用

改变context对象

  • 想要改变context对象,只有让其和父组件的state或者props进行关联,也就是让context中的属性,与其结合,类似在context的回调函数值里面调用setState,这样state变化的时候,会更新context,然后子组件更新渲染
export default class App extends Component{
  constructor(props) {
      super(props);
      this.state = {
          color:"red"
      };
  }
  // 父组件声明自己支持 context
  static childContextTypes = {
      color:PropTypes.string,
      callback:PropTypes.func,
  }
  // 父组件提供一个函数,用来返回相应的 context 对象
  getChildContext(){
      return{
          color:this.state.color,
          callback:this.callback.bind(this)
      }
  }
  // 在此回调中修改父组件的 state,这里context对象和state绑定,所以值改变了,视图也会更新
  callback(color){
      this.setState({
          color,
      })
  }
  render(){
      return(
          <div>
              <Sub></Sub>
          </div>
      );
  }
} 
// 子组件
return(
  <div style = { style }>
      SUBSUB
      <button onClick = { cb("blue") }>点击我</button>
  </div>
);

非嵌套组件通信

  • 解决方案为:使用事件订阅 :声明一个自定义事件,然后触发第二个参数是传递的值
//首先下载events包
npm install events --save
//然后新建一个ev.js,引入包,并向外提供一个事件对象,供通信使用
import { EventEmitter } from "events";
export default new EventEmitter();
//这是主页面,Foo和Boo组件非嵌套关系
export default class App extends Component{
    render(){
        return(
            <div>
                <Foo />
                <Boo />
            </div>
        );
    }
} 
//这是Foo页面
export default class Foo extends Component{
    constructor(props) {
        super(props);
        this.state = {
            msg:null,
        };
    }
    componentDidMount(){
        // 在组件装载完成以后// 声明一个自定义事件
            this.eventEmitter = emitter.addListener("callMe",(msg)=>{
            this.setState({
                msg
            })
        });
    }
    // 组件销毁前移除事件监听
    componentWillUnmount(){
        emitter.removeListener(this.eventEmitter);
    }
    render(){
        return(
            <div>
                { this.state.msg }
                我是非嵌套 1 号
            </div>
        );
    }
}
//Boo页面
export default class Boo extends Component{
    render(){
        const cb = (msg) => {
            return () => {
                // 触发自定义事件
                emitter.emit("callMe","Hello")
            }
        }
        return(
            <div>
                我是非嵌套 2 号
                <button onClick = { cb("blue") }>点击我</button>
            </div>
        );
    }
}

小结:就是定义一个自定义事件,然后触发传参,那边用方法接受参数,并且使用