学习下react的hook(useEffect)

167 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

前言

上一篇文章讲了react hook的useState, 这篇文章再来看看其它的hook,useEffect

useEffect

这个是叫副作用 hook,主要是用来解决副作用的逻辑,比如修改dom,异步请求等等。 因为函数组件原本设计是纯函数,并不计划执行这些操作。

这些逻辑在class组件基本上是在componentDidMount生命周期执行的,然后就可以把这些逻辑迁移到这里。

但是不仅仅如此。

其实在componentDidUpdate生命周期和componentWillUnmount生命周期都会执行。

它其实相当于componentDidMountcomponentDidUpdatecomponentWillUnmount的合并。

这样是不是很方便?

它接受2个参数,第一个就是要执行的副作用的函数,没有参数,第二个是指定哪些state数据更新时才会执行useEffect, 数组形式,里面是对应的state的key。

如果不填的时候,则所有数据更新时都会执行useEffect如果填空数组,则不会在数据更新时执行(相当于componentDidUpdate生命周期不会执行)

然后如果组件被销毁时,如果想把useEffect里的函数清除掉,比如setTimeout,要clearTimeout掉。

这时你可以在第一个函数里返回清除函数,里面是清除的逻辑。

例子

下面通过例子来学习下useEffect:

function HelloWorld () {
  const [text, setText] = useState('hello world')
  useEffect(() => {
    console.log('执行 useEffect')
    // 模拟异步请求
    const timer = setInterval(() => {
      console.log('timer')
    }, 1000)
  })
  return (
    <div onClick={() => { setText('答案cp3') }}>{text}</div>
  )
}

image.png

可以看到一进入页面会打印一次执行 useEffect(相当于componentDidMount

然后就一直执行setInterval

然后点击按钮,会重新打印执行 useEffect(相当于componentDidUpdate)。

然后我们来模拟componentWillUnmount生命周期的代码,第一个函数需要返回清除函数

代码如下:

function HelloWorld () {
  const [text, setText] = useState('hello world')
  useEffect(() => {
    console.log('执行 useEffect')
    // 模拟异步请求
    const timer = setInterval(() => {
      console.log('timer')
    }, 1000)
    return () => {
      console.log('清除 useEffect')
      clearInterval(timer)
    }
  })
  return (
    <div onClick={() => { setText('答案cp3') }}>{text}</div>
  )
}

function App () {
  const [show, setShow] = useState(true)

  return (
    <div>
      <button onClick={() => setShow(false)}>show:{show.toString()}</button>
      {show && <HelloWorld />}
    </div>
  )
}

image.png

页面会执行 useEffect,然后点击button,会把show设置为false,然后就会执行useEffect的清除函数(相当于componentWillUnmount)。

然后timer就不会再打印了。

下面再来看看useEffect的第二个参数的用法。不传就是监听所有数据的更新,传了就是只监听对应数据的更新。

function HelloWorld () {
  const [text1, setText1] = useState('text1')
  const [text2, setText2] = useState('text2')
  useEffect(() => {
    console.log('执行 useEffect')
  }, [text2])
  return (
    <div>
      <div onClick={() => { setText1('text1更新') }}>{text1}</div>
      <div onClick={() => { setText2('text2更新') }}>{text2}</div>
    </div>
  )
}

执行后就会发现,点击第一个按钮不会重新执行useEffect,点击第二个按钮才会,因为它监听的是text2