React 内置 Hook 之 useReducer 优雅管理状态
前言
在开发 React 应用程序时,状态管理一直是一个需我们重点关注的主题。而在 React 16.8 的版本中,新引入的 Hooks API 使得我们可以更加方便的在函数式组件中使用状态和其他 React 特性而无需写 class。本文就详细的为你介绍一个非常强大的 Hook:useReducer
,它为复杂状态的管理提供了出色的解决方案。
什么是 useReducer
useReducer
就如同它的名字暗示的那样,它是一个允许你像使用 Redux 那样使用 reducer 的 React Hook。在复杂的应用中,你需要管理很多相互关联并且可能需要复杂的操作逻辑的组件状态,以上这一切只通过使用 useState
会变得僵硬且繁琐,这正是 useReducer
展现其价值和作用的时候。
javascriptconst [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer
需要三个参数:一个 reducer 函数,一个 初始 state 和一个可选的 init 函数,它会返回当前的 state 值以及配套的 dispatch
方法。
使用案例
一、计数器
一个非常基础的计数器的代码片段
typescriptimport React, { useReducer } from 'react'; // 我们的 reducer 函数 const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: throw new Error(); } }; const initialState = { count: 0 }; function Counter() { // 使用 useReducer,调用 reducer 函数与初始 state const [state, dispatch] = useReducer(reducer, initialState); return ( <div> <p>Count: {state.count}</p> {/* 当点击按钮,我们分发 'increment' 或 'decrement' 操作 --> */} <button onClick={() => dispatch({ type: 'increment' })}>Increment</button> <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button> </div> ); } export default Counter;
当你点击 "Increment" 按钮时,会触发一个 'increment' 操作,这会使 reducer
函数对当前的状态进行操作从而增加计数。同样,点击 "Decrement" 按钮会触发一个 'decrement' 操作,减少计数。
dispatch
函数就像是我们的动作发起器,它传递一个包含欲进行操作类型的对象给 reducer
函数,reducer
函数再根据这个操作类型返回新的状态。
二、Todo 列表功能
除了简单的计数器例子,我们还可以尝试一些更复杂的场景。
javascriptimport React, { useReducer } from 'react'; const initialTodos = [ { id: 'a', task: 'Learn React', complete: false, }, { id: 'b', task: 'Learn Firebase', complete: false, }, ]; function todoReducer(state, action) { switch (action.type) { case 'DO_TODO': return state.map(todo => todo.id === action.id ? { ...todo, complete: true } : todo, ); case 'UNDO_TODO': return state.map(todo => todo.id === action.id ? { ...todo, complete: false } : todo, ); default: return state; } } function TodoList() { const [todos, dispatch] = useReducer(todoReducer, initialTodos); // ... render code } export default TodoList;
在这个例子中,我们处理的是一个列表,每个列表项都包含多个属性,我们需要单独地更改这些属性,这再好不过的展示了 useReducer
是如何优雅地处理富有复杂状态逻辑的操作。
使用建议
- 当状态逻辑复杂以至于无法简单的使用
useState
管理时,可以考虑使用useReducer
。 - 当相互关联且需要在多个事件句柄之间同步的状态过多时,使用
useReducer
将非常便利。 - 在使用
useReducer
时,应当保证你的reducer
函数是纯函数,即在相同的输入下永远返回同样的输出,没有副作用。
总结
useReducer
是一个非常强大的使用 React Hooks 进行状态管理的工具。通过引入 reducer 的概念,我们能更好的组织和管理复杂的状态逻辑。使用 useReducer
,我们可以按照一种更加结构化和可预见的方式更新状态。
在下一篇文章中,我们将探索使用 useEffect
进行副作用的管理,这又是一个非常有力的工具,敬请期待。记得点击关注以获取更新提醒!