React 内置 Hook 之 useReducer 优雅管理状态

前言

在开发 React 应用程序时,状态管理一直是一个需我们重点关注的主题。而在 React 16.8 的版本中,新引入的 Hooks API 使得我们可以更加方便的在函数式组件中使用状态和其他 React 特性而无需写 class。本文就详细的为你介绍一个非常强大的 Hook:useReducer,它为复杂状态的管理提供了出色的解决方案。

什么是 useReducer

useReducer 就如同它的名字暗示的那样,它是一个允许你像使用 Redux 那样使用 reducer 的 React Hook。在复杂的应用中,你需要管理很多相互关联并且可能需要复杂的操作逻辑的组件状态,以上这一切只通过使用 useState 会变得僵硬且繁琐,这正是 useReducer 展现其价值和作用的时候。

javascript
const [state, dispatch] = useReducer(reducer, initialArg, init);

useReducer 需要三个参数:一个 reducer 函数,一个 初始 state 和一个可选的 init 函数,它会返回当前的 state 值以及配套的 dispatch 方法。

使用案例

一、计数器

一个非常基础的计数器的代码片段

typescript
import 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 列表功能

除了简单的计数器例子,我们还可以尝试一些更复杂的场景。

javascript
import 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 是如何优雅地处理富有复杂状态逻辑的操作。

使用建议

  1. 当状态逻辑复杂以至于无法简单的使用 useState 管理时,可以考虑使用 useReducer
  2. 当相互关联且需要在多个事件句柄之间同步的状态过多时,使用 useReducer 将非常便利。
  3. 在使用 useReducer 时,应当保证你的 reducer 函数是纯函数,即在相同的输入下永远返回同样的输出,没有副作用。

总结

useReducer 是一个非常强大的使用 React Hooks 进行状态管理的工具。通过引入 reducer 的概念,我们能更好的组织和管理复杂的状态逻辑。使用 useReducer,我们可以按照一种更加结构化和可预见的方式更新状态。

在下一篇文章中,我们将探索使用 useEffect 进行副作用的管理,这又是一个非常有力的工具,敬请期待。记得点击关注以获取更新提醒!