web-dev-qa-db-ja.com

React同等のフックとコンポーネントのライフサイクル

componentDidMountのようなReactフックを使用するcomponentDidUpdatecomponentWillUnmount、およびuseEffectライフサイクルフックに相当するものは何ですか?

18
Yangshun Tay

componentDidMount

空の配列を2番目の引数としてuseEffect()に渡し、マウント時にのみコールバックのみを実行します。

_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()で十分です。

これは 答えは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>_
37
Yangshun Tay

From React docs

Reactクラスライフサイクルメソッドに精通している場合、useEffectフックはcomponentDidMount、componentDidUpdate、およびcomponentWillUnmountを組み合わせたものと考えることができます。

ということで彼らは意味する:

componentDidMountuseEffect(callback, [])のようなものです

componentDidUpdateuseEffect(callback, [dep1, dep2, ...])のようなものです-depsの配列はReactに伝えます: "変更したら、レンダリング後にコールバックを実行してください」

componentDidMount + componentDidUpdateuseEffect(callback)のようなものです

componentWillUnmountは、コールバックから返された関数の一種です。

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

Dan Abramov の彼の blog のフレージングと、私自身のいくつかの追加の助けを借りて:

これらのフックを使用できますが、完全に同等ではありません。 componentDidMountcomponentDidUpdateとは異なり、captureの小道具と状態になります。そのため、コールバック内でも、特定のレンダーのプロップと状態が表示されます(つまり、componentDidMountで最初のプロップと状態が表示されます)。 「最新の」何かを見たい場合は、refに書き込むことができます。しかし、通常、コードを構造化するより簡単な方法があるため、必要はありません。 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は常に、特定のレンダーに属するカウントではなく、latestカウントを指します。

6
Edan Chetrit