10|React Hooks(下):用Hooks处理函数组件的副作用
什么是副作用?
- 深入了解
- 翻译
- 解释
- 总结
React Hooks(下):用Hooks处理函数组件的副作用 本文深入探讨了React Hooks中的 `useEffect` 以及用于组件性能优化的Hooks:`useMemo` 和 `useCallback`。文章首先解释了副作用的概念,指出在计算机领域,副作用是指函数调用除了返回值外对主调函数产生的附加影响。在React中,诸如挂载、更新、卸载组件、事件处理、添加定时器、修改真实DOM、请求远程数据等行为都可以被称作副作用。此外,文章还提到了state绑定在组件函数之外的 `FiberNode` 上,从而引出了组件函数执行state更新函数也是一种副作用的观点。 通过深入讨论 `useEffect` 以及用于组件性能优化的Hooks:`useMemo` 和 `useCallback`,读者可以了解如何使用Hooks处理函数组件中的副作用,并学习如何优化组件性能。最后,文章回答了函数组件加Hooks是否可以完全替代类组件以及是否有必要学习类组件的疑问,为读者提供了全面的认识和思考角度。 本文通过深入讨论React Hooks中的 `useEffect` 以及用于组件性能优化的Hooks:`useMemo` 和 `useCallback`,帮助读者更好地理解和应用React Hooks,同时回答了相关疑问,为读者提供了全面的学习和思考视角。 文章还介绍了`useMemo` 和 `useCallback` 的完整概念和最典型的使用场景。`useMemo` 的功能是为工厂函数返回一个记忆化的计算值,在两次渲染之间,只有依赖值数组中的依赖值有变化时,该Hook才会调用工厂函数重新计算,将新的返回值记忆化并返回给组件。而`useCallback` 则会把作为第一个参数的回调函数返回给组件,只要第二个参数依赖值数组的依赖项不改变,它就会保证一直返回同一个回调函数(引用),而不是新建一个函数,从而优化组件性能。 此外,文章还强调了Hooks的使用规则,包括只能在React的函数组件中调用Hooks以及只能在组件函数的最顶层调用Hooks等限制,以及解释了这些限制的原因。 总之,本文内容丰富,深入探讨了React Hooks中的 `useEffect` 以及用于组件性能优化的Hooks:`useMemo` 和 `useCallback`,并介绍了Hooks的使用规则,为读者提供了全面的学习和思考视角。
《现代 React Web 开发实战》,新⼈⾸单¥59
全部留言(9)
- 最新
- 精选
- 🐑置顶你好,我是《现代React Web开发实战》的编辑辰洋,这是👇项目的源代码链接,供你学习与参考:https://gitee.com/evisong/geektime-column-oh-my-kanban/releases/tag/v0.10.02022-09-19归属地:北京1
- 船长不是很理解 useMemo 那个例子,比如用 下面这个useEffect 写法不是也可以持久化记忆数据吗?好像只是比 useMemo 那种写法多了个 setXXX 所造成的一次渲染? const [num, setNum] = useState("0"); const [num2, setNum2] = useState("0"); useEffect(() => { const n = parseInt(num, 10); setNum2(fibonacci(n)); }, [num]);
作者回复: 你好,船长,从实现功能来讲你用useState+useEffect代替useMemo是可行的。正如你说的,确实多了一次渲染。具体来说,useMemo的回调是在渲染过程中执行,而useEffect的回调会在提交阶段执行,useEffect回调内部调用了useState的话,会触发一次新的渲染。从用户感知上应该没太大差别,毕竟渲染过程是异步的,useEffect的回调也是异步的。 在实际项目中,我们可能会遇到连续在一个组件中写十来个Hooks的情况,每当存在这种跨多次渲染还相关的Hooks,都会多少增加一些调试的难度。
2022-09-21归属地:北京22 - 学习前端-react请问:use Effect 的执行是可以拿到真实dom的,那为啥在图中提交阶段却是在真实dom之前?
作者回复: 你好,学习前端-react,抱歉这几天在赶稿回复晚了。 你说得对。useEffect的副作用回调和清除函数,它们都在提交阶段执行,且大多情况都是异步执行的。这些函数被加入callback更新队列。在真实DOM绘制之后,下一次React渲染之前,这个队列里的callback会依次执行,所以这时候callback能拿到真实DOM。 这张图在第一次画时,只画了同步执行的情况,给大家造成了误解,还请见谅。目前图片已经做了更新,依然省略了一些实现细节,但更贴近实际情况了,请以这一版为准。
2022-09-14归属地:北京32 - 都市夜归人const KanbanCard = ({ title, status }) => { const [displayTime, setDisplayTime] = useState(status); useEffect(() => { const updateDisplayTime = () => { const timePassed = new Date() - new Date(status); let relativeTime = '刚刚'; // ...省略 setDisplayTime(relativeTime); }; const intervalId = setInterval(updateDisplayTime, UPDATE_INTERVAL); updateDisplayTime(); return function cleanup() { clearInterval(intervalId); }; }, [status]); 可以看到,useEffect 接收了副作用回调函数和依赖值数组两个参数,其中副作用回调函数的返回值也是一个函数,这个返回的函数叫做清除函数。组件在下一次提交阶段执行同一个副作用回调函数之前,或者是组件即将被卸载之前,会调用这个清除函数。 没有看懂,上面的哪有两个参数啊?
作者回复: 你好,都市夜归人,抱歉这两周在赶稿回复晚了。这里说的是useEffect的两个参数。 const KanbanCard = ({ title, status }) => { const [displayTime, setDisplayTime] = useState(status); 这段代码只是为了提示一下useEffect所在的相对位置。 下面的: useEffect(() => { // ... return function cleanup() { // ... }; }, [status]); 中的: () => { // ... return function cleanup() { // ... }; } 就是useEffect第一个参数,称作副作用回调函数(Effect Callback); 而后面的: [status] 就是第二个参数,称作依赖值数组(Dependencies)。
2022-09-15归属地:北京41 - 满眼星🌟 辰🍊图例中,useLayoutEffect是同步更新dom,应该在useEffect之前执行,不是吗
作者回复: 你好,满眼星辰,抱歉这几天在赶稿回复晚了。 你说得对。useEffect记录的副作用回调和清除函数,都在提交阶段执行,且大多情况都是异步执行的。这些函数被加入callback更新队列。在真实DOM绘制之后,下一次React渲染之前,队列里的callback会依次执行。 在第一次画图例时,只画了同步执行的情况,给你造成了误解,还请见谅。目前图片已经做了更新,依然省略了一些实现细节,但更贴近实际情况了,请以这一版为准。
2022-09-16归属地:北京 - 都市夜归人其实这两个 Hooks 与 useEffect 并不沾亲带故。且不说它们的用途完全不同,单从回调函数的执行阶段来看,前者是在渲染阶段执行,而后者是在提交阶段。 这句话与上面的生命周期图不太一致,求解惑
作者回复: 你好,都市夜归人,这两周我都在赶稿,抱歉回复晚了。这里所指的“回调函数”,对于: const memoized = useMemo(() => createByHeavyComputing(a, b), [a, b]); 指的是其中的() => createByHeavyComputing(a, b),同时也叫工厂函数; 对于 const memoizedFunc = useCallback(() => {if (a) b()}, [a, b]); 指的是() => {if (a) b()}; () => createByHeavyComputing(a, b) 和 () => {if (a) b()} 如果符合执行条件的话,会在渲染阶段执行。 对于 useEffect(() => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }}, [province]); 指的是 () => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }} 如果符合执行条件的话,() => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }} 会在提交阶段执行。
2022-09-16归属地:北京2 - ImartuseEffect 是在浏览器渲染/呈现dom内容后执行的; useLayoutEffect 是在真实dom更新后,浏览器渲染dom内容前执行的,即在render函数执行后,接着同步马上执行回调函数内容;2022-11-15归属地:广东2
- Socrakit我试图在 handleSubmit 里调用 handleSaveAll(),希望每次新增“待处理” 后自动保存,但失败了。调用 handleSaveAll 的时候 todoList 还没有被更新,第二次新增后才会把第一次新增的保存进去,这是为什么呢 ? const handleSubmit = (title) => { const d = new Date() const n = d.toLocaleDateString().replace('/', '-') + ' ' + d.toLocaleTimeString(); setTodoList(currentTodoList => [ { title, dt: n}, ...currentTodoList ]); handleSaveAll() };2023-07-12归属地:江苏
- Geeker个人觉得框架不应该把“负担” 甩给用户2022-11-04归属地:浙江