英文:
React State reverting to default value
问题
I am trying to update a Component from inside a nested component. But each time the state in the parent component gets reset to its initial value.
这里我试图从嵌套组件内部更新一个组件。但是每次父组件中的状态都会重置为其初始值。
The initial data:
初始数据:
Parent Component
父组件
Child Component
子组件
This code is using React DND but the main issue is the blocklist state.
这段代码使用了React DND,但主要问题是blocklist状态。
When I drag a card from blocks div it should update the blocklist state on the parent and remove it from the block list. Next update should filter through the updated state but the blocklist always reverts back to the initial value when this line runs
当我从blocks div中拖动一张卡片时,它应该更新父组件上的blocklist状态,并从block列表中将其删除。但是每次运行这行代码时,下一次更新都会通过更新后的状态进行筛选,但是blocklist总是恢复到初始值。
Not sure why the state is being reset.
不确定为什么状态会被重置。
Thanks in advance. Any help is appreciated.
提前感谢。任何帮助都会受到赞赏。
英文:
I am trying to update a Component from inside a nested component. But each time the state in the parent component gets reset to it's initial value.
Here is a simplified version of what I am trying to do:
The initial data:
{
id: 1,
size: "large",
name: "Antman",
url: "https://images-na.ssl-images-amazon.com/images/I/91lviq1Lx6L._AC_UL320_SR320,320_.jpg"
},
{
id: 2,
size: "large",
name: "Avatar",
url: "https://images-na.ssl-images-amazon.com/images/I/91XXks9tlfL._AC_UL320_SR320,320_.jpg"
},
{
id: 3,
size: "large",
name: "Shazam",
url: "https://images-na.ssl-images-amazon.com/images/I/91mXAXL+jBL._AC_UL320_SR320,320_.jpg"
},
{
id: 4,
size: "large",
name: "Test",
url: "https://images-na.ssl-images-amazon.com/images/I/91mXAXL+jBL._AC_UL320_SR320,320_.jpg"
}
];
Parent Component
function DragDrop() {
const [blockList, setBlocklist] = useState(initblockList);
const updateBlockList = (block, id) => {
const update = blockList.filter(block => block.id !== id); //block list reverts to initState
setBlocklist((update) => [...update]); //remove block from blocklist state
}
return (
<>
<AboveBoard
blockList={blockList}
setAbove={setAboveBoard}
updateBlockList={updateBlockList}
/>
<div className="blocks">
{blockList.map((img, i) => {
return <Block key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
</>
)
}
export default DragDrop
Child Component
function AboveBoard({ blockList, setAbove, updateBlockList }) {
const [board, setBoard] = useState([]);
const [{ isOver }, drop] = useDrop(() => ({
accept: "block",
drop: (item) => addBlockToBoard(item.id),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
})
}))
const addBlockToBoard = (id) => {
const currentBlock = blockList.filter(block => block.id === id);
setBoard((board) => [...board, currentBlock[0]]); //add new block to board
updateBlockList(currentBlock, id); //update parent board
}
return (
<div className="aboveboard" ref={drop}>
{board.map((img, i) => {
return <UnBlock key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
)
}
export default AboveBoard
This code is using React DND but the main issue is the blocklist state.
When I drag a card from blocks div it should update the blocklist state on the parent and remove it from the block list. Next update should filter through the updated state but the blocklist always reverts back to initial value when this line runs
const update = blockList.filter(block => block.id !== id);
Not sure why the state is being reset.
Thanks in advance. Any help is appreciated.
答案1
得分: 3
以下是您要翻译的内容:
"因为在 setBlocklist
状态设置器中,您正在使用 setter 形式,您正在将旧状态的名称与新的(过滤后的)列表作为更新值使用相同的名称。
编辑:在查看您的代码和注释时,我注意到您试图将变量 currentBlock
传递给 updateBlockList
状态设置器。问题是,它默认返回为数组,并且因此会作为数组传递下去,因此状态永远不会更新,因为 updateBlockList
的 filter
方法内部的 block
变量上不存在 .id
属性。
解决方法是在 addBlockToBoard
方法中使用 .find
方法,或者访问第一个索引,即 currentBlock[0]
。
编辑:在查看代码沙盒后,问题是旧状态值陈旧(陈旧的闭包),因此每次发生更改时状态都会重置。在这种情况下,我们只能使用 setState(prevState => ...);
的 setter 形式。关于陈旧闭包问题的推荐阅读。
以下是更新后的代码:
父组件:
function DragDrop() {
const [blockList, setBlocklist] = useState(initblockList);
const updateBlockList = (currentBlock, id) => {
setBlocklist((prevState) => prevState.filter(block => block.id !== currentBlock.id));
}
return (
<>
<AboveBoard
blockList={blockList}
setAbove={setAboveBoard}
updateBlockList={updateBlockList}
/>
<div className="blocks">
{blockList.map((img, i) => {
return <Block key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
</>
)
}
export default DragDrop
子组件:
function AboveBoard({ blockList, setAbove, updateBlockList }) {
const [board, setBoard] = useState([]);
const [{ isOver }, drop] = useDrop(() => ({
accept: "block",
drop: (item) => addBlockToBoard(item.id),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
})
}))
const addBlockToBoard = (id) => {
const currentBlock = blockList.find(block => block.id === id);
// OR
// const currentBlock = blockList.filter(block => block.id === id)[0];
setBoard((board) => [...board, currentBlock]); //add new block to board
updateBlockList(currentBlock); //update parent board
}
return (
<div className="aboveboard" ref={drop}>
{board.map((img, i) => {
return <UnBlock key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
)
}
英文:
Well, because in the setBlocklist
state setter where you're using the setter form, you're using the same name for the old state as well as the new(filtered) list as an update value.
Edit: Looking through your code & comments, I noticed that you're trying to pass the variable currentBlock
to the updateBlockList
state setter. Problem is, it's returned from the filter method as an array by default & so, it will be passed down as an array, thus the state will never be updated because the .id
property doesn't exist on the block
variable inside the filter method of the updateBlockList
.
Solution would be using the .find
method in the addBlockToBoard
method or accessing the first index, i.e., currentBlock[0]
.
Edit: After taking a look at the code sandbox, the issue was the old state value being stale(stale closures), thus, the state was reset each time a change happened. In this case, we can only use the setter form of setState(prevState => ...);
. Recommended reading about stale closures issue.
Here is the updated code:
The parent component:
function DragDrop() {
const [blockList, setBlocklist] = useState(initblockList);
const updateBlockList = (currentBlock, id) => {
setBlocklist((prevState) => prevState.filter(block => block.id !== currentBlock.id));
}
return (
<>
<AboveBoard
blockList={blockList}
setAbove={setAboveBoard}
updateBlockList={updateBlockList}
/>
<div className="blocks">
{blockList.map((img, i) => {
return <Block key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
</>
)
}
export default DragDrop
The child component:
function AboveBoard({ blockList, setAbove, updateBlockList }) {
const [board, setBoard] = useState([]);
const [{ isOver }, drop] = useDrop(() => ({
accept: "block",
drop: (item) => addBlockToBoard(item.id),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
})
}))
const addBlockToBoard = (id) => {
const currentBlock = blockList.find(block => block.id === id);
// OR
// const currentBlock = blockList.filter(block => block.id === id)[0];
setBoard((board) => [...board, currentBlock]); //add new block to board
updateBlockList(currentBlock); //update parent board
}
return (
<div className="aboveboard" ref={drop}>
{board.map((img, i) => {
return <UnBlock key={`key-${i}`} id={img.id} url={img.url} />
})}
</div>
)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论