深圳幻海软件技术有限公司 欢迎您!

React useEffect Hooks 传递不同参数有哪些执行规则和返回方式

2023-02-28

EffectHook可以让你在函数组件中执行副作用操作,这里提到副作用,什么是副作用呢,就是除了状态相关的逻辑,比如网络请求,监听事件,查找dom。可以这样说,在使用了useState或是useEffect这样的hooks之后,每次组件在render的时候都生成了一份本次render的state、f

Effect Hook 可以让你在函数组件中执行副作用操作,这里提到副作用,什么是副作用呢,就是除了状态相关的逻辑,比如网络请求,监听事件,查找 dom。

可以这样说,在使用了useState或是useEffect这样的hooks之后,每次组件在render的时候都生成了一份本次render的state、function、effects,这些与之前或是之后的render里面的内容都是没有关系的。而对于class component来说,state是一种引用的形式。这就造成了二者在一些表现上的不同。

只要是副效应,都可以使用useEffect()引入。它的常见用途有下面几种。

  • 获取数据(data fetching)
  • 事件监听或订阅(setting up a subscription)
  • 改变 DOM(changing the DOM)
  • 输出日志(logging)

副效应是随着组件加载而发生的,那么组件卸载时,可能需要清理这些副效应。

useEffect()允许返回一个函数,在组件卸载时,执行该函数,清理副效应。如果不需要清理副效应,useEffect()就不用返回任何值。

使用useEffect()时,有一点需要注意。如果有多个副效应,应该调用多个useEffect(),而不应该合并写在一起。

一、参数规则

1.可选的

2.数组类型

3.值为state或者props

二、不同的参数和返回

1.不传参数

默认的行为,会每次 render 后都执行,一般表单控制中使用。

类似于类组件中的componentDidMoount以及componentDidUpdate。

useEffect(() => {
    console.log('useEffect with no dependency')
})
  • 1.
  • 2.
  • 3.

2.空数组

传入第二个参数,每次 render 后比较数组的值没变化,不会在执行。

类似于类组件中的 componentDidMount。

useEffect(() => {
    console.log('useEffect with empty dependency')
}, [])
  • 1.
  • 2.
  • 3.

3.有一个或者多个值得数组

传入第二个参数,只有一个值,比较该值有变化就执行

传入第二个参数,有2个值的数组,会比较每一个值,有一个不相等就执行;

类似于类组件中的componentDidUpdate;

useEffect(() => {
    console.log('useEffect widh specify dependency')
}, [state, props])
  • 1.
  • 2.
  • 3.

4.返回一个函数

返回时传递一个函数进行卸载,在组件卸载时候调用;

类似于类组价中componentWillUnmout。

useEffect(() => {
   console.log('useEffect widh specify callback');   
   return () => {     
     console.log('useEffect with specify callback');   
   } 
})
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

使用 Hook 的示例

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

默认情况下,它在第一次渲染之后和每次更新之后都会执行。你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

数据获取,设置订阅以及手动更改 React 组件中的 DOM 都属于副作用。有些副作用可能需要清除,所以需要返回一个函数,比如挂载时设置定时器,卸载时取消定时器。

class Example extends Component {
  constructor (props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  componentDidMount() {
    this.id = setInterval(() => {
      this.setState({count: this.state.count + 1})
    }, 1000);
  }
  componentWillUnmount() {
    clearInterval(this.id)
  }
  render() { 
    return <h1>{this.state.count}</h1>;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

使用 Hook 的示例

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <h1>{count}</h1>
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.