多层级使用useContext

3,382 阅读2分钟

useContext作用

  1. Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
  2. Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。

useContext使用

createContext

const P = createContext(defaultValue);

先使用 createContext 创建一个 Context 对象。
就能使用 useContext 订阅了这个 Context 对象。这个组件会从组件树中,离自身最近的上层 Provider 中读取到当前的 context 值。当未匹配到时,值为设置的默认值defaultValue

Provider

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。 多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

<P.Provider value={/* 值 */}>
...
</P.Provider>

useContext

useContext 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <P.Provider value={}> 的 value 决定。
注意:useContext 的参数必须是 context 对象本身

// P Context 对象 由 createContext创建
const count = useContext(P);

多层级使用

import React, { createContext, useContext, useState } from "react";
// 创造一个上下文
const P = createContext(null);
// 创造一个上下文 带默认值
const B = createContext({ value: 3333, count: 12121 });

// 子组件
const Pa = () => {
  // 获取 P--Context
  const { count, setCount } = useContext(P);
  const add = () => {
    setCount((n) => n + 1);
  };

  return <div onClick={add}>pa==P==={count}</div>;
};

// 孙子组件
const Ba = () => {
  // 获取 B--Context
  const value = useContext(B);

  return <div>Ba==B==={value.value}</div>;
};

// 孙子组件
const Bb = () => {
  // 获取 P--Context
  const count = useContext(P);
  // 获取 B--Context
  const value = useContext(B);

  return (
    <div>
      Bb==B==={value.value},Bb==B===默认值==={value.count},<br />
      Pb--P==={count.count},
    </div>
  );
};

// 子组件
const Pb = () => {
  // 获取 P--Context
  const { count, setCount } = useContext(P);
  const add = () => {
    setCount((n) => n + 1);
  };

  return (
    <div>
      <div onClick={add}>Pb==P==={count}</div>
      {/* 加入新的 P--Context */}
      <P.Provider value={{ count: 2222 }}>
        <B.Provider value={{ value: 1111 }}>
          <Ba></Ba>
          <Bb></Bb>
        </B.Provider>
      </P.Provider>
    </div>
  );
};

// 顶级组件
const Home = (props) => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <P.Provider value={{ count, setCount }}>
        <Pa></Pa>
        <Pb></Pb>
      </P.Provider>
    </div>
  );
};

export default Home;
  1. 在组件树中 <P.Provider> 出现多次,订阅组件的 Context 值,以上层最近的 <P.Provider> value 为准。
  2. 当组件树上层未使用<B.Provider> 包裹,可直接使用 useContext(B), 值为设置的默认值。
  3. 组件树中使用多个 Context.Provider 包裹,只需注意 useContext() 传入的 Context 对象,就能获取对应的值。

参考资料

Hook API 索引
Context