关于javascript:useEffect进阶指南下

40次阅读

共计 3665 个字符,预计需要花费 10 分钟才能阅读完成。

React 的外部更新机制?

`<h1 class=”name”> 我的名字是:Kyrie</h1>
<h1 class=”name”> 我的名字是:IRVING</h1>
`

React 也跟 vue 有着 Diff 算法,它每次 render 只会更新与上一次渲染不同的节点和内容,所以下面的例子,React 只须要这样做:

h1.innerText = Kyrie -> h1.innerText = IRVING

那 useEffect 呢?

`function Demo() {
  const initCount = 0
  const [count, setCount] = useState(initCount)
  
  // 当咱们把 count 作为依赖传入时,count 扭转就会从新执行
  useEffect(() => {
    console.log(‘count 的值为:’, count)
  }, [count])
  
  return (
    <div>
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>count++</button>
    </div>
  ) 
}
`

所以 useEffect 的更新机制实现依附咱们传入的依赖,只有在 useEffect 里应用到的状态值都必须在依赖中申明,让 React 外部进行依赖更新。

所以,当依赖的状态变得多起来的时候,难免会让咱们在性能方面有所放心。

useEffect 传入依赖的正确形式?

当初有个需要:书写一个函数,每秒主动让 count+1

`function Demo() {
  const initCount = 0
  const [count, setCount] = useState(initCount)
  
  useEffect(() => {
   // 设定时器,每秒执行一次 setCount
    const timer = setInterval(() => {
      setCount(count + 1)
    }, 1000)
    
    return () => {
      clearInterval(timer)
    }
  }, [])
  
  return (
    <div>
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>count++</button>
    </div>
  ) 
}
`

下面的例子,咱们把 [] 作为 useEffect 的依赖,就是说 effect 只会在组件挂载后执行一次。定时器只须要设定一个,每秒 setInterval 后帮咱们把 count + 1 对吧,这不就能实现需求了吗

看起来貌似没什么问题,但运行起来发现 count 只自增了一次就停住了,也就是 useEffect 只执行了一次,what???

起因很简略,咱们把 [] 作为依赖,React 外部就会认为 effect 函数内没有依赖任何值,所以当 useEffect 第一次执行时,setCount(0 + 1) 此时 count = 1,而后 1s 后,setCount(1 + 1),count = 2?不,React 外部会主动疏忽第二次及当前的每次更新,因为咱们把 [] 作为依赖,就代表了 effect 只会执行一次,第二次开始,count 始终都是 1,这就导致了 count 变为 1 后就不减少了。

那好,咱们把 count 传入作为依赖

`useEffect(() => {
   // 设定时器,每秒执行一次 setCount
    const timer = setInterval(() => {
      setCount(count + 1)
    }, 1000)
    
    return () => {
      clearInterval(timer)
    }
  }, [count])
`

运行之后发现,问题的确解决了,count 胜利的每秒主动自增,但这其实不是最好的解决方案,因为咱们晓得每当 count 值扭转,就会触发 render,每次都会生成一个新的 useEffect,而后执行,从新生成一个定时器,尽管目标达到了,但这显然不是最优解,咱们最好能防止每次都生成一个新的定时器,因为这样咱们的定时器将毫无意义...

`useEffect(() => {
   // 设定时器,每秒执行一次 setCount
    const timer = setInterval(() => {
      setCount(count => count + 1)
    }, 1000)
    
    return () => {
      clearInterval(timer)
    }
  }, [])
`

能够看到,咱们把 count 从依赖中取出,而后在 setCount(count => count + 1),这样做得目标是为了通知 React,咱们只须要 count+1,并不需要读取它的值,因为 React 外部必定是晓得以后 count 的值,这样 effect 外部就不依赖 count 了,useEffect 只需执行一次即可,这也是 setState 的函数写法,函数的参数就是最新的状态值,如果不太理解这种写法的敌人能够去查一下材料,这里就不再过多论述了...

useEffect 配合 useReducer 应用?

这就是 useEffect 究极应用技巧,用法及其宽泛... 还是应用下面的例子,让咱们用 useReducer 改写一下

`function Demo() {
  const initState = {count: 0}
  const [state, dispatch] = useReducer(reducer, initState)
  
  function reducer(state, action) {
    switch(action.type) {
      case ‘increment’ :
        return {count: state.count + 1}
      default: 
        throw new Error(‘type 不存在 …’)
    } 
  }
  
  useEffect(() => {
   // 设定时器,每秒执行一次 setCount
    const timer = setInterval(() => {
      dispatch({type: ‘increment’})
    }, 1000)
    
    return () => {
      clearInterval(timer)
    }
  }, [dispatch]) // 这里咱们依赖了 dispatch 其实能够省略
  
  return (
    <div>
      <h2>{count}</h2>
      <button onClick={() => setCount(count + 1)}>count++</button>
    </div>
  ) 
}
`

大家可能会问我,这种写法的益处是什么?其实,咱们利用 useReducer 通过 action 来形容行为,实现状态和行为的拆散,在多个依赖的时候这种写法的劣势就能很好的体现进去。

还有最初一个疑点:为什么 dispatch 能够省略?其实下面的例子,即便咱们把 dispatch 从依赖中取出,也能失常运行,effect 也只会执行一次。这么神奇?effect 是怎么晓得咱们的行为是什么?其实,React 外部会帮咱们记住 dispatch 的各种行为(action),且能拿到最新的 count,这一系列操作是 React 外部产生的,并不需要放在 effect 内。

useMemo 和 useCallback(性能优化)?

useCallback(缓存函数)

`const memoizedSetCount = useCallback(
  () => {
    setCount(count + 1)
  },
  [count],
);
`

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的缓存版本,该回调函数仅在某个依赖项扭转时才会更新。

useMemo(缓存值:相似于 Vue 的计算属性)

`const memoizedCount = useMemo(() => {
  const doubleCount = count * 2
}, [count]);
`

把“创立”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项扭转时才从新计算缓存值。这种优化有助于防止在每次渲染时都进行高开销的计算。

到这里,useEffect 的进阶指南就介绍完了,要更好的使用 React hooks 还得日常开发中的实战和积攒,置信在往后的开发中,大家能更正当的应用 hooks,也能够封装属于集体的 hooks… 大家加油,一起学习。
正文完
 0