揭秘 React Hooks:useReducer
React Hooks 提供了一种更简单的方式,可以将有状态的行为和副作用封装在函数式组件中,而不是使用类。有些 Hook 比其他 Hook 更容易理解,因此本系列文章将重点讲解那些不太容易理解的 Hook。
到目前为止,我们已经学习了 useCallback、useMemo、useRef 和 useContext,所以如果你还没看过我之前的文章,请务必去看看。本周,我们将从基础知识入手,讲解 JavaScript 的reduce方法。掌握了这些基础知识后,理解useReducer hook 以及如何在代码中使用它就容易多了。
什么是归约器?
reducer是一个用于获取单个值的action。reducer的目标是减少(显而易见!)。返回的值可以是数字、字符串、数组,甚至是对象,只要它是一个单独的值即可。此外,需要强调的是,reducer返回的是一个新值,而不是修改初始值。
当你想对一组值应用某种逻辑后得到单个值时, reduce 函数非常有用。例如,如果你想将一个数字数组相加得到总值,就像我们在下面的例子中所做的那样。
我们对一个名为 `array` 的数字数组应用 JavaScript 的 ` reduce`nums = [1,2,3,4,5]方法。该reduce方法接受两个参数:
reducer——一个提供指令以获取特定值的函数。在本例中,该函数用于将数组中所有给定值相加nums。
const reducer = (accumulator, currentValue) => accumulator + currentValue;
initialValue——执行函数指令时的起始值reducer。在我们的示例中,我们将初始值定义为 0,因此返回的总值仅反映数组中值的总和nums。
const initialValue = 0;
现在我们已经定义了所涉及的元素,让我们一起来看看它们是如何组合在一起的。该reduce方法接收我们的数据initialValue,并按照函数下方的指令逐步构建reducer,将数组中的每个值相加,nums直到最终返回一个总值。
// reducer method - the action that will be executed in order to get one value
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// array of values that we want to add up
const nums = [1,2,3,4,5];
// initial value set to 0
const initialValue = 0;
// JavaScript reduce method receives two parameters: the reducer function and initial value defined above
const totalValue = nums.reduce(reducer, initialValue);
useReducer() 是什么?
useReducer hook 用于状态管理。它接收以下参数:
reducer是一个提供状态管理指令的函数。它接受两个参数state,action并返回一个新的状态。
// reducer type
(state, action) => newState
initialState——初始值。它将根据reducer指令而改变。
看起来眼熟吗?没错……它和上面解释的reduce函数一样,都需要类似的参数。但是, useReducer hook 不像reduce那样只返回一个值,而是返回一个包含两个元素的数组:当前值state和一个dispatch函数。
const [state, dispatch] = useReducer(reducer, initialState);
如果你熟悉 React Hooks,那你可能之前用过useState。让我们来比较一下这两个 Hooks。
// useState implementation
const [state, setState] = useState(initialState);
// useReducer implementation
const [state, dispatch] = useReducer(reducer, initialState);
`useReducer`和`useState`都返回一个有状态的值(`statestate`)和一个用于更新状态的函数(`updateState`setState和 `dispatch)。此外,这两个钩子都接收一个初始状态值(`state`initialValue)。这两个初始化方法的主要区别在于, `useReducer`还接受一个reducer函数,该函数会在我们使用返回的函数时被调用dispatch。我们将在下一节中探讨`useReducer` 的工作原理。
如何使用 useReducer?
有时候,解释事物运作原理的最佳方法是举个例子,所以我们来看一个例子。这里给出一个定义initialState,它指的是一个数据存储,其中包含待领养犬只的列表,包括它们的名字、品种和领养状态。
const initialState = [
{
name: "Waffles",
breed: "Chihuahua",
adopted: false,
},
{
name: "Charlie",
breed: "Pitbull",
adopted: true,
},
{
name: "Prince",
breed: "German Shepherd",
adopted: false,
},
];
现在我们来创建一个reducer函数,用于在狗狗被领养或被退回时更新它们的initialState列表。该函数接受以下参数:
state- 我们目前待领养犬只的状况。
action- 包含以下内容的对象:
-
type我们想要执行的操作。在本例中,我们只构建了两个选项,adopt即“返回”。 -
payload可选数据。在我们的示例中,我们将传递狗狗的信息name,以便确定哪只狗狗被领养了,哪只狗狗被退回了。
const reducer = (state, action) => {
switch (action.type) {
case 'ADOPT':
return state.map(dog => {
if (dog.name === action.payload) dog.adopted = true;
return dog;
});
case 'RETURN':
return state.map(dog => {
if (dog.name === action.payload) dog.adopted = false;
return dog;
});
default:
return state;
}
}
现在终于到了实现useReducer() hook 的时候了!请看下面的示例,其中我们使用(待领养犬只列表)和我们创建的用于处理它们领养状态的函数定义了useReducer() hook 。initialStatereducer
我们遍历狗狗列表的状态,并显示一个按钮,按钮会根据狗狗当前的领养状态显示“已领养”adopt或“已领养”。分配给该按钮的处理程序会调用一个函数,该函数负责使用useReducer() hook返回的函数,并将需要执行的操作和狗狗的名字作为参数传递给该函数。returnonClickdispatchtypepayload
const adoptDog = name => dispatch({ type: 'ADOPT', payload: name });
该dispatch函数会将此数据传递给我们的reducer函数,我们将使用该数据type来确定需要运行的代码部分,并使用该数据payload来查找我们需要更新的狗记录。
何时应该使用 useReducer?
在解释useReducer hook 时,我们将其与useState进行了比较,所以你可能会想……我应该何时使用useReducer,何时使用useState?
在处理以下情况时,useReducer hook是比useState更可取的替代方案:
- 涉及多个子值的复杂状态逻辑
- 取决于其他状态元素状态的状态值
概括
-
当您想要在对一组值应用一些逻辑后获得单个值时,JavaScript 的reduce方法非常有用。
-
reducer会返回一个新值,而不是改变你的初始值。
-
useReducer hook 用于状态管理。
-
当处理复杂的状态逻辑、多个子值,或者状态依赖于状态子值时,应该使用useReducer hook 。
我希望这篇文章能帮助你更好地理解 JavaScript 的reduce方法和useReducer()钩子,并希望你能在未来的项目中运用这些概念。
我喜欢创作用简单易懂的语言解释概念的内容。为什么?因为知识就是力量,我想帮助初级开发者拓展知识,茁壮成长。
如果你觉得这篇文章有用,请点赞并关注我的推特和Dev.to账号,以便及时获取最新文章!
文章来源:https://dev.to/milu_franz/demystifying-react-hooks-usereducer-3o3n

