react class组件间通信的6种方式(父传子、子传父、ref、context、event bus、redux)

前言

用react写项目时,组件间通信是必须要掌握的,但实现组件通信有很多种方法,所以要根据项目实际情况,使用最佳的方法,才能令你,事半功倍

下面有6种组件间通讯方法,代码中都写了注释哦,文章总结有代码下载链接


一、父传子

子组件通过this.props接收父组件传来的数据

最佳使用场景:数据简单,状态单一,数据只涉及在父子组件中使用

1、父组件
import React, { Component } from 'react'

import Child from './child'

class Demo1 extends Component {
  state = {
    userInfo: {
      name: 'A.Liang',
      age: '22',
    },
  }

  render() {
    const { userInfo } = this.state

    return (
      <div>
        demo1
        <Child userInfo={userInfo} />
      </div>
    )
  }
}

export default Demo1

2、子组件
import React, { Component } from 'react'

class Child extends Component {
  render() {
    const { userInfo = {} } = this.props
    const { name = '', age = '' } = userInfo

    return (
      <div>
        child
        <div>
          <label>姓名:</label>
          <span>{name}</span>
        </div>
        <div>
          <label>年龄:</label>
          <span>{age}</span>
        </div>
      </div>
    )
  }
}

export default Child

二、子传父

子组件通过 回调函数 向父组件传递数据。父组件将自己的某个方法传递给子组件,子组件通过this.props接收到父组件的方法后进行调用。

最佳使用场景:数据简单,状态单一,数据只涉及在父子组件中使用

1、父组件
import Child from './child'

class Demo2 extends Component {
  state = {
    name: 'A.Liang',
    age: '22',
  }

  render() {
    const { name = '', age = '' } = this.state

    return (
      <div>
        Demo2
        <div>
          <label>姓名:</label>
          <span>{name}</span>
        </div>
        <div>
          <label>年龄:</label>
          <span>{age}</span>
        </div>
        <Child handleSaveData={obj => this.setState(obj)} />
      </div>
    )
  }
}

export default Demo2
2、子组件
import React, { Component } from 'react'

class Child extends Component {
  componentDidMount() {
    console.log('child==>', this.props)
  }

  render() {
    const { handleSaveData } = this.props

    return (
      <div>
        child
        {handleSaveData && (
          <button onClick={() => handleSaveData({ name: '阿良' })}>
            修改姓名
          </button>
        )}
      </div>
    )
  }
}

export default Child

三、ref

父组件通过 ref 获取到子组件的实例或者元素,调用子组件的方法进行数据传递

最佳使用场景:需使用子组件的方法、数据时;尽量不使用,用多了可读性变差

1、父组件
import React, { Component } from 'react'

import Child from './child'

class Demo6 extends Component {
  constructor(props) {
    super(props)

    this.state = {}
    this.childRef = React.createRef()
  }

  changeName = () => {
    console.log(`修改姓名`)
    const childRef = this.childRef

    childRef.current.changeName()
    console.log(`childRef==>`, childRef)
  }

  render() {
    return (
      <div>
        <p>Demo6</p>
        <button onClick={this.changeName}>修改姓名</button>
        <hr />
        <Child ref={this.childRef} />
      </div>
    )
  }
}

export default Demo6
2、子组件
import React, { Component } from 'react'

class Child extends Component {
  state = {
    userInfo: {
      name: 'A.Liang',
      age: '22',
    },
  }

  changeName = () => {
    console.log(`修改姓名`)
    const { userInfo } = this.state
    userInfo.name = '阿良'
    this.setState({ userInfo })
  }

  resetName = () => {
    console.log('还原名字')
    const { userInfo } = this.state
    userInfo.name = 'A.Liang'
    this.setState({ userInfo })
  }

  render() {
    const { userInfo = {} } = this.state
    const { name = '', age = '' } = userInfo

    return (
      <div>
        child
        <div>
          <label>姓名:</label>
          <span>{name}</span>
        </div>
        <div>
          <label>年龄:</label>
          <span>{age}</span>
        </div>
        <button onClick={this.resetName}>还原名字</button>
      </div>
    )
  }
}

export default Child

四、Context

react 中数据是通过 props 属性自上而下(由父及子)进行传递的,但这种做法对于多层级父子关系的组件传值是极其繁琐的。react 提供了context api 来实现在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props,使用 Context 做组件间的通讯会使得组件的复用性变差

最佳使用场景:组件不多,管理的状态、数据简单,项目中没有redux

1、父组件
import React, { Component } from 'react'

import Child from './child'

