Дочерний компонент не обновляется правильно с обновлением состояния в родительском компоненте

Просто у меня есть элемент списка, содержащий список имен, щелчок по любому элементу списка меняет цвет этого элемента, это моя логика:

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 не получают самую последнюю версию состояния, в то время как сохранение состояния в переменной заставляет его работать ??


person Code Eagle    schedule 31.05.2020    source источник
comment
В turnItemRed вы передаете prev => ... в setNames, у вас нигде не определено prev, плюс вы передаете функцию setNames, которая изменит ее с того, что было раньше (items), на то, что теперь names равно этой функции. Вы можете изменить эту строку на setNames(names.map(i => i.id === id ? {...i, color: 'red' } : i)), и она должна работать правильно.   -  person Rodentman87    schedule 31.05.2020
comment
спасибо за попытку помочь, но это не устранило проблему, я думаю, что предыдущая версия эквивалентна использованию здесь имен   -  person Code Eagle    schedule 31.05.2020


Ответы (2)


Обновления состояния группируются, и ваш onClick запускает 2 функции, которые выполняют обновления состояния. Вторая функция не получает обновленное значение из-за асинхронного поведения.

Просто передайте идентификатор функции 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>
    )
}

Изменить. Быстрая демонстрация вышеуказанной проблемы и исправления: здесь, в демонстрации.. Просто добавляю это, чтобы в будущем это могло помочь другим читателям.

person gdh    schedule 31.05.2020

person    schedule
comment
когда значение установлено в состояние, мы не можем получить значение изменения состояния в следующей строке. в классе реакции есть возможность получить его на следующей строке, используя функцию обратного вызова состояния thi.setState (value_to_set, callback_function) - person Abhijith v; 31.05.2020