尝试使用 reducer 进行状态管理。
那么,什么是 Reducer?
useReducer 钩子!
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
你以前听说过减速器吗?
当然啦,哥们儿,你在说什么呢?我简直爱死减法器了。我到处都用减法器,就连最简单的计数器应用里也用。
太好了!这篇文章不适合你😊。
如果你听说过 reducer,但从听说 reducer 的那一刻起就一直拖延,因为你觉得没有必要去学习这个过于复杂、错综复杂、曲折难懂的东西,而是想在所有需要管理状态的地方都使用 useState,那么你很幸运🍀。
在我看来,Reducer 是一种非常有趣的状态管理方式,它具有多种优点,我们将在本文中看到这一点。
那么,什么是 Reducer?
其实它只是个函数,没什么特别的。它接收参数,然后返回一个值,就像所有普通函数一样。
我们来看一下参数和返回值,好吗?
因此,每个 reducer 函数都会接收应用程序的初始状态和action(就像说“这是发生的事情”),并在 action 发生后抛出应用程序的新状态。
现在,在创建了这个 reducer 函数之后,你只需要分发 action 来更新状态即可。这就是 reducer 模式的基本原理。
开始建造!
好的!我们来创建一个div元素,并使用reducer来修改它的CSS属性。我喜欢先单独编写reducer,思考我想要执行哪些操作。
const INCREASE_WIDTH = "INCREASE_WIDTH";
const TOGGLE_FILL = "TOGGLE_FILL";
const cssReducer = (state, action) => {
if (action.type === INCREASE_WIDTH) {
return { ...state, width: state.width + 5 };
}
if (action.type === TOGGLE_FILL) {
return {
...state,
backgroundColor: state.backgroundColor === "white" ? "plum" : "white"
};
}
return state;
};
所以,我想增加这个框的宽度,并切换背景颜色。如您所见,我在顶部定义了两个操作类型:INCREASE_WIDTH和TOGGLE_FILL,它们都是字符串类型,这样做是为了防止拼写错误。如果您弄错了常量名称,就会弹出错误消息;而如果您到处都使用字符串,即使拼错了一个,也不会弹出任何消息。此外,它们还有助于自动补全功能,所以不妨试试吧👍🏻。
reducer 函数接收初始状态,并根据操作类型相应地改变状态并返回,从而更新视图。
你明白它的好处了吗?因为它只是一个函数,所以测试起来非常容易,只需提供初始状态对象和动作对象,它就会返回一个可预测的最终状态对象。完美🧈。
PS:如果你现在有点困惑也没关系,因为你刚刚看到了 reducer 函数,当我们在应用程序中完全实现它时,这一切就会变得有意义了,接下来就是实现它了。
useReducer 钩子!
useReducer 是 React 预构建的 hooks 之一,它使我们能够非常轻松地实现 reducer 模式,而无需借助 Redux 等外部库。
它缺少 Redux 的一些开箱即用的功能(例如应用中间件),所以这取决于你的应用程序是否需要这些功能。大多数情况下你不需要,但这最终还是需要你自己做出选择。
以下是使用方法
const [styles, dispatch] = useReducer(cssReducer, initialStyles);
useReducer 接受 reducer 和初始状态作为参数,并返回一个包含两部分的数组,第一部分是应用程序在任何给定时间的状态,第二部分是用于分发 action 的 dispatch 函数。
让我们一起编写所有代码,这样你就可以看到调度函数的实际运行情况了。
import React, { useReducer } from "react";
const INCREASE_WIDTH = "INCREASE_WIDTH";
const TOGGLE_FILL = "TOGGLE_FILL";
const initialStyles = {
border: "3px solid plum",
height: 100,
width: 100,
backgroundColor: "white"
};
const cssReducer = (state, action) => {
if (action.type === INCREASE_WIDTH) {
return { ...state, width: state.width + action.payload.step };
}
if (action.type === TOGGLE_FILL) {
return {
...state,
backgroundColor: state.backgroundColor === "white" ? "plum" : "white"
};
}
return state;
};
export default function App() {
const [styles, dispatch] = useReducer(cssReducer, initialStyles);
return (
<div className="App">
<div style={styles}></div>
<button
onClick={() => {
dispatch({
type: INCREASE_WIDTH,
payload: {
step: 10,
}
});
}}
>
Increase Width
</button>
<button
onClick={() => {
dispatch({
type: TOGGLE_FILL
});
}}
>
Toggle Fill
</button>
</div>
);
}
这里我们通过按钮点击来分发 action。action 对象至少应该包含一个 type 属性,但我们也可以传递更多关于 action 的信息,通常使用名为payload的键,就像我们在这里传递 step 属性一样,并且我们稍微修改了 reducer 函数来使用这个键。
这里有一个可供体验的在线演示。
另一个显而易见的优势是,它将所有逻辑从组件本身剥离出来,组件现在只负责渲染 HTML。您可以将 reducer 逻辑放在另一个文件中(甚至可以创建一个专门用于所有 action 的文件),从而使代码更易于维护。
当有很多活动部件时,Reducer 非常有用,例如在有很多字段的表单中,与其为每个字段使用 useState,不如尝试使用 reducer。
您还可以使用 reducer 从外部源获取数据并处理请求的所有不同阶段。
以下是我的看法。
import React, { useEffect, useReducer } from "react";
const REQUEST_LOADING = "REQUEST_LOADING";
const FETCH_SUCCESS = "FETCH_SUCCESS";
const FETCH_FAILURE = "FETCH_FAILURE";
const initialState = {
loading: false,
data: null,
error: null
};
const fetchReducer = (state, action) => {
if (action.type === REQUEST_LOADING) {
return {
date: null,
loading: true,
error: null
};
}
if (action.type === FETCH_SUCCESS) {
return {
data: action.payload.response,
loading: false,
error: null
};
}
if (action.type === FETCH_FAILURE) {
return {
data: null,
error: action.payload.error,
loading: false
};
}
return state;
};
export default function App() {
const [{ loading, data, error }, dispatch] = useReducer(
fetchReducer,
initialState
);
useEffect(() => {
dispatch({ type: REQUEST_LOADING });
fetch("some url")
.then((res) => res.json())
.then((response) => {
console.log(response);
dispatch({ type: FETCH_SUCCESS, payload: { response } });
})
.catch((err) => {
dispatch({ type: FETCH_FAILURE, payload: { error: err } });
});
}, []);
if (error) return <p>{error.message}</p>;
return (
<div className="App">
{loading ? <p>Loading...</p> : <p>{data.setup}</p>}
</div>
);
}
如果使用得当,reducers 的确有一些好处,但不要像开头那个人一样到处乱用。对于简单的状态管理,useState 就完全够用了。
文章来源:https://dev.to/tusharkashyap63/everything-about-reducers-395f