React Hooks技术最佳实践(二)

欢迎访问个人博客html

原文地址:React Hooks技术最佳实践(二)react

useEffect

useEffect是除useState以外使用最经常使用的Hooks之一,它能够用来管理反作用,替代传统class组件中的componentDidMountcomponentWillUnmount方法或是根据依赖项来执行代码。数组

useEffect的用法并不复杂,可是若是对于它的执行过程和机制不熟悉的话,仍是很容易出现死循环、依赖运算错误等问题。同时,它每次运行都至关于对当前的状态存储了一份快照,这就这意味在它当中执行setTimeout获取到的都不是最新的状态,而是运行时的状态。想要更加深刻了解的推荐阅读useEffect 完整指南浏览器

本文章属于React Hooks技术最佳实践的第二篇文章,第一篇介绍了useState的最佳实践,感兴趣的朋友能够阅读React Hooks技术最佳实践(一)异步

替代componentDidMount

经过设置useEffect的第二个依赖参数为[]能够替代componentDidMount,虽然它们的执行时机不是彻底一致的。这样咱们就能够在useEffect中处理须要在组件挂载后的操做或者异步请求,它可以获取到state。由于依赖项为[],因此在整个组件生命周期中只会在挂载时运行。async

useEffect(() => {
  // 在组件挂载后处理事务或反作用
  // 可以获取到state
}, []) 
复制代码

反作用

先来看看如何正确的使用async方法。ide

错误的示范函数

useEffect(async () => {
  const { data, result } = await asyncRequest();  
}, [])
复制代码

useEffect并不建议你在回调函数中直接使用async,这样使用会直接触发报错,一般若是安装了相关lint的话会有提示。由于这么使用会致使回调函数相互之间产生竞争状态,而Effect回调函数应该是同步的。布局

推荐的作法post

const requestFn = async () => {
  const { data, result } = await asyncRequest(); 
}

useEffect(() => {
  requestFn();
}, [])
复制代码

若是须要在获取异步数据以后更新state,也能够在requestFn函数中处理。

const [value, updateValue] = useState();

const requestFn = async () => {
  const { data, result } = await asyncRequest();
  updateValue(value);
}

useEffect(() => {
  requestFn();
}, [])
复制代码

若是异步请求依赖任何的state,则须要清晰的写在useEffect的依赖项中,这样每次在state改变以后都会执行异步请求。

const requestFn = async (param) => {
  const { data, result } = await asyncRequest(param);
  updateValue(value);
}

useEffect(() => {
  requestFn(param);
}, [param])
复制代码

依赖

正确的使用

咱们知道每次state或者props改变都会致使组件的re-render,因此useEffect在没有任何依赖项时每次都会执行一遍。这时若是在它当中改变了state,那么就会致使死循环。过程就是执行useEffect改变了state,而改变state又致使了重复执行useEffect

错误的写法

const [count, updateCount] = useState(0);

useEffect(() => {
  updateCount(prevCount => prevCount++);   
})
复制代码

正确的写法一

const [count, updateCount] = useState(0);

// 增长前置条件,知足时才执行更新状态
useEffect(() => {
  if (count < 1) {
    updateCount(prevCount => prevCount++);  
  }
})
复制代码

正确的写法二

const [count, updateCount] = useState(0);
const [num, updateNum] = useState(1)

// 依赖num,每次num改变后才会执行Effect
useEffect(() => {
  updateCount(prevCount => prevCount+num);  
}, [num])
复制代码

依赖函数

除了使用stateprops做为依赖项,函数也是能够直接做为依赖项使用。不过因为函数每次在组件渲染时都会从新执行,因此Effect会不必的重复执行。

不过可使用useCallback方法来避免这种状况。

每次渲染都重复执行Effect

const doSomething = () => {}

useEffect(() => {
  // do somethings 
}, [doSomething])
复制代码

使用useCallback

const doSomething = () => useCallback(() => {}, [])

useEffect(() => {
  // do somethings once
}, [doSomething])
复制代码

若是函数依赖任何其余的状态执行,则能够将依赖加入到useCallback的依赖数组项中,这样在依赖项改变后函数都会从新执行,Effect因为依赖了函数,因此Effect也会执行。

优化

正确的使用Effect的依赖是很是重要的,每次依赖改变后都会使用Object.is方法来比较,若是不一样,则执行Effect。因此咱们能够经过Memoization技术来优化,具体来讲就是每次状态改变后都会与以前记忆的状态做对比,若是值发生了改变,则返回新的状态,并记忆,若是值没有改变,只是引用变了,则返回记忆的状态。这样Effect只在值改变后才执行。

这一部分在以前的文章中有介绍,这里就不具体展开了。

Memoization技术在React中的应用

useLayoutEffect

大多数状况下使用useEffect便可,不过当你须要在useEffect中操做DOM时,为了优化渲染效果,可使用useLayoutEffect。它会在DOM更新完成以后再执行,同时能够读取到DOM布局并同步触发渲染,以后浏览器才进行绘制。

下一篇介绍其余的Hooks的用法与技巧。

官方的FAQ其实写的很不错,不少陷阱和技巧都介绍了,推荐阅读。

参考文章

  1. useEffect 完整指南
相关文章
相关标签/搜索