createContext 和 useContext 结合使用实现方法共享(React Hook跨组件透传上下文与性能优化)

温馨提示:

使用react-hooks进行正常开发时,需要把组件和createContext创建上下文步骤单独写出来,哪里需要就在哪里引入

 

举个实际的例子:子组件中修改父组件的 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>
    );
}

 

3、子组件 useContext 解析上下文

下面是子组件,相同的,也需要从 context-manager 中引入 MyContext 这个实例,然后才能通过  const { setStep, setNumber, setCount, fetchData } = useContext(MyContext); 解析出上下文中的方法,在子组件中则可以直接使用这些方法,修改父组件的 state。

import React, { useContext, useEffect, memo } from 'react';

import { MyContext } from './context-manager';

export default memo((props = {}) => {
    const { setStep, setNumber, setCount, fetchData } = useContext(MyContext);

    useEffect(() => {
        fetchData().then((res) => {
            console.log(`FETCH DATA: ${res}`);
        })
    }, []);

    return (
        <div>
            <p>step is : {props.step}</p>
            <p>number is : {props.number}</p>
            <p>count is : {props.count}</p>
            <hr />
            <div>
                <button onClick={() => { setStep(props.step + 1) }}>step ++</button>
                <button onClick={() => { setNumber(props.number + 1) }}>number ++</button>
                <button onClick={() => { setCount(props.step + props.number) }}>number + step</button>
            </div>
        </div>
    );
});

 

4、效果:

1.gif

可以发现,在子组件中点击按钮,直接调用 Context 透传过来的方法,可以修改父组件的 state,子组件则会重新渲染。

这种方式显式的避免了多级 props 的层层透传问题,虽然 Demo 只有一级 子组件,即使存在多级子组件也可以直接修改

 

 

 

 

 

.

posted @ 2020-03-20 10:03  剑仙6  阅读(2083)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线