[Day 23 - Redux] React + Redux = React-redux

前情提要:在前面的文章有了Redux,状态管理没烦恼,学到了如何在 Redux 透过 Action 管理更新所有的 State。接下来就让我们学习如何在 React 中使用 Redux 来处理资料状态。

Redux 是一个独立的状态管理函式库,它可以搭配原生 Javascript 直接撰写出一个应用程序,也可以与其他框架像是 React、Angular 一起运作。而当 Redux 与 React 结合时,会使用 React-redux 这个延伸的函式库,有效的来解决 React Component 间 State 复杂化的问题

安装React-redux

Fork 一份之前所使用的React - 计时器范例程序码,基於这个架构从头来使用 React-redux。

React-redux 前面建置步骤基本上跟单纯使用 Redux 一样,要事先建立 Action、Reducer、Store,所以我们直接贴上前篇建立好的三份程序码 actions.js、reducer.js、store.js,里面包含了 Redux 应用在计数器的内容。

actions.js

export const ADD_SCORE = "ADD_SCORE";
export const REDUCE_SCORE = "REDUCE_SCORE";

// action creator
export function addScore(idx) {
  return {
    type: ADD_SCORE,
    payload: { idx }
  };
}

export function reduceScore(idx) {
  return {
    type: REDUCE_SCORE,
    payload: { idx }
  };
}

reducer.js

import { ADD_SCORE, REDUCE_SCORE } from "./actions";

const initialState = {
  members: [
    { name: "May", score: 0 },
    { name: "Julia", score: 0 },
    { name: "Selina", score: 0 }
  ]
};

export default function appReducer(state = initialState, action) {
  switch (action.type) {
    case ADD_SCORE: {
      let new_members = state.members;
      new_members[action.payload.idx] = {
        ...new_members[action.payload.idx],
        score: new_members[action.payload.idx].score + 1
      };
      return {
        members: new_members
      };
    }
    case REDUCE_SCORE: {
      let new_members = state.members;
      new_members[action.payload.idx] = {
        ...new_members[action.payload.idx],
        score: new_members[action.payload.idx].score - 1
      };
      return {
        members: new_members
      };
    }
    default:
      return state;
  }
}

store.js

import { createStore } from "redux";
import rootReducer from "./reducer";

const store = createStore(rootReducer);

export default store;

传递 Store

接着就让我们正式将 React 与 Redux 结合,我们首先要做的就是让 React Component 知道 Store,才能读取资料和调用动作,所以就透过在 Root component 使用 <Provider> 的方式来传递 Store。

...
import { Provider } from "react-redux";
import store from './store'

ReactDOM.render(
  <StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>,
  rootElement
);

从 Store 读取状态

要从 Store 读取状态,可以使用 useSelector 这个方法,直接提取 Redux Store 中的状态数据到指定的元件中。并且它会对之前的选择器回传值和当前的回传值进行比较,如果不同,相关的组件就会重新渲染。

App.js

import { useSelector } from "react-redux";

export default function App() {
  const members = useSelector((state) => state.members);

  return (
    <div className="App">
      ...
      {members.map((member) => (
        <Member key={member.name} idx={index} />
      ))}
    </div>
  );
}

Member.js

...
import { useSelector } from "react-redux";

export default function Member(props) {
  const members = useSelector((state) => state.members);

  return (
    <div className="member">
      <h2>{members[props.idx].name}</h2>
      <div>{members[props.idx].score > 0 ? "PASS" : "FAIL"}</div>
      <Counter idx={props.idx} />
    </div>
  );
}

Counter.js

import { useDispatch, useSelector } from "react-redux";
import { addScore, reduceScore } from "../actions";

export default function Counter(props) {
  const score = useSelector((state) => state.members[props.idx].score);

  return (
    <div className="Counter">
      <h3>{score}</h3>
      ...
      {score > 0 && (
        <button>minus</button>
      )}
    </div>
  );
}

调用动作

完成从 Store 读取资料状态後,最後一个步骤就是要可以在组件中调用动作,来修改 State 的值。我们可以透过 useDispatch() 这个方法,发动指定的 Action 到 Reducer 中更新 State。

Counter.js

...
import { useDispatch, useSelector } from "react-redux";
import { addScore, reduceScore } from "../actions";

export default function Counter(props) {
  const score = ...
  const dispatch = useDispatch();

  return (
    <div className="Counter">
      ...
      <button onClick={() => dispatch(addScore(props.idx))}>Plus</button>
      {score > 0 && (
        <button onClick={() => dispatch(reduceScore(props.idx))}>minus</button>
      )}
    </div>
  );
}


小结

在 React 中使用 Redux 的 React-redux 基本上就是这样运作的,以往在 React 中需要透过提升 State 层级才能在 Component 间共同使用状态,结合 Redux 集中状态管理的功能,就能有效的管理复杂的 State,弥补了 React 框架的缺点更提升它的优势。

范例程序码

如果文章中有错误的地方,要麻烦各位大大不吝赐教;喜欢的话,也要记得帮我按赞订阅喔❤️

参考资料


<<:  Day 23 | 在Flutter里串接restful api - 我不使用HttpClient了 jojo

>>:  DAY22神经网路

Golang 转生到web世界 - template

Golang 玩一下html template 如果golang要使用作为网站的话,不太可能都只靠p...

Day 26 - [Android APP] 04-MVVM - Repository与API串接

前几天介绍的 MVVM 架构,可以参考这篇 [[Android APP] 01-架构介绍-MVVM]...

案例:AWS MLOps Framework - 解决方案介绍

在AWS solutions library你可以找到数十份各式各样的解决方案参考文件,在这个解决方...

D11 - 「数位×IN×OUT」:数位功能

数位 I/O 视窗当然是要有数位讯号相关功能啦。 数位 I/O 功能 在 Supported Mod...

Day 28. 解掉bug了

啊..败给旅游燃烧殆尽症候群了,昨天晚上不小心睡着,忘记设闹钟,再醒来就已经过12点了QwQ    ...