英文:
Why are a functional component's child component's props using outdated state?
问题
以下是您要翻译的内容:
Parent.js
import { useState, useEffect } from 'react';
import Rooms from './Rooms';
export default function TourOverview(props) {
const [roomList, setRoomList] = useState([]);
useEffect(() => { // add one room as default that cant be removed
setRoomList([<Rooms addRoomCount={addRoomCount} id={1} key={1} />]);
}, []);
const addRoomCount = () => {
let tempArr = roomList; //浅拷贝
tempArr.push(<Rooms removeRoomCount={removeRoomCount} id={roomList.length + 1} key={roomList.length + 1} />);
setRoomList([...tempArr]);
}
const removeRoomCount = (id) => {
// 不相关部分保留为空
}
return (
<>
{roomList}
</>
)
Child.js
import { useState, useEffect } from 'react';
export default function Rooms(props, ref) {
return (
<>
房间 {props.id}
{props.addRoomCount !== undefined ? <button type="button" className="btn btn-link" onClick={props.addRoomCount}>
+ 添加房间
</button> :
<button type="button" className="btn btn-link" onClick={() => props.removeRoomCount(props.id)}>
- 移除
</button>
}
</>
)
请注意,翻译中将 HTML 实体(例如 <
和 >
)转换为相应的角括号符号(<
和 >
),并将 "
转换为双引号("
)。
英文:
I am actually using Next JS but its the same. i have simplified the code and removed the irrelevant part.
What i am building is a form where i can add new fields (child component) dynamically but the default will be 1 and there must always be minimum 1 field.
Parent.js
import {useState, useEffect} from 'react'
import Rooms from './Rooms'
export default function TourOverview(props) {
const [roomList, setRoomList] = useState([])
useEffect(()=>{ // add one room as default that cant be removed
setRoomList([<Rooms addRoomCount={addRoomCount} id={1} key={1} />])
}, [])
const addRoomCount=()=> {
let tempArr = roomList //shallow copy
tempArr.push(<Rooms removeRoomCount={removeRoomCount} id={roomList.length+1} key={roomList.length+1} />)
setRoomList([...tempArr])
}
const removeRoomCount=(id)=>{
// will leave empty as not relevant
}
return (
<>
{roomList}
</>
)
Child.js
import {useState, useEffect} from 'react'
export default function Rooms(props, ref) {
return (
<>
Room {props.id}
{props.addRoomCount != undefined ? <button type="button" className="btn btn-link" onClick={props.addRoomCount}>
+ Add Room
</button> :
<button type="button" className="btn btn-link" onClick={()=>props.removeRoomCount(props.id)}>
- Remove
</button>
}
</>
)
From the code you can see that as the parent component loads for the first time it will automatically add a child component that has the "add room" button, the others added later will have only "remove" button.
This doesnt work, it looks ok initially, but the moment you click on "add room" button, the roomList state gets reset to the state when the one time useEffect was initially loaded, which is...empty.
In another words, the addRoomCount() assigned as a prop to the first <Rooms/>, is using the state roomList during the initial load when its still empty, its like a time machine.
I tried the class component version of this and it works. So its only functional component wont work.
Anyone can explain why?
答案1
得分: 2
不要在状态中存储JSX。相反,使用状态来创建要渲染的元素。
在这种情况下,只需将id数组存储为状态。
const [roomList, setRoomList] = useState([1]);
const addRoomCount = () => setRoomList([...roomList, roomList.length + 1]);
// ...
return roomList.map(i => <Room addRoomCount={addRoomCount} id={i} key={i}
removeRoomCount={i ? removeRoomCount : undefined} />);
英文:
Don't store JSX in state. Instead, use the state to create the elements to render.
In this case, it suffices to store the array of ids as state.
const [roomList, setRoomList] = useState([1]);
const addRoomCount = () => setRoomList([...roomList, roomList.length + 1]);
// ...
return roomList.map(i => <Room addRoomCount={addRoomCount} id={i} key={i}
removeRoomCount={i ? removeRoomCount : undefined} />);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论