React系列--组件通信

104 阅读2分钟

首先使用 vite 新建一个 React 项目。

image.png

React版本:18.0.0

父子通信 props + 函数

我们改写一下 App.jsx ,将个人信息的相关参数逐一传递给 UserInfoCard.jsx 组件,代码如下:

export default class App extends Component {
  constructor() {
    super()
    this.state = {
      myInfo: {
        avatarURL: 'https://p26-passport.byteacctimg.com/img/user-avatar/76a815f3450e3c836f11f32a058444d8~300x300.image',
        name: 'leyili',
        occupation: 'FED',
        motto: '生活不奖赏心血来潮。'
      }
    }
  }

  render() {
    return (
      <div>
        <UserInfoCard
          avatarURL={this.state.myInfo.avatarURL}
          name={this.state.myInfo.name}
          occupation={this.state.myInfo.occupation}
          motto={this.state.myInfo.motto}
        />
      </div>
    )
  }
}

UserInfoCard 组件来接收这些参数,要使用 props ,则必须写 constructor ,并且在其中必须有 super ,代码如下:

import React, { Component } from 'react'

export default class UserInfoCard extends Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div className='card-wrapper'>
        <img className='avatar' src={this.props.avatarURL} alt='avatar' />
        <div>姓名:{this.props.name}</div>
        <div>职业:{this.props.occupation}</div>
        <div>座右铭:{this.props.motto}</div>
      </div>
    )
  }
}

这是基本的父组件传递参数给子组件,那如果子组件想要变更父组件传递的信息应该如何做?

也是要靠父组件主动给子组件传递参数,只不过这次需要传递的是一个函数。

首先改写一下 UserInfoCard.jsx

import React, { Component } from 'react'

export default class UserInfoCard extends Component {
  constructor(props) {
    super(props)
  }
  change = () => {
    this.props.changeOccupation('在线炒粉')
  }
  render() {
    return (
      <div className='card-wrapper'>
        <img className='avatar' src={this.props.avatarURL} alt='avatar' />
        <div>姓名:{this.props.name}</div>
        <div>职业:{this.props.occupation}</div>
        <div>座右铭:{this.props.motto}</div>
        <button onClick={this.change}>更换职业</button>
      </div>
    )
  }
}

我们新加了一个按钮,并为其添加了一个点击事件,当点击事件触发后就调用 props 中的 changeOccupation 函数并传递一个新的职业名称给该函数。

好了,接下来我们看父组件该如何定义这个函数。

import React, { Component } from 'react'
import UserInfoCard from './UserInfoCard'

export default class App extends Component {
  constructor() {
    super()
    this.state = {
      myInfo: {
        avatarURL: 'https://p26-passport.byteacctimg.com/img/user-avatar/76a815f3450e3c836f11f32a058444d8~300x300.image',
        name: 'leyili',
        occupation: 'FED',
        motto: '生活不奖赏心血来潮。'
      }
    }
  }
  // 函数处理,更新 state
  changeOccupation = (newVal) => {
    this.setState({
      myInfo: {
        ...this.state.myInfo,
        occupation: newVal
      }
    })
  }

  render() {
    return (
      <div>
        <UserInfoCard
          avatarURL={this.state.myInfo.avatarURL}
          name={this.state.myInfo.name}
          occupation={this.state.myInfo.occupation}
          motto={this.state.myInfo.motto}
          // 新添加的参数传递一个函数给子组件
          changeOccupation={this.changeOccupation}
        />
      </div>
    )
  }
}

爷孙通信

两层父子通信

暂时没想到好的例子,我们强行把座右铭做成一个组件好了。

import React, { Component } from 'react'

export default class Motto extends Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div>座右铭:{this.props.motto}</div>
    )
  }
}

然后 UserInfoCard 稍微做一下改动:

import React, { Component } from 'react'
import Motto from './Motto'

export default class UserInfoCard extends Component {
  constructor(props) {
    super(props)
  }
  change = () => {
    this.props.changeOccupation('在线炒粉')
  }
  render() {
    return (
      <div className='card-wrapper'>
        <img className='avatar' src={this.props.avatarURL} alt='avatar' />
        <div>姓名:{this.props.name}</div>
        <div>职业:{this.props.occupation}</div>
        {/* <div>座右铭:{this.props.motto}</div> */}
        <Motto motto={this.props.motto} />
        <button onClick={this.change}>更换职业</button>
      </div>
    )
  }
}

Context

官网对 Context 的介绍: reactjs.org/docs/contex…

首先我们新建一个 myContext.jsx 文件:

import React from 'react'
export const myContext = React.createContext()

然后在需要用到的地方去引入,在 App.jsx 中使用 Provider:

import React, { Component } from 'react'
import UserInfoCard from './UserInfoCard'
import { myContext } from './myContext'


export default class App extends Component {
  constructor() {
    super()
    this.state = {
      myInfo: {
        avatarURL: 'https://p26-passport.byteacctimg.com/img/user-avatar/76a815f3450e3c836f11f32a058444d8~300x300.image',
        name: 'leyili',
        occupation: 'FED',
        motto: '生活不奖赏心血来潮。'
      }
    }
  }

  changeOccupation = (newVal) => {
    this.setState({
      myInfo: {
        ...this.state.myInfo,
        occupation: newVal
      }
    })
  }

  render() {
    return (
      <myContext.Provider value={{ motto: this.state.myInfo.motto }} >
        <UserInfoCard
          avatarURL={this.state.myInfo.avatarURL}
          name={this.state.myInfo.name}
          occupation={this.state.myInfo.occupation}
          motto={this.state.myInfo.motto}
          changeOccupation={this.changeOccupation}
        />
      </myContext.Provider>
    )
  }
}

在 Motto.jsx 中使用 Consumer:

import React, { Component } from 'react'
import { myContext } from './myContext'

export default class Motto extends Component {
  constructor(props) {
    super(props)
  }
  componentDidMount() {
    console.log('this', this)
  }
  static contextType = myContext
  render() {
    return (
      // <div>座右铭:{this.props.motto}</div>
      // <div>座右铭:{this.context.motto}</div>
      <myContext.Consumer>
        {value => <div>座右铭:{value.motto}</div>}
      </myContext.Consumer>
    )
  }
}

任意组件通信

其实就是使用状态管理库了,如 Redux、Mobx 。

我们下次再做介绍吧!

源码地址

github.com/ximuli/reac…

参考链接:

  1. reactjs.org/docs/contex…