在學生(兒童)組件中
useEffect
掛鉤將透過 handleStudentsChange
(父元件提供的函數)更新父數組。 在學生(家長)組件中
handleStudentsChange
函數使用 useCallback
掛鉤定義。然而,它似乎不起作用。 問題/疑問
handleStudentsChange
就會無限運行請參閱此處的程式碼: 我是 CodeSandBox 連結
Student.tsx(兒童)
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} /> </> );
Students.tsx(父級)
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) } /> ); })} </> ); }
如上面的程式碼所示,我嘗試在學生(兒童)元件上使用React.memo
,並在handleStudentsChange
上使用useCallback
,希望能夠防止無限循環。然而,無限循環仍在持續。
P粉9550636622024-02-27 00:32:58
handleStudentsChange
不僅在發生更改時無限運行一次-它從第一次渲染開始就無限運行。這是因為Student
元件具有呼叫handleStudentsChange
的useEffect
,它更新了Students
元件中的狀態,導致Student
元件重新渲染,然後再次呼叫useEffect
,無限循環。
您需要在更新輸入後才呼叫handleStudentsChange
,而不是每次渲染後都會呼叫。我在下面的範例中包含了一個範例,它在從輸入觸發blur
事件後更新了Students
中的狀態。對於更聰明(和複雜)的方法,您可以對比props和state來決定是否需要更新,但我將讓您自己解決。
const { Fragment, StrictMode, useCallback, useEffect, useState } = React; const { createRoot } = ReactDOM; const { TextField } = MaterialUI; 函數學生(道具){ 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)} 值={等級} >> </片段> ); } 函數學生() { const [學生,setStudents] = useState([ { 名字:“賈斯汀”,姓氏:“比伯”,成績:100 }, { 名字:“羅伯特”,姓氏:“奧本希默”,成績:100 } ]); const handleStudentsChange = useCallback( (索引,更新學生)=> { // console.log(index) // 我只希望它在值更改時重新渲染,但它會變成無限循環 console.log({ updateStudent }); setStudents((prevStudents) => { const UpdatedStudents = [...prevStudents]; 更新的學生[索引] = 更新的學生; 返回更新的學生; }); }, [] ); 返回 ( <片段> {students.map((學生, 索引) => { 返回 ( <學生 鍵={索引} id={索引} 名字={學生.名字} 姓氏={學生.姓氏} 年級={學生.年級} handleStudentsChange={(index, newStudent) =>; 處理StudentsChange(索引,newStudent) } >> ); })} </片段> ); } 函數應用程式(){ 返回 (<學生>>); } const root = createRoot(document.getElementById("root")); root.render();
<腳本跨域 src="https://unpkg.com/react@18/umd/react.development.js"></script> <腳本跨域 src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <腳本跨域 src="https://unpkg.com/@mui/material@latest/umd/material-ui.production.min.js"></script>