子组件无法通过父组件中的状态更新正确更新

时间:2020-05-31 04:22:06

标签: javascript reactjs react-state

仅我有一个列表项,其中包含一个名称列表,单击任何列表项都会更改该项目的颜色,这是我的逻辑:

const App = () => {

    const items = [
        {
            name: 'peter',
            id: 1
        },
        {
            name: 'Mark',
            id: 2
        },
        {
            name: 'john',
            id: 3
        }
    ]

    const [id, setId] = useState(null);
    const [names, setNames] = useState(items)

    const setClickedItemId = (id) => {
        setId(id)
    }

    const turnItemRed = () => {
        setNames(prev =>  prev.map(i => i.id === id ? {...i, color: 'red' } : i))

    }


    return (
        <div className="app">
            <ul className="items">
                {
                    names.map(i => {
                        return (
                            <Item 
                               item={i}
                                setClickedItemId={setClickedItemId}
                                turnItemRed={turnItemRed}
                            />
                        )
                    })
                }
            </ul>
        </div>
    )
}

function Item({item, ...props}) {
    const { name, id} = item;
    const { setClickedItemId, turnItemRed } = props;
    return (
        <li
            className={`${item.color === 'red' ? 'red' : ''}`}
            onClick={() => {
                setClickedItemId(id);
                turnItemRed()

            }}
        >{name}</li>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

这将显示项目列表,我需要单击两次以使项目变成红色,这意味着子组件不会捕获最新的状态,但是

只需在父组件的return语句之前添加该行代码,

const showingItems = names.map(i => i.id === id ? {...i, color: 'red'} : i)

然后使用该变量showingItems而不是状态变量names来呈现列表,使它正确而且不知道为什么

所以,为什么子组件Items在将状态存储到变量中时却没有获得状态的最新版本?

2 个答案:

答案 0 :(得分:1)

批处理状态更新,并且您的onClick会触发2个执行状态更新的功能。由于异步行为,第二个函数没有收到更新的值。

只需将id传递给turnItemRed函数,而不要从状态中获取它。

应用

    const turnItemRed = (id) => { //<----take the id
        setNames(prev =>  prev.map(i => i.id === id ? {...i, color: 'red' } : i))

    }

项目

function Item({item, ...props}) {
    const { name, id} = item;
    const { setClickedItemId, turnItemRed } = props;
    return (
        <li
            className={`${item.color === 'red' ? 'red' : ''}`}
            onClick={() => {
                setClickedItemId(id);
                turnItemRed(id) //<---- pass the id

            }}
        >{name}</li>
    )
}

修改 上述问题的快速演示和解决方法是here in the demo.。只需添加它,这样将来可能会对其他读者有所帮助。

答案 1 :(得分:1)

import React,{useState} from 'react';
export default  () => {

    const items = [
        {
            name: 'peter',
            id: 1
        },
        {
            name: 'Mark',
            id: 2
        },
        {
            name: 'john',
            id: 3
        }
    ]

    const [id, setId] = useState(null);
    const [names, setNames] = useState(items)

    const setClickedItemId = (id) => {
        setId(id);
        turnItemRed(id);
    }

    const turnItemRed = (id) => {
        setNames(prev => prev.map(i => i.id === id ? { ...i, color: 'red' } : i))
    }
    return (
        <div className="app">
            <ul className="items">
                {
                    names.map(i => {
                        return (
                            <Item
                                item={i}
                                setClickedItemId={setClickedItemId}
                                turnItemRed={turnItemRed}
                            />
                        )
                    })
                }
            </ul>
        </div>
    )
}

function Item({ item, ...props }) {
    const { name, id } = item;
    const { setClickedItemId, turnItemRed } = props;
    return (
        <li
            style={{ color: item.color === 'red' ? 'red' : ''}}
            onClick={() => {
                setClickedItemId(id);
            }}
        >{name}</li>
    )
}