作者回复: 好问题,之前在 Class 组件中可以把组件继承自 React.PureComponent,从而 props 没变就不重新 render。现在函数组件没有 PureComponent的概念,但是提供了 React.memo (https://reactjs.org/docs/react-api.html#reactmemo) 这样一个高阶组件,可以让任何 React 组件都能在 props 不变时就不重新渲染。所以,在开发过程中,即使现在没有使用 React.memo,但是使用 useCallback 或者 useMemo 至少可以为性能优化提供一个基础。
作者回复: 100分~
作者回复: useRef 可以保证这个变量只在当前组件的实例中使用。也就是说,如果一个组件页面上有多个实例,比如: <div><Timer /><Timer /></div> 那么组件外的普通变量是被 Timer 共享的,就会产生问题。
作者回复: 确实不是,useCallback 可以减少不必要的渲染,主要体现在将回调函数作为属性传给某个组件。如果每次都不一样就会造成组件的重新渲染。但是如果你确定子组件多次渲染也没有太大问题,特别是原生的组件,比如 button,那么不用 useCallback 也问题不大。所以这和子组件的实现相关,和函数是否轻量无关。但是比较好的实践是都 useCallback。
作者回复: 是的,所以依赖比较都是浅比较
作者回复: 只有需要触发 UI 更新的状态才需要放到 state 里。这里的 timer 其实只是临时存放一个变量,无需用 state 保存。否则会造成不必要的渲染。
作者回复: 依赖项比较大的性能开销可以忽略。useMemo 其实除了解决自身计算的性能问题之外,还有就是可以避免 接收这个数据的组件过多的重新渲染,以及依赖这个数据的其它 hooks 多余的计算。所以即使简单的计算,最好也是用 useMemo。
作者回复: 没有意义,相当于每次都创建一个新的函数
作者回复: 你这个写法,看上去能够 work 是因为 handleStop 没有将 timer2 设为依赖项,eslint 会报错。其实在你第二次 start 后就无法 stop 了。因为 timer 一直是第一次的值。
作者回复: 严格来说,后者确实优于前者,因为后者在 count 变化时不会创建新的 handleIncrement 这样的 callback,这样接收这个属性的组件就不需要重新刷新。但是对于简单的场景,可以忽略这种差异。