useContext 介绍和基本使用

一、前言

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。使用 context, 我们可以避免通过中间元素传递 props。

const value = useContext(MyContext);
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memoshouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染。调用了 useContext 的组件总会在 context 值变化时重新渲染

别忘记 useContext 的参数必须是 context 对象本身:

  • 正确useContext(MyContext)
  • 错误useContext(MyContext.Consumer)
  • 错误useContext(MyContext.Provider)

二、使用

创建一个 Context 对象 (React.createContext)

当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。此默认值有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Provider 的 value 时,消费组件的 defaultValue 不会生效。

//  MyContext.ts
import { createContext } from "react";

export const MyContext = createContext(null);

包裹 Context.Provider 组件

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
Provider 接收一个 value 属性,传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。

//  index.ts
import { MyContext } from './MyContext';
import { MyContextComponent } from './MyContextComponent';

const initialData = {
    name: 'index',
    age:18,
}

const index = () => {
    return(
        <MyContext.Provider value={ initialData }> 
            <MyContextComponent />
        </MyContext.Provider>
    )
}

export default index;

嵌套消费组件层级 (未订阅 MyContext 变化)

//  MyContextComponent.ts
import { MyContext1 } from './MyContext1';
import { MyContext2 } from './MyContext2';

const initialData = {
    name: 'index',
    age:18,
}

const MyContextComponent = () => {
    return(
        <> 
            <MyContext1 />
            <MyContext2 />
        </>
    )
}

export default MyContextComponent;

组件中订阅 MyContext

//  MyContext1.ts
import { ReducerContext } from './MyContext';

const MyContext1 = () => {
    const MyContext1Context = useContext(MyContext)
    return(
        <div>
            订阅indexname:
            {MyContext1Context.name}
        </div>
    )
}

export default MyContext1;

三、在嵌套组件中更新 Context

若在嵌套组件中更新 上面例子中的 MyContext,则将传入的对象使用 useState函数更新:

//  index.ts
import { ReducerContext } from './MyContext';
import { MyContextComponent } from './MyContextComponent';

const initialData = {
    name: 'index',
    age:18,
}

const index = () => {
    const [indexData, setIndexData] = useState(initialData)
    return(
        <MyContext.Provider value={ setIndexData }> 
            <MyContextComponent />
        </MyContext.Provider>
    )
}

export default index;
//  MyContext1.ts
import { ReducerContext } from './MyContext';

const MyContext1 = () => {
    const MyContext1Context = useContext(MyContext)
    return(
        <button onClick={() => MyContext1Context(10)}>修改</button>
    )
}

export default MyContext1;

四、useState + useContext 结合实现 redux 数据管理效果

在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。

useReducer 替代 useState ,加上 useContext可以实现类似 redux 的数据管理效果。
可参考:结合 useContext 和 useReducer ( redux 效果)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值