zl程序教程

您现在的位置是:首页 >  其他

当前栏目

React的Reducer Hook让state有了状态!

2023-03-20 14:51:24 时间
一、解决什么问题?

useReducer 是 useState 的升级版本,对 setState 这个操作进行了拆分,可以根据不同类型,进行不同的逻辑计算,最后去改变 state 对象。

1、实例:useReducer 实现计数器组件
const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        default:
            throw new Error();
    }
}

function Counter() {
    const [state, dispatch] = React.useReducer(reducer, initialState);
    return (
        <>
            Count: {state.count}
            <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
            <button onClick={() => dispatch({ type: 'increment' })}>+</button>
        </>
    );
}

二、useReducer 初始化方法
1、法一:使用第二个参数初始化
const [state, dispatch] = useReducer(
    reducer,
    { count: initialCount }
);
2、法二:惰性初始化

useReducer 需要一个初始值和初始函数,经过计算得到的值作为 useReduccer 的初始化数据。这样就把计算逻辑独立在 useReducer 外部,为将来对重置 state 的 action 做处理提供了便利。

function init(initialCount) {
    return { count: initialCount };
}

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        case 'reset':
            return init(action.payload);
        default:
            throw new Error();
    }
}

function Counter({ initialCount }) {
    const [state, dispatch] = useReducer(reducer, initialCount, init);
    return (
        <>
            Count: {state.count}
            <button
                onClick={() => dispatch({ type: 'reset', payload: initialCount })}>
                Reset
            </button>
            <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
            <button onClick={() => dispatch({ type: 'increment' })}>+</button>
        </>
    );
}

三、提升性能的说明

如果 useReducer 返回的 state 相比于之前没有变化,React会自动跳过对组件的渲染操作。这里的比较操作是调用了js的 Object.is() 方法。


四、解决层层回调的烦恼
1、useContext + useReducer

顶层组件有个回调函数要传递下去,需要每一层都使用 props 进行设置,很繁琐,这里可以用 useContext + useReducer 来解决。

useContext 负责传递执行函数,useReducer 负责对执行函数划分出不同状态,可供选择执行。

const TodosDispatch = React.createContext(null);

function TodosApp() {
    // 提示:`dispatch` 不会在重新渲染之间变化
    const [todos, dispatch] = useReducer(todosReducer);

    return (
        <TodosDispatch.Provider value={dispatch}>
            <DeepTree todos={todos} />
        </TodosDispatch.Provider>
    );
}
function DeepChild(props) {
    // 如果我们想要执行一个 action,我们可以从 context 中获取 dispatch。
    const dispatch = useContext(TodosDispatch);

    function handleClick() {
        dispatch({ type: 'add', text: 'hello' });
    }

    return (
        <button onClick={handleClick}>Add todo</button>
    );
}

五、参考链接: