Я хочу добиться эффекта при изменении PRODUCTS
(во время нажатия кнопки), список также меняется с изменением первой категории на «ха-ха».
Вся цель состоит в том, чтобы позволить компоненту перерисовываться во время изменения реквизита. Но похоже, что это не работает. Ниже приведен код.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const FilterableProductTable = (props) =>{
return (
<ul>
{props.products.map((product) =>
(<li>{product.category}</li>)
)}
</ul>
);
}
const PRODUCTS = [
{ category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football' },
{ category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball' },
{ category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball' },
{ category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch' },
{ category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5' },
{ category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7' }
];
const Home = () => {
const [productData, changeProduct] = useState(PRODUCTS);
const handleClick = () => {
PRODUCTS[0].category = 'haha';
changeProduct(PRODUCTS);
console.info(PRODUCTS);
};
return (
<>
<button onClick = {handleClick}>haha</button>
<FilterableProductTable products = {productData} />
</>
);
};
export default Home;
Вы можете попробовать это здесь:
Как разрешить FilterableProductTable
ререндеринг во время смены реквизита?
Когда вы устанавливаете состояние в функциональном компоненте, реакция выполняет ===
между старым и новым состоянием. Если они совпадают, то реакция пропускает рендеринг. Поскольку вы изменяете состояние, это один и тот же массив до и после, а рендеринг пропускается.
Исправление состоит в том, чтобы сохранить ваше состояние неизменным. Не изменяйте старый массив, а вместо этого создайте новый:
const handleClick = () => {
changeProducts(prev => {
const next = [...prev];
next[0] = {
...next[0],
category: 'haha';
}
return next;
});
}
при изменении свойства в массиве реакция не видит его как изменение, вы можете использовать оператор распространения для клонирования вашего массива и установки нового массива:
changeProduct([...PRODUCTS])
useState вызовет повторный рендеринг, только если его текущее значение отличается от текущего состояния. Это сделает Object.is
или ===
сравнение. Здесь вы устанавливаете ту же ссылку PRODUCTS
, что и в defaultState, и значение, переданное в changeProduct
, также имеет ту же ссылку, что и PRODUCTS
, что не вызовет повторного рендеринга.
Цитата из React ДОКУМЕНТЫ
If your update function returns the exact same value as the current state, the subsequent rerender will be skipped completely.
const handleClick = () => {
const res = productData.map((prod,index) => index === 0 ? {...prod,category:"haha"} : prod)
changeProduct(res);
console.info(res);
};
map
каждый раз будет создавать новый массив.