1. ホーム
  2. reactjs

[解決済み] react hooks useEffect() cleanup for only componentWillUnmount?

2022-05-08 18:28:03

質問

私の問題を簡単に解決するために、このコードの結果を説明しましょう。

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

このとき ForExample component がマウントされると、'effect' がログに記録されます。これは componentDidMount() .

そして、名前入力を変更するたびに、「効果」と「クリーンアップ」の両方がログに記録されます。逆に、ユーザー名の入力を変更しても、メッセージは記録されません。 [username] の第2パラメータに useEffect() . これは componentDidUpdate()

最後に ForExample component がアンマウントされると、'cleaned up' がログに記録されます。これは componentWillUnmount() .

みんな知っていることです。

要約すると、コンポーネントの再レンダリング(アンマウントを含む)のたびに 'cleaned up' が実行されます。

もし、このコンポーネントがアンマウントされたときだけ 'cleaned up' を記録するようにしたい場合は、次のように useEffect()[] .

しかし、もし私が [username][] , ForExample component は実装されなくなりました。 componentDidUpdate() を名前入力に使用します。

私がやりたいことは、コンポーネントが両方の componentDidUpdate() のみで、名前入力は componentWillUnmount() . (コンポーネントがアンマウントされる瞬間だけログが「クリーンアップ」されます)

解決方法は?

クリーンナップは username を使用すれば、クリーンアップを別の useEffect で、第二引数に空の配列が渡されます。

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>