React@16.x(25)useReducer

目录

1,介绍

这也是官方的一个HOOK,目的是更方便的使用 Redux。

Redux 后续会详细介绍。它的主体思想沿用了 Flux 数据流框架(也是 FaceBook 出品的)的思想,Vuex 也是同样的实现。

1.1,Flux 的设计思想

  1. 数据是单项流动的。

  2. 数据存储在数据仓库 state 中(可以将 useState 的 state 简单理解为数据仓库)。

  3. action 是改变数据的唯一原因 ,它本质上是一个对象,有2个属性

    1. type,字符串,表示改变数据的动作类型;
    2. payload,any类型,表示动作的附加信息,也就是额外的参数。

    例如,添加一个学生:{ type: 'addStu', payload: { 学生对象的各种信息 } }

    例如,删除一个学生:{ type: 'deleteStu', payload: 学生id }

  4. reducer 改变数据的具体实现,是一个函数:

    1. 有2个参数
      1. state,表示当前数据仓库中的数据;
      2. action。
    2. 必须有返回值,表示数据仓库变化后的数据。另外,Flux 要求对象是不可变的,所以要修改 state 必须创建新的对象。
    3. 必须是纯函数,不能有任何副作用。
    4. 不能直接调用,必须通过辅助函数 dispatch。
  5. dispatch 是一个辅助函数,用于触发 reducer。该函数仅接收一个参数 action,并调用 reducer 来改变 state。

2,实现

2.1,引入

先看个简单例子:

js 复制代码
export default function App() {
    const [n, setN] = useState(0);
    return (
        <div>
            <button
                onClick={() => {
                    setN(n - 1);
                }}
            >
                -
            </button>
            <span>{n}</span>
            <button
                onClick={() => {
                    setN(n + 1);
                }}
            >
                +
            </button>
        </div>
    );
}

用 Flux 的思想改造:

js 复制代码
function reducer(state, action) {
    let newState = state;
    if (action.type === "minus") {
        newState = state <= 0 ? 0 : state - 1;
    } else if (action.type === "add") {
        newState = state + 1;
    }
    return newState;
}

export default function App() {
    const [n, setN] = useState(0);
    function dispatch(action) {
        const newN = reducer(n, action);
        setN(newN);
    }
    return (
        <div>
            <button
                onClick={() => {
                    dispatch({ type: "minus" });
                }}
            >
                -
            </button>
            <span>{n}</span>
            <button
                onClick={() => {
                    dispatch({ type: "add" });
                }}
            >
                +
            </button>
        </div>
    );
}

注意,通过 Flux 的思想,只是为了把逻辑拆分的更细,便于管理状态 state。

我要改变数据(dispatch),至于如何实现(reducer)并不关心。

而对使用状态的组件来说,影响并不大。因为完全可以直接使用 reducer 这个自定义函数。

2.2,实现 useReducer

dispatch 的实现很简单,所以可以考虑做成一个通用的 HOOK:useReducer。

js 复制代码
import { useState } from "react";

export const useReducer = (reducerFunc, initState) => {
    const [state, setState] = useState(initState);
    function dispatch(action) {
        const newState = reducerFunc(state, action);
        setState(newState);
    }
    return [state, dispatch];
};

使用:

js 复制代码
export default function App() {
    const [n, dispatch] = useReducer(reducer, 0);
    // 其他内容...
}

3,官方实现

React 考虑到这一点,所以官方实现了 useReducer 这个HOOK函数,并且还有第3个可选参数:

该函数将 useReducer 的第2个参数作为它的参数,返回值作为 useReducer 中的 state 初始值。

js 复制代码
import { useReducer } from "react";

改造下自己实现的:

js 复制代码
import { useState } from "react";

/**
 * 通用的useReducer函数
 * @param { function } reducer reducer函数
 * @param { any } initialState 初始状态
 * @param { function } initFunc 计算初始值的函数
 */
export const useReducer = (reducerFunc, initState, initFunc) => {
    const [state, setState] = useState(initFunc ? initFunc(initState) : initState);
    function dispatch(action) {
        const newState = reducerFunc(state, action);
        setState(newState);
    }
    return [state, dispatch];
};

以上。

相关推荐
阿明的小蝴蝶4 分钟前
自定义桌面应用、内置系统应用与镜像
前端
代码搬运媛22 分钟前
原生websocket 双工demo
前端
limit007526 分钟前
三维 WebGIS 工具选型:加载、样式、分析、交付,一套界面能做完什么
android·前端·web3·安卓·webgl
全栈项目管理程序猿33 分钟前
ArcGIS JS 基础教程(35):体元系列 - VoxelLayer 时间维度动画
前端·javascript
mantou13242 分钟前
从纯 CSR 到 SSR:用 WebComponents 做一个 Next.js 式框架 Gemkit
前端·全栈·web components
cidy_9843 分钟前
深度拆解任务工作台架构:左右分栏、队列管理、实时刷新全方案
前端
Linye1 小时前
告别“PRD 与原型两张皮”!我们把可交互原生组件直接嵌进了需求文档,还能双向回写 Markdown
前端
deli0071 小时前
RSA 为什么公开公钥也解不开?2 个质数拆开实测一遍
前端
ModyQyW1 小时前
vite-plugin-uni-pages 0.6:统一扫描规则,开发期少重启
前端·uni-app
门思科技1 小时前
把 ThinkLink 接进 Home Assistant 与 Node-RED:一条 MQTT 转发器能走通的路
前端