React状态恢复为默认值

huangapple go评论53阅读模式
英文:

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 状态设置器。问题是,它默认返回为数组,并且因此会作为数组传递下去,因此状态永远不会更新,因为 updateBlockListfilter 方法内部的 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>
    )
}

huangapple
  • 本文由 发表于 2023年5月25日 23:43:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76334106.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定