検索

ホームページ  >  に質問  >  本文

親コンポーネントの配列に対する子コンポーネントの更新によって引き起こされる無限の再レンダリングを防止します

学生 (子) コンポーネント内

学生 (親) コンポーネント内

質問/質問

ここでコードを参照してください: 私はCodeSandBoxリンク

です

Student.tsx(子供) リーリー

Students.tsx(親) リーリー

上記のコードに示すように、student (子) コンポーネントで

React.memo を使用し、handleStudentsChangeuseCallback を使用してみました。できればできると思います。無限ループを防ぎます。ただし、無限ループは続きます。

P粉197639753P粉197639753329日前560

全員に返信(1)返信します

  • P粉955063662

    P粉9550636622024-02-27 00:32:58

    ###質問###

    handleStudentsChange

    は、変更が発生したときに一度だけ無限に実行されるのではなく、最初のレンダリングから無限に実行されます。これは、Student コンポーネントには handleStudentsChange を呼び出す useEffect があり、これにより Students コンポーネントの状態が更新され、 が発生するためです。 Studentコンポーネントが再レンダリングされ、useEffect が再度呼び出されます (無限ループ)。 ###解決### handleStudentsChange

    を呼び出す必要があるのは、レンダリングのたびではなく、入力を更新した後でのみです。以下に、入力から

    blur

    イベント が発生した後に Students の状態を更新する例を示します。より賢い (そしてより複雑な) アプローチとして、props と state を比較して更新が必要かどうかを判断することもできますが、それは自分で判断してもらいます。

    const {フラグメント、StrictMode、useCallback、useEffect、useState} = 反応;
    const { createRoot } = ReactDOM;
    const { TextField } = マテリアルUI;
    
    関数 Student(小道具) {
      const [firstName, setFirstName] = useState(props.firstName);
      const [lastName, setLastName] = useState(props.lastName);
      const [グレード, setGrade] = useState(props.grade);
      const handleStudentsChange = props.handleStudentsChange;
      
      const onBlur = () => {
        handleStudentsChange(props.id, {
          ファーストネーム、
          苗字、
          学年、
        });
      };
    
      戻る (
        <フラグメント>
          <テキストフィールド
            ラベル="名"
            onBlur={onBlur}
            onChange={(イベント) => setFirstName(event.target.value)}
            値={名}
          />
          <テキストフィールド
            ラベル="姓"
            onBlur={onBlur}
            onChange={(イベント) => setLastName(event.target.value)}
            値={姓}
          />
          <テキストフィールド
            ラベル="グレード"
            onBlur={onBlur}
            onChange={(イベント) => setGrade(event.target.value)}
            値={グレード}
          />
        </フラグメント>
      );
    }
    
    関数 Student() {
      const [students, setStudents] = useState([
        { 名: "ジャスティン"、姓: "ビーバー"、学年: 100 },
        { 名: "ロバート"、姓: "オッペンハイマー"、学年: 100 }
      ]);
    
      const handleStudentsChange = useCallback(
        (インデックス、更新された学生) => {
          // console.log(index) // 値が変更されたときにのみ再レンダリングしたいのですが、無限ループになってしまいます
          
          console.log({ updatedStudent });
    
          setStudents((prevStudents) => {
            const updatedStudents = [...prevStudents];
            updatedStudents[インデックス] = updatedStudent;
            updatedStudents を返します。
          });
        }、
        []
      );
    
      戻る (
        <フラグメント>
          {students.map((student, インデックス) => {
            戻る (
              <学生
                キー={インデックス}
                id={インデックス}
                firstName={学生.名}
                lastName={学生.姓}
                学年={学生.学年}
                handleStudentsChange={(index, newStudent) =>
                  handleStudentsChange(index, newStudent)
                }
              />
            );
          })}
        </フラグメント>
      );
    }
    
    関数 App() {
      戻る (
        <div className="アプリ">
          <学生/>
        </div>
      );
    }
    
    const root = createRoot(document.getElementById("root"));
    root.render(<StrictMode><App /></StrictMode>);
    <スクリプト クロスオリジン src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <scriptcrossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <scriptcrossorigin src="https://unpkg.com/@mui/material@latest/umd/material-ui.production.min.js"></script>
    <div id="ルート"></div>

    返事
    0
  • キャンセル返事