React使用context进行组件通信

本文介绍了如何使用React的Context API实现组件间的父子及兄弟组件之间的数据和方法共享,通过Provider和Consumer组件展示了如何传递和接收数据,适用于大型应用状态管理。

1、介绍

之前文章介绍了使用Props进行参数和函数引用的传参达到组件通信的效果。这次使用context来实现这个效果。

2、创建组件

创建 GrandpaFatherSon1Son2Son3 组件

const Grandpa = () => {
  return (
    <>
      <div>我是 Grandpa</div>
      <Father />
    </>
  )
}

const Father = () => {
  return (
    <>
      <div>我是 Father</div>
      <Son1 />
      <Son2 />
    </>
  )
}

const Son1 = () => {
  return (
    <>
      <div>我是Son1</div>
    </>
  )
}

class Son2 extends React.Component {
  render(){
    return <div>我是 Son2</div>
  }
}

const Son3 = () => {
  return (
    <>
      <div>我是 Son3</div>
    </>
  )
}

function App() {
  return (
      <div className="App">
        <Grandpa />
      </div>
  )
}

3、创建 context 对象

引入 createContext 函数,用于构造context对象

import { createContext } from 'react'
const context = createContext()

context 中结构出 ProviderConsumer 两个组件

const { Provider, Consumer } = context

4、注入数据

在 App 中使用 Provider 组件进行注入,并把对应数据和方法传递下去

function App() {
  const [name, setName] = useState('梁又文')
  const data = {
    name,
    age: '20',
    setName,
  }
  return (
    <Provider value={data}>
      <div className="App">
        <Grandpa />
      </div>
    </Provider>
  )
}

5、子孙组件获取数据

5.1 函数组件

通过 Consumer 获取数据

Son1

const Son1 = () => {
  return (
    <Consumer>
      {({ name, setName }) => (
        <div>
          我是Son1,我拿到的数据是:{name} <button onClick={() => setName('我是被Son1修改的名字')}>修改名字</button>
        </div>
      )}
    </Consumer>
  )
}

5.2 类组件

通过 contextType 挂载 context 的属性

Son2

class Son2 extends Component {
  static contextType = context
  render() {
    const { name, setName } = this.context
    return (
      <>
        我是Son2,我拿到的数据是:{name} <button onClick={() => setName('我是被Son2修改的名字')}>修改名字</button>
      </>
    )
  }
}

5.3 useContext 方式

通过把 context 对象传入到 useContext 中,返回所有数据。

const Son3 = () => {
  const { name, setName, age } = useContext(context)
  return (
    <div>
      我是Son1,Grandpa今年{age}岁了。我拿到的数据是:{name}
      <button onClick={() => setName('我是被Son1修改的名字')}>修改名字</button>
    </div>
  )
}

6、最终代码

import { Component, createContext, useState, useContext } from 'react'
const context = createContext()
const { Provider, Consumer } = context
export { Consumer, context }

const Grandpa = () => {
  return (
    <>
      <div>我是 Grandpa</div>
      <Father />
    </>
  )
}

const Father = () => {
  return (
    <>
      <div>我是 Father</div>
      <Son1 />
      <Son2 />
      <Son3 />
    </>
  )
}

const Son1 = () => {
  return (
    <Consumer>
      {({ name, setName }) => (
        <div>
          我是Son1,我拿到的数据是:{name} <button onClick={() => setName('我是被Son1修改的名字')}>修改名字</button>
        </div>
      )}
    </Consumer>
  )
}

class Son2 extends Component {
  static contextType = context
  render() {
    const { name, setName } = this.context
    return (
      <>
        我是Son2,我拿到的数据是:{name} <button onClick={() => setName('我是被Son2修改的名字')}>修改名字</button>
      </>
    )
  }
}

const Son3 = () => {
  const { name, setName, age } = useContext(context)
  return (
    <div>
      我是Son1,Grandpa今年{age}岁了。我拿到的数据是:{name}
      <button onClick={() => setName('我是被Son1修改的名字')}>修改名字</button>
    </div>
  )
}

function App() {
  const [name, setName] = useState('梁又文')
  const data = {
    name,
    age: '20',
    setName,
  }
  return (
    <Provider value={data}>
      <div className="App">
        <Grandpa />
      </div>
    </Provider>
  )
}

export default App
### React组件间通信使用 Context API 实现数据共享 #### 创建上下文对象 为了使不同层级的组件能够访问相同的数据,在最外层定义并导出一个上下文对象是必要的。这可以通过调用 `React.createContext()` 来完成,它会返回一个新的上下文对象。 ```javascript import React from 'react'; // 定义默认值为空的对象 const MyContext = React.createContext({}); export default MyContext; ``` 此部分代码创建了一个名为 `MyContext` 的上下文实例[^1]。 #### 提供者模式分发状态 接着,在应用的根部或任何希望作为数据源的位置包裹 `<MyContext.Provider>` 组件,并向其传递 `value` 属性来指定要共享的状态。 ```jsx import React, { useState } from 'react'; import MyContext from './path/to/MyContext'; // 导入之前创建好的context文件路径 function App() { const [data, setData] = useState('Initial Data'); return ( <MyContext.Provider value={{ data, setData }}> {/* 子组件 */} </MyContext.Provider> ); } ``` 这段代码展示了如何利用 `Provider` 将应用程序中的某些特定信息暴露给后代节点,使得这些节点可以方便地读取到该信息而不必担心中间层次结构的影响[^2]。 #### 消费者模式接收状态 最后一步是在目标子组件内部通过 `useContext(MyContext)` 钩子函数订阅来自父级提供的最新状态更新。 ```jsx import React, { useContext } from 'react'; import MyContext from './path/to/MyContext'; function ChildComponent() { const { data, setData } = useContext(MyContext); function handleClick() { setData('Updated Data'); } return ( <> <p>{data}</p> <button onClick={handleClick}>Update Data</button> </> ); } export default ChildComponent; ``` 上述例子说明了怎样在一个较深嵌套级别的组件里轻松获取由祖先级别所提供的公共资源,从而简化了复杂界面间的交互逻辑处理过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值