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')
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章