• 何以解忧
    置顶
    2021-06-10
    关于子组件props 不变,可以减少不必要的渲染问题,不是特别理解。似乎只要父组件重新渲染子组件必然重新渲染,是内部有什么别的地方优化么?

    作者回复: 好问题,之前在 Class 组件中可以把组件继承自 React.PureComponent,从而 props 没变就不重新 render。现在函数组件没有 PureComponent的概念,但是提供了 React.memo (https://reactjs.org/docs/react-api.html#reactmemo) 这样一个高阶组件,可以让任何 React 组件都能在 props 不变时就不重新渲染。所以,在开发过程中,即使现在没有使用 React.memo,但是使用 useCallback 或者 useMemo 至少可以为性能优化提供一个基础。

    共 8 条评论
    17
  • 满月
    2021-06-01
    我们能否用 state 去保存 window.setInterval() 返回的 timer 呢? 我理解的是可以,只是没有 useRef 更优,因为在更新 state 值后会导致重新渲染,而 ref 值发生变化时,是不会触发组件的重新渲染的,这也是 useRef 区别于 useState 的地方。

    作者回复: 100分~

    共 3 条评论
    67
  • 桃翁
    2021-06-01
    useRef 如果只是用来 在多次渲染之间共享数据,是不是直接可以把变量定义到组件外面,这样也可以达到目的,感觉还更方便一点呢。

    作者回复: useRef 可以保证这个变量只在当前组件的实例中使用。也就是说,如果一个组件页面上有多个实例,比如: <div><Timer /><Timer /></div> 那么组件外的普通变量是被 Timer 共享的,就会产生问题。

    共 5 条评论
    28
  • cyh41
    2021-06-01
    是任何场景 函数都用useCallback 包裹吗?那种轻量的函数是不是不需要?

    作者回复: 确实不是,useCallback 可以减少不必要的渲染,主要体现在将回调函数作为属性传给某个组件。如果每次都不一样就会造成组件的重新渲染。但是如果你确定子组件多次渲染也没有太大问题,特别是原生的组件,比如 button,那么不用 useCallback 也问题不大。所以这和子组件的实现相关,和函数是否轻量无关。但是比较好的实践是都 useCallback。

    共 4 条评论
    15
  • 七月有风
    2021-06-03
    问下老师,useCallback、useMemo 和 useEffect的依赖机制一样吗?都是浅比较吗?

    作者回复: 是的,所以依赖比较都是浅比较

    共 2 条评论
    6
  • Geek_71adef
    2021-06-01
    1 useState 实现组件共享,考虑到组件之间的通信 2 state 去保存的话 会造成异步渲染 造成无限循环

    作者回复: 只有需要触发 UI 更新的状态才需要放到 state 里。这里的 timer 其实只是临时存放一个变量,无需用 state 保存。否则会造成不必要的渲染。

    
    6
  • 院长。
    2021-06-11
    有个问题想问下,关于useMemo,文档说的是性能优化的保证,也就是涉及到大量计算的时候可以使用,因为依赖项的比较本身也是有开销的。 那如果我就只是很简单的计算,或者就只是返回一个固定的对象,有必要使用吗

    作者回复: 依赖项比较大的性能开销可以忽略。useMemo 其实除了解决自身计算的性能问题之外,还有就是可以避免 接收这个数据的组件过多的重新渲染,以及依赖这个数据的其它 hooks 多余的计算。所以即使简单的计算,最好也是用 useMemo。

    
    4
  • 闲闲
    2021-06-01
    useCallBack依赖是空数组表示什么?

    作者回复: 没有意义,相当于每次都创建一个新的函数

    共 6 条评论
    4
  • 开开之之
    2021-06-06
    老师,我也有同样的疑问,定时器的例子,不能用一个常量去保存吗? import React, { useState, useCallback, useRef } from 'react' export default function Timer() { const [time, setTime] = useState(0) const timer = useRef(null) let timer2 = null const handleStart = useCallback(() => { timer2 = window.setInterval(() => { // 这里是个闭包,每次拿到的time值是0,所以要这样写手动去更新time的值 setTime((time) => time + 1) }, 1000) }, [time]) const handleStop = useCallback(() => { window.clearInterval(timer2) timer2 = null }, []) return ( <div> {time / 10} seconds. <br/> <button onClick={handleStart}>start</button> <button onClick={handleStop}>stop</button> </div> ) }
    展开

    作者回复: 你这个写法,看上去能够 work 是因为 handleStop 没有将 timer2 设为依赖项,eslint 会报错。其实在你第二次 start 后就无法 stop 了。因为 timer 一直是第一次的值。

    共 5 条评论
    2
  • 琼斯基亚
    2021-06-03
    老师,请问: const handleIncrement = useCallback(() => setCount(count + 1), [count]); const handleIncrement = useCallback(() => setCount(q => q + 1), []); 在性能方面是否后者优于前者?我的理解: 后者只创建了一次函数,但是又调用了多次在setCount的回调函数 前者只会在count变化的时候创建新的回调函数 这样分析下来我又觉得两者没什么差异 我不是太清楚这两者的优缺点,希望得到老师的解答。

    作者回复: 严格来说,后者确实优于前者,因为后者在 count 变化时不会创建新的 handleIncrement 这样的 callback,这样接收这个属性的组件就不需要重新刷新。但是对于简单的场景,可以忽略这种差异。

    共 4 条评论
    1