组件进阶【3】-组件通讯的三种方式及Context

132 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情

1. 组件通讯的三种方式

1.1 父组件 -> 子组件

  1. 父组件提供要传递的 state 数据
  2. 给子组件标签添加属性,值为 state 中的数据
  3. 子组件中通过 props 接收父组件中传递的数据

父组件

class Parent extends React.Component {
	state = {
    	lastName: '邱'
    }
	
	render() {
    	return (
        	<div>
            	传递数据给子组件:<Child name={this.state.lastName} />
            </div>
        )
    }
}

子组件

const Child = (props) => {
    return (
    <div>子组件接收到数据:{props.name}</div>
    )
}

1.2. 子组件 -> 父组件

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数

  1. 父组件提供一个回调函数(用于接收数据)
  2. 将该函数作为属性的值,传递给子组件
  3. 子组件通过 props 调用回调函数
  4. 将子组件的数据作为参数传递给回调函数
// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// 父组件
class Parent extends React.Component {
  // 共享状态
  state = {
    message: ''
  }

  // 父组件提供的回调函数,用来接收数据
  getChildMsg = (data) => {
    console.log('接收子组件中传过来的数据:', data)

    // 父组件值更新为子组件传递过来的值
    this.setState({
      message: data
    })
  }

  render() {
    return (
      <div className='parent'>
        父组件:{this.state.message}
        <Child getMsg={this.getChildMsg}></Child>
      </div>
    )
  }
}

// 子组件
class Child extends React.Component {
  state = {
    msg: '子组件传递的数据'
  }

  handleClick = () => {
    // 子组件调用父组件传递过来的回调函数
    this.props.getMsg(this.state.msg)
  }

  render() {
    return (
      <div className='child'>
        子组件:{this.state.msg}
        <button onClick={this.handleClick}>点我,将子组件数据传递给父组件</button>
      </div>
    )
  }
}

// 渲染
ReactDOM.render(<Parent />, document.getElementById('root'))

1.3. 兄弟组件

  • 将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
  • 思想:状态提升
  • 公共父组件职责:1.提供共享状态 2.提供操作共享状态的方法
  • 要通讯的子组件只需通过 props 接收状态或操作状态的
// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// 父组件
class Parent extends React.Component {
  // 共享状态
  state = {
    count: 0
  }

  // 操作共享状态的方法
  increment = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  calc = () => {
    this.setState({
      count: this.state.count - 1
    })
  }

  render() {
    return (
      <div>
        <Child1 num={this.state.count}></Child1>
        <Child2 onIncrement={this.increment}></Child2>
        <br />
        <Child3 onCalc={this.calc}></Child3>
      </div>
    )
  }
}

// 子组件1
const Child1 = (props) => {
  return (
    <h1>计数器:{props.num}</h1>
  )
}

// 子组件2
const Child2 = (props) => {
  return (
    <button onClick={() => props.onIncrement()}>+1</button>
  )
}

// 子组件3
const Child3 = (props) => {
  return (
    <button onClick={() => props.onCalc()}>-1</button>
  )
}

// 渲染
ReactDOM.render(<Parent />, document.getElementById('root'))

2. Context

思考:

App 组件要传递数据给 Child 组件,该如何处理?

  • 处理方式:使用 props 一层层组件往下传递(繁琐)
  • 更好的方式:使用 Context
  • 作用:跨组件传递数据(比如:主题、语言等)

使用步骤:

  1. 调用 React.createContext() 创建 Provider(提供数据)和 Consumer(消费数据)两个组件。
  2. 使用 Provider 组件作为父节点。
  3. 设置 value 属性,表示要传递的数据。
  4. 调用 Consumer 组件接收数据。
// 导入ract
import React from 'react'
import ReactDOM from 'react-dom'

// 1.调用 React.createContext() 创建 Provider(提供数据)和 Consumer(消费数据)两个组件。
const { Provider, Consumer } = React.createContext()

// 2.使用 Provider 组件作为父节点。
// 3.设置 value 属性,表示要传递的数据。
class App extends React.Component {
  render() {
    return (
      <Provider value="red">
        <div className='app'>
          <Node />
        </div>
      </Provider>
    )
  }
}

const Node = props => {
  return (
    <div className='node'>
      <SubNode />
    </div>
  )
}

const SubNode = props => {
  return (
    <div className='subNode'>
      <Child />
    </div>
  )
}

// 4.调用 Consumer 组件接收数据。
const Child = props => {
  return (
    <Consumer>
      {
        data => (
          <div className='child'>
            <span>我是子节点 -- {data}</span>
          </div>
        )
      }
    </Consumer>
  )
}

// 渲染
ReactDOM.render(<App />, document.getElementById('root'))