Сейчас я пытаюсь сделать таблицу с флажками и столкнулся с очень раздражающей проблемой. Я воспроизвел эту проблему в этом примере.
У меня есть список элементов формата {id, value}. Для каждого элемента я создаю элемент div с флажком и текстом внутри. Когда я хочу сделать элемент выбранным, я добавляю идентификатор элемента в список selectedItems.
Проблема в том, что я не могу заставить флажок компонента обновлять свое состояние при изменении списка selectedItems.
Подскажите пожалуйста, как это сделать нормально? В Vue я мог просто создать вычисляемое свойство для каждого подкомпонента и передать selectedItems и связанную поддержку. Как это сделать в Реакте?
import {Checkbox} from "@mui/material";
import {useMemo, useState} from "react";
export default function Example() {
const items = useState([{id: 0, value: "Item 1"}, {id: 1, value: "Item 2"}, {id: 2, value: "Item 3"}])
const [selectedItems, setSelectedItems] = useState([])
console.info(items)
function ListItems({items}) {
return useMemo(() => {
const elements = []
for (let i = 0; i < items[0].length; i++) {
const item = items[0][i]
const checked = selectedItems.indexOf(item.id) !== -1
console.info(item, items.length)
elements.push(
<div key = {i}>
<Checkbox
checked = {checked}
onChange = {() => {
let state = selectedItems
if (checked) {
state = state.filter(id => id !== item.id)
} else {
state.push(item.id)
}
setSelectedItems(state)
}}
/>
<p>{item.value}</p>
</div>
)
}
return elements
}, [items])
}
return (
<div style = {{display: "flex", flexDirection: "column"}}>
<ListItems items = {items}/>
</div>
)
}
Codesandbox: https://codesandbox.io/s/not-working-computed-props-react-forked-fywtxp?file=/src/App.js
Ваш useMemo зависит от items, но не от selectedItems, поэтому он не переоценивается, вы должны сделать useMemo(..., [items, selectedItems]), чтобы при изменении одного из items или selectedItems он переоценивал
Да, ты прав. Я действительно пропустил это на этот раз. Но должен сказать, что раньше у меня вообще не было useMemo, и это не влияло... Сейчас исправил, все равно не работает...



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Помимо моего комментария о selectedItems, который должен быть предоставлен в useMemo зависимостях, у вас есть другая проблема, которая заключается в том, что вы действительно не изменяете свое состояние здесь setSelectedItems(state)
Массивы сравниваются по ссылке, поэтому если у вас есть const x = y = []; и тогда x.push('1'), x по-прежнему равно y. Следовательно, когда вы делаете
let state = selectedItems
...
state.push(...)
...
setSelectedItems(state)
Это не вызывает повторный рендеринг, потому что state все еще равен предыдущему (до selectedItems)
Исправление может быть либо
state = [...state, item.id] вместо push
Или setSelectedItems([...state])
Вы можете загрузить этот код куда-нибудь, чтобы мы могли проверить, что с ним не так 🙏