0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

予期しないuseEffectが動いている原因

Last updated at Posted at 2023-02-24

1. 要素の出しわけでrenderが走っている

もし第二引数を空[]にしても予期しないuseEffectが走る場合は、要素が新たに表示されてrenderが走っている可能性あり。
下記のような方法で子コンポーネントが表示、非表示されていないか確認する。
子コンポーネント側でuseEffectを使用している場合に予期しないuseEffectが走る可能性がある。

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

function ParentComponent() {
  const [showChild, setShowChild] = useState(false);

  const handleClick = () => {
    setShowChild(!showChild);
  };

  return (
    <div>
      <button onClick={handleClick}>
        {showChild ? 'Hide Child' : 'Show Child'}
      </button>
      {showChild && <ChildComponent />}
    </div>
  );
}

function ChildComponent() {
  useEffect(() => {
    console.log('ChildComponent rendered');
  }, []);

  return <div>This is the child component.</div>;
}

2. render毎に新しいobjectが作られている

同列のstateが変更した時に、再renderするのだがuseEffectの第二引数がrenderの度に違うobjectとして生成されている。

下記の例だと、ageとnameの値が変わらなかったとしてもrenderの度に新しいpersonとしてobjectが生成される。そのためpersonに関係ないsetDarkModeをした時もuseEffectが走ってしまう。

import { useEffect, useState } from "react";
import "./App.css";

function App() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");
  const [darkMode, setDarkMode] = useState(false);

  // renderの度に新しいperson objectを生成
  const person = { age, name };

  useEffect(() => {
    // darkModeが変わった時にも呼ばれる
    // personが毎回違うobjectとして認識されるため
    console.log(person);
  }, [person]);

  const appStyle = {
    backgroundColor: darkMode ? "black" : "white",
    color: darkMode ? "white" : "black",
  };

  return (
    <div style={appStyle}>
      <label>Name:</label>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <br />
      <label htmlFor="age-input">Age:</label>
      <input
        type="number"
        value={age ?? ""}
        onChange={(e) => setAge(e.target.value)}
      />
      <br />
      <label>Dark Mode:</label>
      <input
        type="checkbox"
        checked={darkMode}
        onChange={() => setDarkMode((prev) => !prev)}
      />
    </div>
  );
}

export default App;

image.png
上記にて、checkBox押した時にuseEffectを動かしたくない場合はuseMemoを使ってnameageが変更された時のみ新しいobjectを生成するようにすれば良い。

import { useEffect, useState, useMemo } from "react";
import "./App.css";

function App() {
  const [age, setAge] = useState(0);
  const [name, setName] = useState("");
  const [darkMode, setDarkMode] = useState(false);

  // personをuseMemo化することによってageとnameが変わった時のみ新しいobjectを生成するようにする
  const person = useMemo(() => {
    return { age, name };
  }, [age, name]);

  useEffect(() => {
    // darkModeが変わった時に呼ばれなくなる
    // ageとnameが変わった時のみpersonが生成されるため
    console.log(person);
  }, [person]);

  const appStyle = {
    backgroundColor: darkMode ? "black" : "white",
    color: darkMode ? "white" : "black",
  };

  return (
    <div style={appStyle}>
      <label>Name:</label>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <br />
      <label htmlFor="age-input">Age:</label>
      <input
        type="number"
        value={age ?? ""}
        onChange={(e) => setAge(e.target.value)}
      />
      <br />
      <label>Dark Mode:</label>
      <input
        type="checkbox"
        checked={darkMode}
        onChange={() => setDarkMode((prev) => !prev)}
      />
    </div>
  );
}

export default App;

image.png
チェックボックスを変更しても、useEffectが動かなくなった

参考ビデオ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?