Heading for the future

React组件通信

React间组件间通信有如下几种方式:

  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件通信
  • 非嵌套关系的组件通信

父组件向子组件通信

父组件直接通过props向子组件传递需要的信息

// 子组件
const Child = props => {
    return <p>{props.name}</p>
}
// 父组件
const Parent = ()=>{
    return <Child name='哈哈哈'/>
}

子组件向父组件通信

props+回调。即父组件通过props传递方法下去,子组件调用这个方法。

// 子组件
const Child = props=> {
  const test = msg=> {
    return () => {
        props.callback(msg);
    }
  }
    return (
    <Button onClick={test('子组件的数据')}>按钮</Button>
  )
}
// 父组件
class parent extends Component{
    callback = (msg) => {
    console.log('子组件的数据:' + msg);
  }
  render(){
    return <Child callback={this.callback}>
  }
}

跨级组件通信

  • 使用props进行多级传递,但是增加了复杂度
  • 使用context,context相当于一个大容器,不管多少层都可以轻松拿到,对于跨越多层的数据可以采用这个方案。

官网Context详细介绍https://react.docschina.org/docs/context.html

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
  render() {
    // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
    // 无论多深,任何组件都能读取这个值。
    // 在这个例子中,我们将 “dark” 作为当前的值传递下去。
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
  // 指定 contextType 读取当前的 theme context。
  // React 会往上找到最近的 theme Provider,然后使用它的值。
  // 在这个例子中,当前的 theme 值为 “dark”。
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

非嵌套关系的组件通信

  • 使用redux等状态管理工具
  • 可以使用自定义事件通信(发布订阅模式)

设置一个event文件

      class Event{
        constructor() {
          this.eventList = [];
        }
        // 绑定事件
        $on = (eventName, cb)=> {  
          // 判断该类型的事件是否存在,若存在则添加
          let lists = this.eventList[eventName];
          if(!lists){
            this.eventList[eventName] = []
          }
          this.eventList[eventName].push(cb)
        }
        // 触发事件
        $emit = (eventName, params) => {
          // 先判断事件类型是否存在
          let lists = this.eventList[eventName];
          if(!lists) {
            throw new Error('无此事件类型')
          }
          // 若存在则执行
          lists.forEach((item)=>{
            item(params);
          });
        }
        
        $off = (eventName, cb) => {
          let lists = this.eventList[eventName];
          if(lists){
            // 若第二个参数存在,则删除该类型下指定的方法,若不存在则删除整个类型
            if(!cb){
              this.eventList[eventName] = []
            }else{
              this.eventList[eventName] = lists.filter((item)=>{
                return item !=cb;
              })
            }
          }
        }
      }

使用示例

a文件里触发

import Event from 'event'
class A extends React.Component {
    componentDidMount() {
        Event.on('data1Change', this.handleData1Change)
    }
    handleData1Change = ()=>{
        console.log('测试')
    }
}

b文件里触发

import Event from 'event'
class B extends React.Component {
    handleUpdateData = () => {
       Event.emit('data1Change')
    }
}

 

posted @ 2020-09-20 19:01  一只菜鸟攻城狮啊  阅读(479)  评论(0编辑  收藏  举报