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、效果:
可以发现,在子组件中点击按钮,直接调用 Context 透传过来的方法,可以修改父组件的 state,子组件则会重新渲染。
这种方式显式的避免了多级 props 的层层透传问题,虽然 Demo 只有一级 子组件,即使存在多级子组件也可以直接修改
.