【Day 22】Hook 05:useReducer

Reducer

Reducer 这个概念,
来源於 React 的延伸套件 Redux,
其核心由 React 拿来参考後,
开发出了 React 原生 API ── useReducer。

所谓 Reducer 就是用模组化方式
自订处理、改变数据的一套逻辑,
useState 的底层即是以 useReducer 实践,
可视为扩充版的 useState。


useReducer

useReducer 核心要素
基本上与 Redux 完全相同

  • Actions:描述「行为内容」的物件
  • Reducer:负责计算,对应每种 Action 实际如何改变资料
  • Store:资料库,储存修改後的资料

Reducer 必须是 pure function,不得处理有副作用的行为,以确保每次计算结果都相同。

使用方法

const [state, dispatch] = useReducer(reducer, initialState, init?)

参数

  • reducer:定义如何处理资料
  • initialState:初始值
  • init(选填):计算初始值的 function

返回值

  • state:返回的资料
  • dispatch:更新 state 的方法(可视为自订的 useState),接受 action 作为参数

使用范例

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] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

指定初始 state

方法一:作为 useReducer 第二个参数传入

  const [state, dispatch] = useReducer(
    reducer,
    {count: initialCount}
  );

方法二:Lazy initialization

传入 init function 作为第三个参数,
初始 state 会是 init function 的回传值。

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>
    </>
  );
}

这可以将初始 state 的计算逻辑
提取到之外 reducer 之外,
也方便处理重置 state 的 action。


与 Redux 的差异

  • 跟 Redux 的 store 不同,useReducer 储存的值是 component 的 state,需要另外搭配 useContext,才能实现全局存取(global store)。
  • useReducer「没有 middleware」,无法使用如 Redux-Thunk 或 Redux-Saga 等工具,来进行 data fetching 或处理 side effect。

参考资料


<<:  Day23 - Shioaji X Backtesting - RSI低买高卖策略

>>:  Day23 AR隐形眼镜 实现前的最後几哩路 是坎坷的天堂路还是一路顺风的云霄飞车呢?

[从0到1] C#小乳牛 练成基础程序逻辑 Day 3 - Hello World

打Code打Call | 主控台App | Hello World 🐄点此填写今日份随堂测验 ...

Day02网页设计的三巨头!

网页设计的三巨头 为什麽会说三巨头呢 因为要做好一个网页最重要的就是HTML, CSS, JavaS...

RNN

今天来介绍NN的另一个类别,RNN主要是运用在sequence data做预测,也就是任何有序的资料...

[Day 28] 建立注册的画面及功能(十二) - 寄出注册通知信

寄送会员通知信 Laravel基於SwiftMailer函式库开发了一套邮件套件, 可以支援多种服务...

Day 06:专案01 - 超简单个人履历05 | CSS版面布局、Flex

昨天讲完的CSS的文字和区块属性後,今天要接续介绍版面布局的属性,以及一个非常好用的布局容器 - F...