gpt4 book ai didi

javascript - React 组件 props 在应该改变的时候没有改变?

转载 作者:行者123 更新时间:2023-12-05 05:46:21 25 4
gpt4 key购买 nike

我正在从事的一个项目涉及一个大型组件树,向下传递来自顶部组件中一个大型复杂状态对象的 Prop 。

在一个特定的组件“ChecklistEditor”中,我将“subchecklists” Prop 映射到“Subchecklist”组件中,每个组件都有各自的 Prop 。我发现的问题是,当我更新子 list 的状态(在父组件中)时,它会导致 ChecklistEditor 的 Prop (子 list )发生变化(正如我从 devtools 中看到的那样),但即使这些 Prop 被传递给子 list 组件map 函数,Subchecklist 组件的属性不会改变,也不会使用更新后的数据重新渲染。

ChecklistEditor.js

import { useState, useCallback } from "react";

import ChecklistTitle from "../ChecklistTitle/ChecklistTitle";
import Subchecklist from "../Subchecklist/Subchecklist";
import NewSubchecklistForm from "../NewSubchecklistForm/NewSubchecklistForm";
import BlankSpace from "../BlankSpace/BlankSpace";
import Button from "../../UI/Button";
import classes from "./ChecklistEditor.module.css";
import useMemoizedCallback from "../../../hooks/useMemoizedCallback";
import SectionTitle from "../SectionTitle/SectionTitle";

const ChecklistEditor = (props) => {
const [dragItemIndex, setDragItemIndex] = useState(-1);
const [draggedOverItemIndex, setDraggedOverItemIndex] = useState(-1);

// Called when the subchecklist is dragged.
const handleDrag = useCallback(
(subchecklistIndex) => {
setDragItemIndex(subchecklistIndex);
},
[setDragItemIndex]
);

// Called when another subchecklist is dragged over this subchecklist.
const handleDragOver = useCallback(
(itemIndex) => {
setDraggedOverItemIndex(itemIndex);
},
[setDraggedOverItemIndex]
);

// Called when the dragend event fires for a subchecklist. (Memoized so that it doesnt cause tons of re-renders).
const handleDragEnd = useMemoizedCallback(() => {
props.onReorderSubchecklists(dragItemIndex, draggedOverItemIndex);
}, [props.onReorderSubchecklists, dragItemIndex, draggedOverItemIndex]);

// Resets the index of the subchecklist being dragged.
const resetDragItemIndex = useCallback(() => {
setDragItemIndex(-1);
}, [setDragItemIndex]);

// Map item data into Subchecklist elements
const subchecklists = props.subchecklists.map((item, index) => {
let returnItem;
if (item.type === "subchecklist") {
returnItem = (
<Subchecklist
key={item.id}
subchecklistIndex={index}
subchecklistId={item.id}
title={item.title}
color={item.color}
items={item.checkItems}
onDeleteSubchecklist={props.onDeleteSubchecklist}
onUpdateSubchecklistTitle={props.onUpdateSubchecklistTitle}
onChangeColor={props.onChangeSubchecklistColor}
onItemUpdate={props.onItemUpdate}
onDeleteItem={props.onDeleteItem}
onAddCheckItem={props.onAddCheckItem}
onAddCondition={props.onAddCondition}
onDrag={handleDrag}
onDragOver={handleDragOver}
onDragEnd={handleDragEnd}
onReorderCheckItems={props.onReorderCheckItems}
resetDragItemIndex={resetDragItemIndex}
/>
);
} else if (item.type === "blankSpace") {
returnItem = (
<BlankSpace
key={item.id}
id={item.id}
index={index}
height={item.height}
onUpdateHeight={props.onUpdateBlankSpace}
onDelete={props.onDeleteSubchecklist}
onDrag={handleDrag}
onDragOver={handleDragOver}
onDragEnd={handleDragEnd}
onReorderCheckItems={props.onReorderCheckItems}
resetDragItemIndex={resetDragItemIndex}
/>
);
} else if (item.type === "sectionTitle") {
returnItem = (
<SectionTitle
key={item.id}
id={item.id}
index={index}
title={item.title}
color={item.color}
onUpdateTitle={props.onUpdateSectionTitle}
onChangeColor={props.onChangeSubchecklistColor}
onDelete={props.onDeleteSubchecklist}
onDrag={handleDrag}
onDragOver={handleDragOver}
onDragEnd={handleDragEnd}
onReorderCheckItems={props.onReorderCheckItems}
resetDragItemIndex={resetDragItemIndex}
/>
);
}
return returnItem;
});

return (
<div className={classes.container}>
<div className={classes.editor}>
<ChecklistTitle
title={props.name}
onTitleChange={props.onTitleChange}
/>
<Button type="submit" onClick={props.onSave}>
Save
</Button>
<div className={classes.subchecklistContainer}>{subchecklists}</div>
<NewSubchecklistForm onSubmit={props.onAddSubchecklist} />
<Button type="submit" onClick={props.onAddBlankSpace}>
Add Blank Space
</Button>
<Button type="submit" onClick={props.onAddSectionTitle}>
Add Section Title
</Button>
</div>
</div>
);
};

export default ChecklistEditor;

我发现的一些奇怪的事情是,如果我对子检查列表状态进行更改,然后对我的代码进行小的更改并保存,nodemon 将重新加载应用程序并且值将更新为它们应该的值。

我真的被困在这上面,不知道发生了什么,所以我会很感激我能得到的任何帮助。谢谢。

编辑: 我应该提一下,如果我从传递给 Subchecklist 组件的任何函数中删除 useCallback Hook ,它会强制组件重新加载并且信息会正确更新,但是这对于重新渲染变得太昂贵了。这似乎也是错误的,因为函数更改是导致重新加载的原因,而数据属性本身应该导致它...

最佳答案

好的,所以我找到了问题。它与复制嵌套状态对象时扩展运算符的工作方式有关。

简而言之;如果您状态中的嵌套对象用作子组件的 Prop ,则仅对整个对象使用展开运算符不足以复制嵌套属性。这是因为展开运算符创建了一个浅拷贝(一层),嵌套对象仍将引用与以前相同的对象,并且您的 props 不会更新以触发重新渲染。

因此,如果我的状态对象如下所示,如果我将内容数组映射到多个子组件并希望它们的更改显示在 props 中并触发组件的重新渲染,我将不得不制作一个副本要修改的内容数组,然后用新值替换旧数组。

const [myObj, setMyObj] = useState({
name: "MyName",
id: 1,
contents: [
{
id: 2,
name: "Nested Name"
}
]
});

错误

let newMyObj = {...myObj};
newMyObj.contents[0].name = "Updated Name";
setMyObj(newMyObj);

let newContents = [...myObj.contents];
newContents[0].name = "Updated Name";
let newMyObj = {...myObj};
newMyObj.contents = newContents;
setMyObj(newMyObj);

关于javascript - React 组件 props 在应该改变的时候没有改变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71210972/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com