We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
作者:Dave Ceddia 译者:前端小智 来源:daveceddia
作者:Dave Ceddia
译者:前端小智
来源:daveceddia
为了保证的可读性,本文采用意译而非直译。
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
这个礼拜《大迁世界》有抽奖活动,奖品:专栏 《左耳听风》 x3, 技术书 x5,欢迎关注回复:抽奖
看到“reducer”这个词,容易让人联想到Redux,但是在本文中,不必先理解Redux才能阅读这篇文章。咱们将一起讨论“reducer”实际上是什么,以及如何利用useReducer来管理组件中的复杂状态,以及这个新钩子对Redux意味着什么?
“reducer”
Redux
reducer
useReducer
如果你熟悉Redux或数组上中的reduce方法,你大概就知道“reducer”是什么。 如果不熟悉,“reducer”大概是一个带有2个值并返回1个值的函数这么个意思。
reduce
2
1
如果你有一系列的东西,并且想将这些东西组合成一个单独的物体。“函数式编程”中就是使用Array的reduce函数。 例如,如果你有一个数字数组并且想得到数组中所有数字的总和,咱们就可以写一个reducer函数并将它传递给reduce,如下所示:
let numbers = [1, 2, 3]; let sum = numbers.reduce((total, number) => { return total + number; },0)
如果你以前没用过这个,它可能看起来有点神秘。它所做的是为数组的每个元素调用函数,传入前一个total和当前元素 number。无论你返回什么,都会成为新的total。reduce的第二个参数(在本例中为0)是total的初始值。在本例中,reduce函数会被调用3次:
total
number
0
3
(0, 1)
(1, 2)
(3, 4)
6
reduce返回6,它保存在sum中。
sum
使用useReducer又会是什么样的?
各位花了在半篇幅来解释Array的reduce函数,因为 useReducer 参数与 reduce 相同,并且工作方式基本一样。 useReducer接收 (state, action) => newState,并且返回了一个与当前state成对的dispatch的方法。 咱们使用 useReducer 来编写上面的求和例子。
(state, action) => newState
state
dispatch
useReducer((state, acton) => { return state + action }, 0)
useReducer返回一个包含2个元素的数组,类似于useState hook。 第一个是当前状态,第二个是dispatch方法,如下所示:
useState
const [sum, dispatch] = useReducer((state, action) => { return state + action }, 0)
注意,state可以是任何值,它不一定是一个对象,可以是一个数字,一个数组,或者其他任何类型。
尽管 useReducer 是扩展的 hook, 而 useState 是基本的 hook,但 useState 实际上执行的也是一个 useReducer。这意味着 useReducer 是更原生的,你能在任何使用 useState 的地方都替换成使用 useReducer。
import React, { useReducer } from 'react'; function Counter() { // First render will create the state, and it will // persist through future renders const [sum, dispatch] = useReducer((state, action) => { return state + action; }, 0); return ( <> {sum} <button onClick={() => dispatch(1)}> Add 1 </button> </> ); }
点击按钮dispatch一个值为1的action,该action将被添加到当前状态,然后组件使用新的状态重新渲染。
action
这里故意展示了,派发action没有遵循Redux的典型模式{type: "INCREMENT BY"、value: 1}或其他类似的东西。hook 的世界是一个新的世界:值得考虑的是,你是否发现旧的模式有价值并希望保留它们,或者你是否愿意更改它们。
{type: "INCREMENT BY"、value: 1}
再来看看更接近典型Redux reducer 的例子。创建一个组件来管理购物列表,这里看还会使用另外一个 hook:useRef。
Redux reducer
useRef
首先,导入两个 hook
import React, { useReducer, useRef } from 'react';
然后创建一个设置ref和reducer的组件。 ref保存对表单的引用,以便咱们可以提取其值。
ref
function ShoppingList() { const inputRef = useRef(); const [items, dispatch] = useReducer((state, action) => { switch (action.type) { // do something with the action } }, []); return ( <> <form onSubmit={handleSubmit}> <input ref={inputRef} /> </form> <ul> {items.map((item, index) => ( <li key={item.id}> {item.name} </li> ))} </ul> </> ); }
请注意,在这种情况下,咱们的“state”是一个数组。 咱们通过useReducer第二个参数将它初始化为一个空数组,并从reducer函数返回一个数组。
useRef hook为DOM节点创建持久引用。 调用useRef会创建一个空的节点。它返回的对象具有current属性,因此在上面的示例中,咱们可以使用inputRef.current访问输入的DOM节点。 如果你熟悉React.createRef(),则其工作原理非常相似。
DOM
current
inputRef.current
React.createRef()
但是,useRef返回的对象不仅仅是一种保存DOM引用的方法。 它可以保存特定于此组件实例的任何值,并且它在渲染之间保持不变。
useRef可用于创建通用实例变量,就像使用具有this.whatever = value的React类组件一样。 唯一的问题是,写入它会被视为“副作用”,因此咱们无法在渲染过程中更改它,需要在useEffect hook 中才能修改。
this.whatever = value
React
useEffect
回到useReducer示例
我们用表单来处理用户的输入,按回车提交表彰。 现在来编写handleSubmit函数,该函数主要做的是将一个项添加到列表中,以及处理reducer中的 action。
handleSubmit
function ShoppingList() { const inputRef = useRef(); const [items, dispatch] = useReducer((state, action) => { switch (action.type) { case 'add': return [ ...state, { id: state.length, name: action.name } ]; default: return state; } }, []); function handleSubmit(e) { e.preventDefault(); dispatch({ type: 'add', name: inputRef.current.value }); inputRef.current.value = ''; } return ( // ... same ... ); }
在reducer函数中主要判断两种情况:一种用于action.type==='add'的情况,还有就是默认下的情况。
action.type==='add'
当action.type为 add 时,它返回一个包含所有旧元素的新数组,以及最后的新元素。
action.type
add
这里有一点需要注意的是,咱们使用数组的length作为一种自动递增的 ID 方便演示,但是对于一个真正的应用程序来说这是不可靠,因为它可能导致重复的ID和bug。(最好使用uuid这样的库,或者让服务器生成一个惟一的ID!)
length
当用户在输入框中按Enter键时会调用handleSubmit函数,因此咱们需要调用preventDefault以避免在发生这种情况时重新加载整页。 然后dispatch派发一个 action。
preventDefault
现在来看看如何从列表中删除项的。
在项目中添加一个删除<button>,点击该按钮派发 它将发送一个 action type === "remove"的操作,以及要删除的项的索引。
<button>
type === "remove"
然后咱们只需要在reducer中处理该action
function ShoppingList() { const inputRef = useRef(); const [items, dispatch] = useReducer((state, action) => { switch (action.type) { case 'add': // ... same as before ... case 'remove': // keep every item except the one we want to remove return state.filter((_, index) => index != action.index); default: return state; } }, []); function handleSubmit(e) { /*...*/ } return ( <> <form onSubmit={handleSubmit}> <input ref={inputRef} /> </form> <ul> {items.map((item, index) => ( <li key={item.id}> {item.name} <button onClick={() => dispatch({ type: 'remove', index })} > X </button> </li> ))} </ul> </> ); }
试着添加一个功能:添加一个清空列表的按钮。
在<ul>上方插入一个按钮,并为其提供一个onClick prop,派发一个action ,type 为“clear”的动作,并在 reducer 方法执行清空列表的动作。
<ul>
onClick prop
type
clear
可以在前面 CodeSandbox的基础上完成。
大部分人看到useReducer hook, React 现在已经内置了reducer ,它有Context传递数据,所以可能会想到 Redux 会不会因此就死了,以下是原作者给出的一些看法。
Context
作者不认为useReducer会杀死Redux。React Hook 扩展了React在状态管理方面的能力,所以会让使用 Redux的情况减少。
Redux仍然比Context + useReducer的组合做得更多,它具有Redux DevTools 用于调试,可定制中间件、,以及整个相关库生态系统,当然 Redu x在很多地方都被过度使用了,但它仍然具有强大的功能。
Redux提供了一个全局存储,可以在其中集中保存应用程序数据。useReducer本地化到特定组件。但是,没有什么可以阻止咱们使用useReducer和useContext构建自己的迷你redux 。如果你想这么做,而且符合你的需要,那就去做吧!
useContext
redux
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:
https://www.robinwieruch.de/react-usereducer-hook/
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
https://github.com/qq449245884/xiaozhi
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
为了保证的可读性,本文采用意译而非直译。
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
看到
“reducer”
这个词,容易让人联想到Redux,但是在本文中,不必先理解Redux
才能阅读这篇文章。咱们将一起讨论“reducer
”实际上是什么,以及如何利用useReducer
来管理组件中的复杂状态,以及这个新钩子对Redux意味着什么?Reducer 是什么鬼
如果你熟悉Redux或数组上中的
reduce
方法,你大概就知道“reducer”是什么。 如果不熟悉,“reducer
”大概是一个带有2
个值并返回1
个值的函数这么个意思。如果你有一系列的东西,并且想将这些东西组合成一个单独的物体。“函数式编程”中就是使用Array的
reduce
函数。 例如,如果你有一个数字数组并且想得到数组中所有数字的总和,咱们就可以写一个reducer
函数并将它传递给reduce
,如下所示:如果你以前没用过这个,它可能看起来有点神秘。它所做的是为数组的每个元素调用函数,传入前一个
total
和当前元素number
。无论你返回什么,都会成为新的total
。reduce
的第二个参数(在本例中为0
)是total
的初始值。在本例中,reduce
函数会被调用3
次:(0, 1)
返回1
(1, 2)
返回3
(3, 4)
返回6
reduce
返回6
,它保存在sum
中。使用
useReducer
又会是什么样的?各位花了在半篇幅来解释Array的
reduce
函数,因为useReducer
参数与reduce
相同,并且工作方式基本一样。useReducer
接收(state, action) => newState
,并且返回了一个与当前state
成对的dispatch
的方法。 咱们使用useReducer
来编写上面的求和例子。useReducer
返回一个包含2
个元素的数组,类似于useState
hook。 第一个是当前状态,第二个是dispatch
方法,如下所示:注意,
state
可以是任何值,它不一定是一个对象,可以是一个数字,一个数组,或者其他任何类型。尽管
useReducer
是扩展的 hook, 而useState
是基本的 hook,但useState
实际上执行的也是一个useReducer
。这意味着useReducer
是更原生的,你能在任何使用useState
的地方都替换成使用useReducer
。点击按钮
dispatch
一个值为1
的action
,该action
将被添加到当前状态,然后组件使用新的状态重新渲染。这里故意展示了,派发
action
没有遵循Redux的典型模式{type: "INCREMENT BY"、value: 1}
或其他类似的东西。hook 的世界是一个新的世界:值得考虑的是,你是否发现旧的模式有价值并希望保留它们,或者你是否愿意更改它们。一些更复杂的例子
再来看看更接近典型
Redux reducer
的例子。创建一个组件来管理购物列表,这里看还会使用另外一个 hook:useRef
。首先,导入两个 hook
然后创建一个设置
ref
和reducer
的组件。ref
保存对表单的引用,以便咱们可以提取其值。请注意,在这种情况下,咱们的“
state
”是一个数组。 咱们通过useReducer
第二个参数将它初始化为一个空数组,并从reducer
函数返回一个数组。useRef Hook
useRef
hook为DOM
节点创建持久引用。 调用useRef
会创建一个空的节点。它返回的对象具有current
属性,因此在上面的示例中,咱们可以使用inputRef.current
访问输入的DOM节点。 如果你熟悉React.createRef()
,则其工作原理非常相似。但是,
useRef
返回的对象不仅仅是一种保存DOM引用的方法。 它可以保存特定于此组件实例的任何值,并且它在渲染之间保持不变。useRef
可用于创建通用实例变量,就像使用具有this.whatever = value
的React
类组件一样。 唯一的问题是,写入它会被视为“副作用”,因此咱们无法在渲染过程中更改它,需要在useEffect
hook 中才能修改。回到
useReducer
示例我们用表单来处理用户的输入,按回车提交表彰。 现在来编写
handleSubmit
函数,该函数主要做的是将一个项添加到列表中,以及处理reducer
中的action
。在
reducer
函数中主要判断两种情况:一种用于action.type==='add'
的情况,还有就是默认下的情况。当
action.type
为add
时,它返回一个包含所有旧元素的新数组,以及最后的新元素。这里有一点需要注意的是,咱们使用数组的
length
作为一种自动递增的 ID 方便演示,但是对于一个真正的应用程序来说这是不可靠,因为它可能导致重复的ID和bug。(最好使用uuid这样的库,或者让服务器生成一个惟一的ID!)当用户在输入框中按Enter键时会调用
handleSubmit
函数,因此咱们需要调用preventDefault
以避免在发生这种情况时重新加载整页。 然后dispatch
派发一个action
。删除项
现在来看看如何从列表中删除项的。
在项目中添加一个删除
<button>
,点击该按钮派发 它将发送一个 actiontype === "remove"
的操作,以及要删除的项的索引。然后咱们只需要在
reducer
中处理该action
练习:清空列表
试着添加一个功能:添加一个清空列表的按钮。
在
<ul>
上方插入一个按钮,并为其提供一个onClick prop
,派发一个action
,type
为“clear
”的动作,并在reducer
方法执行清空列表的动作。可以在前面 CodeSandbox的基础上完成。
Redux 会死吗
大部分人看到
useReducer
hook, React 现在已经内置了reducer
,它有Context
传递数据,所以可能会想到Redux
会不会因此就死了,以下是原作者给出的一些看法。作者不认为
useReducer
会杀死Redux
。React Hook 扩展了React
在状态管理方面的能力,所以会让使用Redux
的情况减少。Redux
仍然比Context +useReducer
的组合做得更多,它具有Redux DevTools 用于调试,可定制中间件、,以及整个相关库生态系统,当然 Redu x在很多地方都被过度使用了,但它仍然具有强大的功能。Redux
提供了一个全局存储,可以在其中集中保存应用程序数据。useReducer
本地化到特定组件。但是,没有什么可以阻止咱们使用useReducer
和useContext
构建自己的迷你redux
。如果你想这么做,而且符合你的需要,那就去做吧!代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
原文:
https://www.robinwieruch.de/react-usereducer-hook/
交流
干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
The text was updated successfully, but these errors were encountered: