React Hooks和Component Lifecycle等效

问题描述 投票:12回答:2

使用像componentDidMount这样的React钩子的componentDidUpdatecomponentWillUnmountuseEffect生命周期钩子的等价物是什么?

javascript reactjs react-hooks
2个回答
23
投票

componentDidMount

将一个空数组作为第二个参数传递给useEffect(),仅在mount上运行回调。

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentDidUpdate

更新发生后立即调用componentDidUpdate()。初始渲染不会调用此方法。 useEffect在每个渲染上运行,包括第一个渲染。因此,如果您想要与componentDidUpdate具有严格的等价物,则必须使用useRef来确定组件是否已安装一次。如果你想更加严格,使用useLayoutEffect(),但它会同步发射。在大多数情况下,useEffect()应该足够了。

这个answer is inspired by Tholle,所有功劳归于他。

function ComponentDidUpdate() {
  const [count, setCount] = React.useState(0);

  const isFirstUpdate = React.useRef(true);
  React.useEffect(() => {
    if (isFirstUpdate.current) {
      isFirstUpdate.current = false;
      return;
    }

    console.log('componentDidUpdate');
  });

  return (
    <div>
      <p>componentDidUpdate: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <ComponentDidUpdate />,
  document.getElementById("app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentWillUnmount

在useEffect的回调参数中返回一个回调函数,它将在卸载之前调用。

function ComponentWillUnmount() {
  function ComponentWillUnmountInner(props) {
    React.useEffect(() => {
      return () => {
        console.log('componentWillUnmount');
      };
    }, []);

    return (
      <div>
        <p>componentWillUnmount</p>
      </div>
    );
  }
  
  const [count, setCount] = React.useState(0);

  return (
    <div>
      {count % 2 === 0 ? (
        <ComponentWillUnmountInner count={count} />
      ) : (
        <p>No component</p>
      )}
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentWillUnmount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

1
投票

来自React docs

如果您熟悉React类生命周期方法,则可以将useEffect Hook视为componentDidMount,componentDidUpdate和componentWillUnmount的组合。

通过这个说他们的意思是:

componentDidMount是useEffect(callback, [])的一种

componentDidUpdate是useEffect(callback, [dep1, dep2, ...])的一种 - deps数组告诉React:“如果其中一个deps发生了变化,则在渲染后运行回调”。

componentDidMount + componentDidUpdate是useEffect(callback)的一种

componentWillUnmount是回调函数的返回函数:

useEffect(() => { 
    /* some code */
    return () => { 
      /* some code to run when rerender or unmount */
    }
)

Dan Abramovblog短语的帮助下,以及我自己的一些补充:

虽然你可以使用这些钩子,但它并不完全等同。与componentDidMountcomponentDidUpdate不同,它将捕获道具和状态。所以即使在回调中,你也会看到特定渲染的道具和状态(这意味着在componentDidMount中最初的道具和状态)。如果你想看到“最新”的东西,你可以把它写到参考。但是通常有一种更简单的方法来构建代码,这样您就不必这样做了。假设替换componentWillUnmount的返回函数也不是精确等价的,因为每次组件重新渲染时以及组件卸载时函数都会运行。请记住,效果的心理模型与组件生命周期不同,尝试找到它们的确切等效项可能会让您感到困惑,而不仅仅是帮助。为了提高效率,您需要“思考效果”,并且他们的心理模型更接近于实现同步而不是响应生命周期事件。

Dan的博客示例:

function Counter() {
  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(count + 1)}>
        Click me
      </button>
    </div>
  );
}

enter image description here

如果我们使用类实现:

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

enter image description here

this.state.count总是指向最新的计数,而不是属于特定渲染的计数。

© www.soinside.com 2019 - 2024. All rights reserved.