React Hooks 中useContext createContext 组件之间透传 props func

719 阅读2分钟

一、React.createContext

API 文档地址:zh-hans.reactjs.org/docs/contex…

从 API 名字就可以看出, createContext 能够创建一个 React 的 上下文(context),然后订阅了这个上下文的组件中,可以拿到上下文中提供的数据或者其他信息。

基本的使用方法:

const MyContext = React.createContext(defaultValue)

其中 defaultValue 是传入的默认值。

如果要使用创建的上下文,需要通过 Context.Provider 最外层包装组件,并且需要显示的通过 <MyContext.Provider value={{xx:xx}}> 的方式传入 value,指定 context 要对外暴露的信息。

子组件在匹配过程中只会匹配最新的 Provider,也就是说如果有下面三个组件:ContextA.Provider->A->ContexB.Provider->B->C

如果 ContextA 和 ContextB 提供了相同的方法,则 C 组件只会选择 ContextB 提供的方法。

为什么要默认值?

如果匹配不到最新的 Provider 则会使用默认值,默认值一般只有在对组件进行单元测试(组件并未嵌入到父组件中)的时候,比较有用。

二、使用 useContext 获取上下文

useContext 文档地址:zh-hans.reactjs.org/docs/hooks-…

通过 React.createContext 创建出来的上下文,在子组件中可以通过 useContext 这个 Hook 获取 Provider 提供的内容

const {funcName} = useContext(MyContext);

从上面代码可以发现,useContext 需要将 MyContext 这个 Context 实例传入,不是字符串,就是实例本身。

这种用法会存在一个比较尴尬的地方,父子组件不在一个目录中,如何共享 MyContext 这个 Context 实例呢?

一般这种情况下,我会通过 Context Manager 统一管理上下文的实例,然后通过 export 将实例导出,在子组件中在将实例 import 进来。

三、createContext 和 useContext 结合使用实现方法共享

举个实际的例子:子组件中修改父组件的 state

一般的做法是将父组件的方法比如 setXXX 通过 props 的方式传给子组件,而一旦子组件多层级的话,就要层层透传。

使用 Context 的方式则可以免去这种层层透传

1、context-manager.js

创建一个上下文管理的组件,用来统一导出 Context 实例

import React from 'react';

export const MyContext = React.createContext(null);

2、父组件 Provider 提供上下文 value

下面代码中,父组件引入了实例,并且通过 MyContext.Provider 将父组件包装,并且通过 Provider.value 将方法提供出去。

下面的实例提供了三个 state 操作方法:

  • setStep
  • setCount
  • setNumber

以及一个副作用方法:

  • fetchData

子组件 Child 接受的 props 只有三个 state 的值 step/number/count

import React, { useState } from 'react';
import Child from './Child';
import { MyContext } from './context-manager';

const fetchData = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(1);
        })
    });
}

export default (props = {}) => {
    const [step, setStep] = useState(0);
    const [count, setCount] = useState(0);
    const [number, setNumber] = useState(0);


    return (
        <MyContext.Provider value={{ setStep, setCount, setNumber, fetchData }}>
            <Child step={step} number={number} count={count} />
        </MyContext.Provider>
    );