【发布时间】:2020-04-23 15:29:25
【问题描述】:
我已经在 SPA 上工作了一段时间,并使用自定义上下文 API 管理我的全局状态,但它一直在导致树下不受欢迎的重新渲染让人头疼,所以我想我应该试试 react-easy-state .到目前为止,一切都很好,但我开始遇到一些我认为与全局状态的可变性有关的问题,这很容易通过使用 immer 之类的库的自定义上下文 api 实现来解决。
这是我遇到的问题的简化版本:我有一个用于管理订单的全局状态。订单对象primaryOrder 有一个插件数组,其中添加了额外的项目 - 可用插件的列表存储在一个单独的存储中,该存储负责从我的 API 获取列表。 orderStore 看起来像这样:
const orderStore = store({
initialized: false,
isVisible: false,
primaryOrder: {
addons: [],
}
})
当用户选择增加一个插件项目的数量时,如果它不存在,它会被添加到插件数组中,如果它是插件的qty 属性则增加。当数量减少时,同样的逻辑适用,除非它达到 0,然后从数组中删除插件。这是在 orderStore 上使用以下方法完成的:
const orderStore = store({
initialized: false,
isVisible: false,
primaryOrder: {
addons: [],
},
get orderAddons() {
return orderStore.primaryOrder.addons;
},
increaseAddonItemQty(item) {
let index = orderStore.primaryOrder.addons.findIndex(
(i) => i.id === item.id
);
if (index === -1) {
let updatedItem = {
...item,
qty: 1,
};
orderStore.primaryOrder.addons = [
...orderStore.primaryOrder.addons,
updatedItem,
];
} else {
orderStore.primaryOrder.addons[index].qty += 1;
}
console.log(orderStore.primaryOrder.addons);
},
decreaseAddonItemQty(item) {
let index = orderStore.primaryOrder.addons.findIndex(
(i) => i.id === item.id
);
if (index === -1) {
return;
} else {
// remove the item from the array if value goes 1->0
if (orderStore.primaryOrder.addons[index].qty === 1) {
console.log("removing item from array");
orderStore.primaryOrder.addons = _remove(
orderStore.primaryOrder.addons,
(i) => i.id !== item.id
);
console.log(orderStore.primaryOrder.addons);
return;
}
orderStore.primaryOrder.addons[index].qty -= 1;
}
}
})
我遇到的问题与我的一个视图使用orderStore.addons 的事实有关。在这种情况下,我的 Product 组件是消费者:
const Product = (item) => {
const [qty, setQty] = useState(0);
const { id, label, thumbnailUrl, unitCost } = item;
autoEffect(() => {
if (orderStore.orderAddons.length === 0) {
setQty(0);
return;
}
console.log({ addons: orderStore.orderAddons });
let index = orderStore.orderAddons.findIndex((addon) => addon.id === id);
console.log({ index });
if (index !== -1) setQty(orderStore.findAddon(index).qty);
});
const Adder = () => {
return (
<div
className="flex"
style={{ flexDirection: "row", justifyContent: "space-between" }}
>
<div onClick={() => orderStore.decreaseAddonItemQty(item)}>-</div>
<div>{qty}</div>
<div onClick={() => orderStore.increaseAddonItemQty(item)}>+</div>
</div>
);
}
return (
<div>
<div>{label} {unitCost}</div>
<Adder />
</div>
)
}
export default view(Product)
当我调用 decreaseAddonItemQty 并且该项目从 addons 数组中删除时,会出现此问题。在Product 组件中抛出错误,指出Uncaught TypeError: Cannot read property 'id' of undefined 由于数组长度读取为2,尽管该项目已被删除(见下图)
我的假设是消费者Product 在完成更新之前正在读取全局存储,当然我可能是错的。
使用 react-easy-state 来避免这个问题的正确方法是什么?
【问题讨论】:
标签: reactjs react-state-management react-easy-state