结合 useContext 和 useReducer ( redux 效果)

一、 useContext 和 useReducer

如果使用回调函数作为参数传递的话,因为每次 render 函数都会变化,也会导致子组件 render。当然我们可以使用useCallback解决这个问题,但相比useCallbackReact官方更推荐使用useReducer,因为React会保证dispatch始终是不变的,不会引起组件的 render。

1.1 介绍和基本使用

参考:React官网文档
或者我之前博客:
useContext 介绍和基本使用
useReducer 介绍和基本使用

二、使用

Context.tsx

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

import { createContext } from "react";

export const ReducerContext = createContext(null);
index.tsx

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化。
Provider 接收一个 value 属性,传递给消费组件。

//  index.tsx
import { useReducer } from 'react';
import ChildComponent from './ChildComponent';
import { ReducerContext } from './Context';

const initialData = {
    isLogin: false,
    error: '',
}

const loginReducer = (state, action) => {
    switch (action.type) {
        case 'success':
            return {
                ...state,
                isLogin: true,
                message: '登陆成功!'
            }
        case 'fail':
            return {
                ...state,
                isLogin: false,
                message: '登陆失败!'
            }

        default:
            return state;
    }
}

const index = () => {
    const [state, dispatch] = useReducer(loginReducer, initialData);

    return (
        <div>
            Reducer2:
            <p>登陆状态:{isLogin ? '成功' : '失败'}</p>
            <ReducerContext.Provider value={dispatch}>
                <ChildComponent />
            </ReducerContext.Provider>
        </div>
    )
}

export default index;
ChildComponent.tsx

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

此层组件并未订阅 ReducerContext,但 当组件上层最近的 <ReducerContext.Provider> 更新时,会触发页面 render,从而导致此页面 render,所以使用 memo 对组件进行包裹。
参考:React 中 memo()、useCallback()、useMemo()

//  ChildComponent.tsx
import { memo } from "react";
import Child1 from './Child1';
import Child2 from './Child1';

const ChildComponent = () => {
    console.log('ChildComponent');

    return (
        <>
            <Child1 />
            <Child1 />
        </>
    )
}

//  使用 `memo` 
export default memo(ChildComponent);

Child1.tsx

组件中更新 ReducerContext

//  Child1.tsx
import { useContext } from "react";
import { ReducerContext } from "./Context";

const Child1 = () => {
    console.log('Child1');
    const dispatch = useContext(ReducerContext)

    return (
        <>
            <button onClick={()=>dispatch({type:'success'})}>成功</button>
            <button onClick={()=>dispatch({type:'fail'})}>失败</button>
        </>
    )
}

export default Child1;

总结

  • 页面state很简单,可以直接使用useState
  • 页面state比较复杂(state是一个对象或者state非常多散落在各处)请使用userReducer
  • 页面组件层级比较深,并且需要子组件触发state的变化,可以考虑useReducer + useContext
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值