Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hacker0limbo/f62f2bd6b9e6b158f8c345e63341d569 to your computer and use it in GitHub Desktop.
Save hacker0limbo/f62f2bd6b9e6b158f8c345e63341d569 to your computer and use it in GitHub Desktop.
关于 useEffect, class 组件, 函数组件里 state, props 的一些笔记

两个计数器代码:

使用 class:

import React, {Component} from "react";
import ReactDOM from "react-dom";

class Example extends Component {
  state = {
    count: 0
  };
  componentDidMount() {
    setTimeout(() => {
      console.log(`You clicked ${this.state.count} times`);
    }, 3000);
  }
  componentDidUpdate() {
    setTimeout(() => {
      console.log(`You clicked ${this.state.count} times`);
    }, 3000);
  }
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({
          count: this.state.count + 1
        })}>
          Click me
        </button>
      </div>
    )
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);

使用 hook:

import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";

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

  useEffect(() => {
    setTimeout(() => {
      console.log(`You clicked ${count} times`);
    }, 3000);
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>
        Click me
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);

操作: 连续点击 5 次增加按钮:

  • hook 的组件 timeout 以后依次显示 1, 2, 3, 4, 5
  • class 的组件 timeout 以后依次显示 5, 5, 5, 5, 5

原因

由于函数组件使用闭包的特点, 每一次调用useEffect()函数, 里面的 count 都是当前的 state, 相当于渲染 5 次, 每次都是一份快照, 里面的 state 也是独立的, 因此最后的结果也是符合直觉

class 组件在每次 state 更新重新渲染以后, 都会去修改 this.props或者this.state, 这样永远都是拿到的最新的 state 或者 props

对于函数式组件, 如果想要获取 state 的最新值, 需要使用 ref

同时, 函数式组件里面, 例如使用setCount(count+1)这种, 这里的count永远都是一个, 因此尽量使用setCount(prevCount => prevCount+1)这种写法进行 state 更新, 如下的例子设置 state 永远只会设置一次, 例如:

setCount(count+1)
setCount(count+1)

由于闭包的原因, 这里相当于:

setCount(2)
setCount(2)

关于useEffect: 最后, 如果一个函数有使用到 props 或者 state, 那么这个函数会参与到数据流中, 两种办法:

  • 使用useCallback包裹, 当然其中的 dependency array 里需要包含该函数访问到的组件里的 props 和 state
  • 直接将该函数放入useEffect中, dependency array 里面同样需要包含该函数访问到的 props 和 state
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment