cari

Rumah  >  Soal Jawab  >  teks badan

Cegah pemaparan semula tanpa had yang disebabkan oleh kemas kini komponen anak kepada tatasusunan komponen induk

Dalam komponen pelajar (kanak-kanak)

Dalam komponen pelajar (ibu bapa)

Soalan/Soalan

Lihat kod di sini: Saya adalah pautan CodeSandBox

Pelajar.tsx(Anak)

import React, { useState, useEffect, useRef } from "react";
import TextField from "@mui/material/TextField";

interface student {
  firstName: string;
  lastName: string;
  grade: number;
}

interface studentProps {
  id: number;
  firstName: string;
  lastName: string;
  grade: number;
  handleStudentsChange: (index: number, student: student) => void;
}

function Student(props: studentProps) {
  const [firstName, setFirstName] = useState(props.firstName);
  const [lastName, setLastName] = useState(props.lastName);
  const [grade, setGrade] = useState(props.grade);

  useEffect(() => {
    handleStudentsChange(id, {
      firstName: firstName,
      lastName: lastName,
      grade: grade
    });
  }, [firstName, lastName, grade, props]);

  return (
    <>
      <TextField
        label="firstName"
        onChange={(event) => setFirstName(event.target.value)}
        value={firstName}
      />
      <TextField
        label="lastName"
        onChange={(event) => setLastName(event.target.value)}
        value={lastName}
      />
      <TextField
        label="grade"
        onChange={(event) => setGrade(+event.target.value)}
        value={grade}
      />
    </>
  );

Pelajar.tsx(ibu bapa)

import React, { useState, useCallback } from "react";
import Student from "./Student";

interface student {
  firstName: string;
  lastName: string;
  grade: number;
}

export default function Students() {
  const [students, setStudents] = useState<student[]>([
    { firstName: "Justin", lastName: "Bieber", grade: 100 },
    { firstName: "Robert", lastName: "Oppenhiemer", grade: 100 }
  ]);

  const handleStudentsChange = useCallback(
    (index: number, updatedStudent: student) => {
      // console.log(index) //I only want this to rerender when the value change however it turn into an infinity loop
      setStudents((prevStudents) => {
        const updatedStudents = [...prevStudents];
        updatedStudents[index] = updatedStudent;
        return updatedStudents;
      });
    },
    []
  );

  return (
    <>
      {students.map((student, index) => {
        return (
          <Student
            key={index}
            id={index}
            firstName={student.firstName}
            lastName={student.lastName}
            grade={student.grade}
            handleStudentsChange={(index: number, newStudent: student) =>
              handleStudentsChange(index, newStudent)
            }
          />
        );
      })}
    </>
  );
}

Seperti yang ditunjukkan dalam kod di atas, saya cuba menggunakan React.memo pada komponen pelajar (kanak-kanak) dan useCallback pada React.memo ,并在 handleStudentsChange 上使用 useCallback dengan harapan dapat menghalang gelung tak terhingga. Walau bagaimanapun, gelung tak terhingga berterusan.

P粉197639753P粉197639753261 hari yang lalu482

membalas semua(1)saya akan balas

  • P粉955063662

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

    Soalan

    handleStudentsChange不仅在发生更改时无限运行一次-它从第一次渲染开始就无限运行。这是因为Student组件具有调用handleStudentsChangeuseEffect,它更新了Students组件中的状态,导致Student组件重新渲染,然后再次调用useEffect, gelung tak terhingga.

    Penyelesaian

    Anda perlu memanggil negeri dalam handleStudentsChange,而不是在每次渲染后都调用。我在下面的示例中包含了一个示例,它在从输入触发blur事件后更新了Students hanya selepas mengemas kini input. Untuk pendekatan yang lebih bijak (dan lebih kompleks), anda boleh membandingkan prop dan keadaan untuk memutuskan sama ada kemas kini diperlukan, tetapi saya akan membenarkan anda memikirkannya sendiri.

    const { Fragment, StrictMode, useCallback, useEffect, useState } = React;
    const { createRoot } = ReactDOM;
    const { TextField } = MaterialUI;
    
    function Student(props) {
      const [firstName, setFirstName] = useState(props.firstName);
      const [lastName, setLastName] = useState(props.lastName);
      const [grade, setGrade] = useState(props.grade);
      const handleStudentsChange = props.handleStudentsChange;
      
      const onBlur = () => {
        handleStudentsChange(props.id, {
          firstName,
          lastName,
          grade,
        });
      };
    
      return (
        <Fragment>
          <TextField
            label="firstName"
            onBlur={onBlur}
            onChange={(event) => setFirstName(event.target.value)}
            value={firstName}
          />
          <TextField
            label="lastName"
            onBlur={onBlur}
            onChange={(event) => setLastName(event.target.value)}
            value={lastName}
          />
          <TextField
            label="grade"
            onBlur={onBlur}
            onChange={(event) => setGrade(+event.target.value)}
            value={grade}
          />
        </Fragment>
      );
    }
    
    function Students() {
      const [students, setStudents] = useState([
        { firstName: "Justin", lastName: "Bieber", grade: 100 },
        { firstName: "Robert", lastName: "Oppenhiemer", grade: 100 }
      ]);
    
      const handleStudentsChange = useCallback(
        (index, updatedStudent) => {
          // console.log(index) // I only want this to rerender when the value change however it turn into an infinity loop
          
          console.log({ updatedStudent });
    
          setStudents((prevStudents) => {
            const updatedStudents = [...prevStudents];
            updatedStudents[index] = updatedStudent;
            return updatedStudents;
          });
        },
        []
      );
    
      return (
        <Fragment>
          {students.map((student, index) => {
            return (
              <Student
                key={index}
                id={index}
                firstName={student.firstName}
                lastName={student.lastName}
                grade={student.grade}
                handleStudentsChange={(index, newStudent) =>
                  handleStudentsChange(index, newStudent)
                }
              />
            );
          })}
        </Fragment>
      );
    }
    
    function App() {
      return (
        <div className="App">
          <Students />
        </div>
      );
    }
    
    const root = createRoot(document.getElementById("root"));
    root.render(<StrictMode><App /></StrictMode>);
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script crossorigin src="https://unpkg.com/@mui/material@latest/umd/material-ui.production.min.js"></script>
    <div id="root"></div>

    balas
    0
  • Batalbalas