更新对象的redux数组,但不重新渲染组件



问题说明

我正在尝试修改存储在redux存储中的一组对象。从组件更新后,不会重新渲染组件
基本上,我采用redux状态,它是使用mapStateToProps的对象数组。然后,从react组件更新此数组中的对象。我预计当数组被操纵时,组件将使用更新的数组重新渲染。但是,不幸的是,当我更新这个数组的对象时,我的组件无法检测到更改。

冗余状态

const initialState = {
basket: [
{id: 1, name: "", quantity: 1},
{id: 2, name: "", quantity: 1},
{id: 3, name: "", quantity: 1},
],
};
// My Reducers
const foodReducer = (state = initialState, action) => {
.....................
.....................
.....................
}

反应组分

这里,increaseItem函数只是更新一个项目的数量
注意:当调用increaseItem函数时,redux dev tools显示更改。

function Ordered({ basket }) {
// INCREASE FOOD ITEM
const increaseItem = (id) => {
basket.map(food => {
if(food.id === id){
food.quantity++;
}
});
useEffect(() => {
console.log(basket);
}, [JSON.stringify(basket)]);

return (
{basket.length > 0 &&
basket.map((food) => (
<div className="ofood" key={food.id}>
<div className="no">{food.id}</div>
<div className="name">{food.name}</div>
<div className="quantity">
<div className="btn" onClick={() => increaseItem(food.id)}> + </div>
<div>{food.quantity}</div>
</div>
</div>
))}
);
}
const mapStateToProps = (state) => {
return { 
basket: state.food.basket,
};
};
export default connect(mapStateToProps, null)(Ordered);

如何解决此问题????

food.quantity++是Redux状态的突变。这将导致Redux中的值发生更改,但组件不会重新渲染,因为您更改了数据,而没有正确更新数据。

就React而言,basket没有改变,因为数组包含与以前相同的项。你突变了其中一个项目,使quantity不同,但React不知道这一点。这就是为什么必须在useEffect依赖项中使用JSON.stringify(basket)而不是basket


您也不能在reducer中调用food.quantity++,除非您使用的是像Redux Toolkit这样的辅助库。您更改的每个对象都必须替换为复制的版本。一个非突变的减缩器应该是这样的:

const foodReducer = (state = initialState, action) => {
switch (action.type) {
case "INCREASE_QUANTITY":
return {
...state,
basket: state.basket.map((food) => {
if (food.id === action.payload) {
return {
...food,
quantity: food.quantity + 1
};
} else return food;
})
};
}
};

使用Redux工具包,它要简单得多。

export const foodSlice = createSlice({
name: "food",
initialState,
reducers: {
increaseItem(state, action) {
state.basket.forEach((food) => {
if (food.id === action.payload) {
// it's ok to do this with Redux Toolkit
food.quantity++;
}
});
// don't return anything, just modify the draft state
}
}
});
export const {increaseItem} = foodSlice.actions;
export default foodSlice.reducer;
import { useEffect } from "react";
import { increaseItem } from "../store/slice";
import { connect } from "react-redux";
function Ordered({ basket, increaseItem }) {
useEffect(() => {
console.log(basket);
}, [JSON.stringify(basket)]);
return (
<div>
{basket.map((food) => (
<div className="ofood" key={food.id}>
<div className="no">{food.id}</div>
<div className="name">Food: {food.name}</div>
<div className="quantity">
<div className="btn" onClick={() => increaseItem(food.id)}>
+ Add One
</div>
<div>Current Quantity: {food.quantity}</div>
</div>
</div>
))}
</div>
);
}
const mapStateToProps = (state) => {
return {
basket: state.food.basket
};
};
export default connect(mapStateToProps, { increaseItem })(Ordered);

代码沙盒演示

最新更新