Day15-Redux 篇-实作范例

在今天的文章中,我们将会使用 Redux 去完成一个计数器的范例程序。

第一步

使用 createStore 建立一个 Redux store ,并将 store 用 react-redux 的 Provider 元件提供给 React 的母元件 App

// store/index.js
import { createStore } from 'redux';

const counterReducer = (state = { counter: 0 }, action) => {
  if (action.type === 'increment') {
    return { counter: state.counter + 1 };
  }

  if (action.type === 'decrement') {
    return { counter: state.counter - 1 };
  }

  return state;
};

const store = createStore(counterReducer);

export default store;
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';

import App from './App';
import store from './store/index';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

第二步

在元件使用 useSelector 和 useDispatch 这两个 hook ,这边介绍一下这两个 hook 的用法:

useSelector

使用这个 hook 可以从 store 里面去拿取想要的 state 出来,效用大致等於 connect 元件的 mapStateToProps。

ex:
const counter = useSelector(state => state.counter);

特点:

  1. 可以返回各种型别的值
  2. useSelector 回传的值(也就是取出的 state)若有更新,就会重新渲染元件
  3. 不接受 ownProps 参数,但可以透过 JavaScript 的闭包观念取得元件中的 props

useDispatch

透过这个 hook 会回传一个 dispatch 方法,可以让我们 dispatch actions,用来取代 mapStateToDispatch。

const dispatch = useDispatch();

useStore

另外还有一个 hook useStore,不过我们暂时不会用到,但还是介绍一下,它可以取得 store,并进行 getState()、subscribe() 、dispatch() 等函式呼叫。

const store = useStore();

在程序码中可以看到使用 useSelector 去取出 store 里面的 counter state,并透过 useDispatch 回传的 dispatch 方法去触发 reducer。

// Counter.js
import { useSelector, useDispatch } from "react-redux";

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);

  const incrementHandler = () => {
    dispatch({ type: "increment" });
  };

  const decrementHandler = () => {
    dispatch({ type: "decrement" });
  };

  return (
    <>
      <div>{counter}</div>
      <button onClick={incrementHandler}>Increment</button>
      <button onClick={decrementHandler}>Decrement</button>
    </>
  );
};

export default Counter;

完成以上程序码的实作後,就可以点击按钮做加减了。

3. 增加多一点 state

接着我们多加一个 toggle 按钮及一个点击一次就增加多个数字的按钮。

// store/index.js
import { createStore } from 'redux';

const initialState = { counter: 0, showCounter: true };

const counterReducer = (state = initialState, action) => {
  if (action.type === 'increment') {
    return {
      counter: state.counter + 1,
      showCounter: state.showCounter
    };
  }

  if (action.type === 'increase') {
    return {
      counter: state.counter + action.amount,
      showCounter: state.showCounter
    };
  }

  if (action.type === 'decrement') {
    return {
      counter: state.counter - 1,
      showCounter: state.showCounter
    };
  }

  if (action.type === 'toggle') {
    return {
      showCounter: !state.showCounter,
      counter: state.counter
    };
  }

  return state;
};

const store = createStore(counterReducer);

export default store;
// Counter.js
import { useSelector, useDispatch } from "react-redux";

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const show = useSelector((state) => state.showCounter);

  const incrementHandler = () => {
    dispatch({ type: "increment" });
  };

  const increaseHandler = () => {
    dispatch({ type: "increase", amount: 10 });
  };

  const decrementHandler = () => {
    dispatch({ type: "decrement" });
  };

  const toggleCounterHandler = () => {
    dispatch({ type: "toggle" });
  };

  return (
    <>
      {show && <div>{counter}</div>}
      <button onClick={incrementHandler}>Increment</button>
      <button onClick={increaseHandler}>Increase by 10</button>
      <button onClick={decrementHandler}>Decrement</button>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </>
  );
};

export default Counter;

到这边实作就完成了!实作的程序码范例在底下连结,明天将会介绍另一种撰写 Redux 的 library: Redux toolkit。

程序码范例(codesandbox)

2021/11/23 补充

这里补充一个管理多个 Reducer 的范例:
程序码范例

2022/01/26 补充

在范例中,可以看到 dispatch({ type: "increase", amount: 10 }); 等 action 物件,如果在多个地方使用的话就得重复去撰写同样的 action,所以可以建立一个 action creator 的函式,如果有多个地方同时去使用相同的 action,就只要去呼叫已经定义好 action 结构的该函式即可。

const increaseByNum = (num) => {
  return {
    type: "increase",
    amount: num
  };
};

<button onClick={() => dispatch(increaseByNum(10))}>Increase by 10</button>

<<:  树状结构转线性纪录再转二元树-孩子兄弟标记法 - DAY 15

>>:  Day15|【Git】git reset 补充 - 三种模式

Day 02 环境建置

安装Python 既然是用 Python 编写的框架,那理所当然的应该先建立 Python 的环境对...

【Day 2】什麽是分散式系统?RPC?

为了不让队友 panic,先发文,正在修改,有兴趣可以明日观看。 1.1 Introduction ...

Day25 实作MiddleWare(2)

昨天跟大家介绍完middleware的基本建立後,大家有没有理解并成功做出来呢! 如果对於这部分还有...

[第二十六只羊] 迷雾森林舞会XV 继续整理房间

天亮了 昨晚是平安夜 关於迷雾森林故事 苏醒 在发牌之前我们先稍微小小调整一下房间的介面 我对你 想...

STM32开发笔记02---新建库函数工程

架构图 创建工程 首先我们先创建一个资料夹example,路径最好配置为全英文,然後分别在examp...