---
title: React useCallback()/useEffect()最佳实践
category: clean-code, excellence
---

先占个坑。是个重要又重复的问题。可以尝试写一写。

## 大纲

* 什么时候用？
  * 期望场景：默认都要写上所有参数。参数有变化就重新执行，很多场景往往也是这种要求。
  * 实际情况：有很多功能不变但引用变的函数，需要被一次次引入依赖数组，降低代码可读性。
* 有什么不合适的场景？
  * 希望只在页面进入时触发一次的场景，依赖常常是有意被忽略：`useMount()`/`useUnmount()`解决
  * 其他可用封装函数解决的：比如埋点相关功能，`usePageAnalytics()`封装解决
  * **依赖数组只有/有大量的三方库函数（常见的如自己封装的hooks `setXXX()`、redux的`dispatch()`、国际化`t()`等） —— 这个没想好怎么解决，`useEvent()`？这样又会忽略掉对参数的更新。**
* 归根结底，`useCallback`/`useEffect`这个依赖数组是好的吗？是希望在某些参数有变化的时候重新触发计算逻辑？我总结下来觉得：
  * `useEffect`依赖变化时触发是可能有的，这条规则确实可以有。但是仍然有可能引入大量功能不变引用改变的函数
  * `useCallback`一般来说很没必要，函数应该只关注它的输出，不应该关注函数本身的引用。
  * 如果函数本身能够设计成输出只与输入有关系，那么函数就可以被合理地传递，不在意引用。不过这样一来，在React组件中使用闭包特性设计函数的做法就会被减弱了。
  * **但是说到底，结果正确是最重要的，不用`useCallback`最坏的结果就是组件重复渲染，这在大多数情况下都不是问题，这样也可以解放闭包的使用。因此，这条是我推荐的最佳实践**
  * 使用函数，应该关注的就只有输入输出，还关注什么函数本身的引用，虽然我理解这是React做性能优化（使用浅比较决定组件是否重新渲染）对设计组件带来的要求，但还是过分繁琐、不必要，让编程更困难了
* `useCallback`唯一一个合适的场景，就是跟`useMemo`结合使用，避免组件重新渲染，用作性能提升用。
  * 性能提升的话，一般只会出现在大量渲染的组件上，比如`Table`等
