React - 组件通信

1. 分类:

  • 父子组件通信

  • 子父组件通信

  • 非父子组件通信

  • 跨组件通信

  • 多组件状态共享

2. 父组件与子组件通信

  • 父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变
  • 父组件利用ref对子组件做标记,通过调用子组件的方法以更改子组件的状态,也可以调用子组件的方法..
   /* Father.js如下 */
  import React, { Component } from 'react'
  import Son from './Son'
  export default class Father extends Component {

    constructor(props) {
      super(props)

      this.state = {
        money: 2000
      }
    }


    render() {
      const { money } = this.state 
      return (
        <div>
          <Son money = { money } />
        </div>
      )
    }
  }
  /* Son.js定义如下 */
  import React, { Component } from 'react'

  export default class Son extends Component {
    render() {
      const { money } = this.props 
      return (
        <div>
          <p> 老爸给了我: { money } </p>
        </div>
      )
    }
  }

3. 子组件与父组件通信

  • 父组件将自己的某个方法传递给子组件,在方法里可以做任意操作,比如可以更改状态,子组件通过this.props接收到父组件的方法后调用。
  /* Father组件定义如下 */
  import React, { Component } from 'react'
  import OneOne from './OneOne'

  export default class One extends Component {

    constructor(props) {
      super(props)

      this.state = {
        jk: 0
      }
    }

    changeJk = val  => {
      this.setState({
        jk: val 
      })
    }


    render() {
      const { jk } = this.state 
      return (
        <div>

          <OneOne changeJk = { this.changeJk }/>
          <p> 儿子给了我 { jk }  红包 </p>
        </div>
      )
    }
  }
  /* Son组件定义如下 */
  import React, { Component } from 'react'

  export default class OneOne extends Component {

    constructor(props) {
      super(props)

      this.state = {
        hongbao: 80000
      }
    }


    render() {
      const { changeJk } = this.props 
      const { hongbao } = this.state 
      return (
        <div>
          <button onClick = {() => { changeJk( hongbao ) }}> 给红包 </button>
        </div>
      )
    }
  }

4. 跨组件通信

在react没有类似vue中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react提供了context api来实现跨组件通信, React 16.3之后的contextapi较之前的好用。

实例,使用context 实现购物车中的加减功能

    class App extends React.Component {
      render() {
        return <Toolbar theme="dark" />;
      }
    }

    function Toolbar(props) {
      // Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。
      // 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事,
      // 因为必须将这个值层层传递所有组件。
      return (
        <div>
          <ThemedButton theme={props.theme} />
        </div>
      );
    }

    class ThemedButton extends React.Component {
      render() {
        return <Button theme={this.props.theme} />;
      }
    }
    // 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(props) {
      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} />;
      }
    }

5. 非父子组件通信

  /* Father.js定义如下 */
  import React, { Component } from 'react'
  import Brother from './Brother'
  import Sister from './Sister'

  export default class Father extends Component {
    /* 父组件 */

    cry = () => {
      // this.refs.brother.cry()
      this.brother.cry()
    }

    render() {
      return (
        <div>
          <Sister cry = { this.cry }/>
          {/* <Brother ref = "brother"/> */}
          <Brother ref = { el => this.brother = el }/>
        </div>
      )
    }
  }
/* Brother.js定义如下 */
import React, { Component } from 'react'

export default class Brother extends Component {

  constructor(props) {
    super(props)

    this.state = {
       f: false 
    }
  }

  cry = () => {
    this.setState({
      f: true 
    })
  }

  render() {
    const { f } = this.state 
    return (
      <div>
          { f && <img src = "http://5b0988e595225.cdn.sohucs.com/q_70,c_zoom,w_640/images/20180113/db7a23a0460c4ffe80533a64c47c94ee.gif" />}
      </div>
    )
  }
}
/* Sister组件定义如下 */
import React, { Component } from 'react'

export default class Sister extends Component {


  hick = () => {
    //执行揍弟弟
  }

  render() {
    const { cry } = this.props 
    return (
      <div>
          <button onClick = { cry }> 揍弟弟 </button>
      </div>
    )
  }

}

5. 状态管理

说明: 状态管理我们将在后面讲解

复杂的非父子组件通信在react中很难处理,多组件间的数据共享也不好处理,在实际的工作中我们会使用flux、redux、mobx来实现

results matching ""

    No results matching ""