react 使用hook_如何在React中使用Debounce和Throttle并将其抽象为Hook
react 使用hook
Hooks are a brilliant addition to React. They simplify a lot of logic that previously had to be split up into different lifecycles with
classcomponents.
钩子是React的绝佳补充。 它们简化了许多以前必须通过
class组件拆分为不同生命周期的逻辑。
They do, however, require a different mental model, especially for first-timers.
但是,他们确实需要不同的思维模式, 尤其是对于初学者 。
I also recorded a short video series on this article which you may find helpful.
我还在本文上录制了一个简短的视频系列 ,您可能会有所帮助。
防抖和油门 (Debounce and throttle)
There are a ton of blog posts written about debounce and throttle so I won't be diving into how to write your own debounce and throttle. For brevity, consider debounce
and throttle
from Lodash.
有大量关于防抖和节流的博客文章,因此我不会深入研究如何编写自己的防抖和节流。 为简便起见,请考虑从Lodash进行debounce
和throttle
。
If you need a quick refresher, both accept a (callback) function and a delay in milliseconds (say
x) and then both return another function with some special behavior:
如果需要快速刷新,则都接受一个(回调)函数和一个毫秒级延迟 (例如
x),然后都返回另一个具有某些特殊行为的函数:
debounce
: returns a function that can be called any number of times (possibly in quick successions) but will only invoke the callback after waiting forx
ms from the last call.debounce
:返回一个可以多次调用的函数(可能是快速连续调用),但是仅在等待上次调用x
ms 之后才调用回调。throttle
: returns a function that can be called any number of times (possibly in quick succession) but will only invoke the callback at most once everyx
ms.throttle
:返回可以多次调用的函数(可能是快速连续调用),但每x
ms最多只能调用一次回调。
用例 (Usecase)
We have a minimal blog editor (here's the GitHub repo) and we would like to save the blog post to the database 1 second after the user stops typing.
我们有一个最小的博客编辑器(这是GitHub repo ),并且我们希望在用户停止键入后1秒钟将博客文章保存到数据库中。
You may also refer to this Codesandbox if you wish to see the final version of the code.
如果您希望查看代码的最终版本,则也可以参考此Codesandbox 。
A minimal version of our editor looks like this:
我们的编辑器的最低版本如下所示:
import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { setValue(event.target.value); }; return ( <main> <h1>Blog</h1> <textarea value={value} onChange={handleChange} rows={5} cols={50} /> <section className="panels"> <div> <h2>Editor (Client)</h2> {value} </div> <div> <h2>Saved (DB)</h2> {dbValue} </div> </section> </main> ); }
Here,
saveToDbwould actually be an API call to the backend. To keep things simple, I'm saving it in state and then rendering as
dbValue.
在这里,
saveToDb实际上是对后端的API调用。 为了简单
dbValue,我将其保存为state,然后呈现为
dbValue。
Since we only want to perform this save operation once user has stopped typing (after 1 second), this should be debounced.
因为我们只希望,一旦用户停止输入(1秒后)保存操作执行此,本应去抖 。
Here's the starter code repo and branch.
这是入门代码存储库和分支。
创建一个去抖动功能 (Creating a debounced function)
First of all, we need a debounced function that wraps the call to
saveToDb:
首先,我们需要一个去抖动的函数来包装对
saveToDb的调用:
import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // highlight-starts const debouncedSave = debounce(() => saveToDb(nextValue), 1000); debouncedSave(); // highlight-ends }; return <main>{/* Same as before */}</main>; }
But, this doesn't actually work because the function
debouncedSaveis created fresh on each
handleChangecall. This will end up debouncing each keystroke rather than debouncing the entire input value.
但是,由于该功能,这实际上并不工作
debouncedSave创建每个新
handleChange通话。 这样最终会消除每个按键,而不是消除整个输入值。
useCallback (useCallback)
useCallback
is commonly used for performance optimizations when passing callbacks to child components. But we can use its constraint of memoizing a callback function to ensure the
debouncedSavereferences the same debounced function across renders.
将回调传递给子组件时, useCallback
通常用于性能优化。 但是,我们可以使用它的记忆一个回调函数的约束,以确保该
debouncedSave引用同去抖功能跨越渲染。
I also wrote this article here on freeCodeCamp if you wish to understand the basics of memoization.
如果您希望了解记忆的基础知识,我也在freeCodeCamp上写了这篇文章 。
This works as expected:
这按预期工作:
import React, { useState, useCallback } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // highlight-starts const debouncedSave = useCallback( debounce(nextValue => saveToDb(nextValue), 1000), [], // will be created only once initially ); // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return <main>{/* Same as before */}</main>; }
useRef (useRef)
useRef
gives us a mutable object whose
currentproperty refers to the passed initial value. If we don't change it manually, the value will persist for the entire lifetime of the component.
useRef
为我们提供了一个可变对象,其
current属性引用传递的初始值。 如果我们不手动更改它,则该值将在组件的整个生命周期内保持不变。
This is similar to class instance properties (i.e. defining methods and properties on
this).
这类似于类实例的属性(即,限定上的方法和属性
this)。
This also works as expected:
这也可以按预期工作:
import React, { useState, useRef } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // This remains same across renders // highlight-starts const debouncedSave = useRef(debounce(nextValue => saveToDb(nextValue), 1000)) .current; // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return <main>{/* Same as before */}</main>; }
Continue reading on my blog for how to abstract these concepts into custom hooks or check out the video series.
继续在我的博客上阅读有关如何将这些概念抽象为自定义钩子的内容,或查看视频系列 。
You may also follow me on Twitter to stay updated on my latest posts. I hope you found this post helpful. :)
您也可以在Twitter上关注我,以了解我的最新帖子。 希望这篇文章对您有所帮助。 :)
翻译自: https://www.freecodecamp.org/news/debounce-and-throttle-in-react-with-hooks/
react 使用hook
- 如何在C#中使用全局鼠标、键盘Hook
- 如何使用Runtime.addShutdownHook
- 如何在已有的 Web 应用中使用 ReactJS
- 如何在C#中使用全局鼠标、键盘Hook
- 如何使用Android或iphone手机调试react-native应用
- Android中使用react-native框架中的View组件如何使其中的文本换行
- 如何使用 npm 安装 React
- 如何在C#中使用全局鼠标、键盘Hook
- 浅谈 Underscorejs中 _.throttle 和 _.debounce 的差异和使用场景
- React Native如何使用 code-push 热更新
- 直播|百安居前端架构师陈国兴:如何使用React构建同构(isomorphic)应用
- 纯干货分享: 如何在 React 框架中使用SpreadJS
- 如何使用npm构建一个react demo项目
- react 中如何使用 ueditor 富态编辑器
- [原创]如何使用新版HooKlogger查找内存泄露(3版)
- 如何使用WINSOCK Api hook拦截修改socket数据包
- 关于Python中如何使用静态、类、抽象方法的权威指南
- 如何在React组建中使用百度地图api (react js)
- Andriod如何使用react-native-vector-icons
- 如何使用webpack+react+redux从头搭建Todolist应用