import { MyContext } from './myContext.js'

class Demo4 extends Component {
  state = {
    userInfo: {
      name: 'A.Liang',
      age: 23,
    },
  }

  render() {
    return (
      <MyContext.Provider value={this.state.userInfo}>
        Demo4
        <Child />
      </MyContext.Provider>
    )
  }
}

export default Demo4
2、context.js
import React from 'react'

export const MyContext = React.createContext({
  data: 'default data',
})
3、子组件(child1)
import React, { Component } from 'react'

import Son from './son.js'

import { MyContext } from './myContext.js'

class Child extends Component {
  // 指定 contextType 读取 my的context对象
  // 这样写的话,可以不用.Consumer去获取里面的数据
  static contextType = MyContext

  componentDidMount() {
  	// 查看MyContext里的数据
    console.log('context==>', this.context)
  }

  render() {
    return (
      <div>
        Child
        <Son />
      </div>
    )
  }
}
4、子孙组件(son)
import React, { Component } from 'react'

import { MyContext } from './myContext.js'

class Son extends Component {
  render() {
    return (
      <MyContext.Consumer>
        {(userInfo = {}) => {
          const { name = '', age = '' } = userInfo
          console.log('userInfo==>', userInfo)

          return (
            <div>
              son
              <div>
                <label>姓名:</label>
                <span>{name}</span>
              </div>
              <div>
                <label>年龄:</label>
                <span>{age}</span>
              </div>
            </div>
          )
        }}
      </MyContext.Consumer>
    )
  }
}

export default Son

五、event bus

利用中央事件总线,event bus可以适用于任何情况的组件通信,在项目规模不大的情况下,完全可以使用中央事件总线event bus的方式

最佳使用场景:组件不多,管理的状态、数据简单、状态(数据)没变化依旧触发时,bus且项目中没有redux

1、父组件
import React, { Component } from 'react'

import Child from './child'
import Child2 from './child2.js'

class Demo3 extends Component {
  componentDidMount() {
    console.log('Demo3==>', this.props)
  }

  render() {
    return (
      <div>
        Demo3
        <Child />
        <Child2 />
      </div>
    )
  }
}

export default Demo3
2、bus.js
import { EventEmitter } from 'events'

var bus = new EventEmitter() //注册一个组件
export { bus } //导出
3、子组件(child1)
import React, { Component } from 'react'

import { bus } from './bus'

class Child extends Component {
  //传值的触发函数
  sentToB = () => {
    bus.emit('eventbus', {
      name: '阿良',
      age: 18,
    })
  }

  render() {
    return (
      <div>
        child
        <button onClick={this.sentToB}>请点击我触发sentToB进行传值</button>
      </div>
    )
  }
}

export default Child
4、子组件(child2)
import React, { Component } from 'react'

import { bus } from './bus'

class Child2 extends Component {
  constructor(props) {
    super(props)
    this.state = {
      name: 'A.Liang',
      age: 23,
    }
  }

  componentDidMount() {
    // bus.on监听事件 将传递的值绑定到state
    // 监听event事件,获得emit传递的参数,触发时调用callback函数
    bus.on('eventbus', data => {
      this.setState(data)
    })
  }

  render() {
    const { name = '', age = '' } = this.state

    return (
      <div>
        Child2
        <div>
          <label>姓名:</label>
          <span>{name}</span>
        </div>
        <div>
          <label>年龄:</label>
          <span>{age}</span>
        </div>
      </div>
    )
  }
}

export default Child2

六、Redux

集中式状态管理模式,Redux 的状态管理存储是响应式的,可以集中式存储管理应用的所有状态

推荐使用场景:如果项目比较复杂、模块比较很多的情况,推荐使用 Redux 来做组件间的通信。

1、父组件
import React, { Component } from 'react'

import Child from './child'
import Child2 from './child2.js'

class Demo3 extends Component {
  render() {
      return (
      <div>
        Demo5
        <Child />
        <hr />
        <Child2 />
      </div>
    )
  }
}

export default Demo3
2、store的配置

2.1、reducer.js(第一步:定义计算规则,即 reducer)

const initialState = {
  cityName: '杭州',
}

// 第一步:定义计算规则,即 reducer
const userinfo = (state = initialState, action) => {
  switch (action.type) {
    // 修改城市
    case 'UPDATE_CITYNAME':
      return action.data
    default:
      return state
  }
}

export default userinfo

2.2、store/configureStore.js(根据计算规则生成 store)

import { createStore } from 'redux'
import rootReducer from '../reducers'

export default function configureStore(initialState) {
  const store = createStore(
    rootReducer,
    initialState,
    // 触发 redux-devtools
    window.devToolsExtension ? window.devToolsExtension() : undefined
  )
  return store
}

2.3、index.js(入口文件引入、挂载store)

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'

import App from './containers/App'

import configureStore from './store/configureStore'

const store = configureStore()

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,

  document.getElementById('root')
)

2.4、action/userinfo.js(触发数据变化的actions)

export const updateCityName = data => ({
  type: 'UPDATE_CITYNAME',
  data,
})
3、子组件(child1)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import * as userInfoActions from '../../actions/userinfo'

class Child1 extends Component {
  state = {}

  componentDidMount() {
    const { userInfoActions } = this.props
    console.log('Child1-userInfoActions :>> ', userInfoActions)
  }

  // 修改城市
  handleChangeCity = () => {
    const { updateCityName } = this.props.userInfoActions
    updateCityName && updateCityName({ cityName: '上海' })
  }

  render() {
    const { cityName } = this.props.userinfo

    return (
      <div>
        <div>Child1:{cityName}</div>
        <button onClick={this.handleChangeCity}>改变城市为'上海'</button>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  userinfo: state.userinfo,
})

const mapDispatchToProps = dispatch => ({
  userInfoActions: bindActionCreators(userInfoActions, dispatch),
})

export default connect(mapStateToProps, mapDispatchToProps)(Child1)
4、子组件(child2)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import * as userInfoActions from '../../actions/userinfo'

class Child2 extends Component {
  state = {}

  componentDidMount() {
    const { userInfoActions } = this.props
    console.log('Child2-userInfoActions :>> ', userInfoActions)
  }

  // 修改城市
  handleChangeCity = () => {
    const { updateCityName } = this.props.userInfoActions
    updateCityName && updateCityName({ cityName: '杭州' })
  }

  render() {
    const { cityName } = this.props.userinfo

    return (
      <div>
        <div>Child2:{cityName}</div>
        <button onClick={this.handleChangeCity}>改变城市为'杭州'</button>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  userinfo: state.userinfo,
})

const mapDispatchToProps = dispatch => ({
  userInfoActions: bindActionCreators(userInfoActions, dispatch),
})

export default connect(mapStateToProps, mapDispatchToProps)(Child2)

七、总结
1、父子通信:

①父传子
②子传父
③ref
④context
⑤event bus
⑥redux

2、跨组件通信

①event bus
②context
③redux

代码下载:https://gitee.com/staraliang/react17-app/tree/p-comp-by-value


你可能感兴趣的文章:

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
React中,父组件向子组件传递方法的方式是通过将方法作为props传递给子组件。子组件可以通过调用这个方法并传递参数来向父组件传递消息。具体步骤如下: 1. 在父组件中定义一个方法,用于接收子组件传递过来的值,并将值赋给父组件的state。 2. 在父组件的render方法中,将这个方法作为props传递给子组件。 3. 在子组件中,通过props获取父组件传递过来的方法,并在需要的时候调用这个方法并传递参数。 举个例子,假设父组件为Parent,子组件为Son,父组件需要向子组件传递一个方法getDatas,用于接收子组件传递过来的值。具体代码如下: 父组件Parent.js: ``` import React from 'react'; import Son from './Son'; class Parent extends React.Component { constructor() { super(); this.state = { mess: '' // 初始化mess属性 } } // 用于接收子组件的传值方法,参数为子组件传递过来的值 getDatas(msg) { // 把子组件传递过来的值赋给this.state中的属性 this.setState({ mess: msg }); } render() { return ( <React.Fragment> {/* 渲染子组件,设置子组件访问的方法,getdata属性名为子组件中调用的父组件方法名 */} <Son getdata={this.getDatas.bind(this)}></Son> <div>展示数据:{this.state.mess}</div> </React.Fragment> ); } } export default Parent; ``` 子组件Son.js: ``` import React from 'react'; class Son extends React.Component { constructor() { super(); this.state = { msg: 'Hello World!' } } handleClick() { // 调用父组件传递过来的方法,并传递参数 this.props.getdata(this.state.msg); } render() { return ( <div> <button onClick={this.handleClick.bind(this)}>向父组件传递消息</button> </div> ); } } export default Son; ``` 在这个例子中,父组件定义了一个方法getDatas,用于接收子组件传递过来的值,并将值赋给父组件的state。在父组件的render方法中,将这个方法作为props传递给子组件。子组件通过props获取父组件传递过来的方法,并在需要的时候调用这个方法并传递参数。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员良仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值