I just want to be sure. I have this store in solidjs:
type StoreState = {
selectionByCondition: Array<{
condition: BogoCondition;
cardState: Array<{
handle: string;
variant: string;
}>;
}>;
selectionByReward: Array<{
reward: BogoReward;
cardState: Array<{
handle: string;
variant: string;
checked: boolean;
}>;
}>;
};
I set it like this
setState(
"selectionByReward",
widgetData()?.discountData.rewards.map((reward) => {
console.log({ sortedConditions: sortedConditions() });
if (reward.condition === "SAME_SELECTION") {
if ("match" in reward) {
return {
cardState: state.selectionByCondition[0].cardState.map((v) => ({
...v,
checked: true,
})),
reward,
};
} else if (
"combination" in reward &&
reward.combination === "DIFFERENT_PRODUCTS"
) {
return {
cardState: getCondition(0)
.products.slice(0, reward.quantity)
.map((p) => ({
handle: p.handle,
variant: p.variants[0],
checked: true,
})),
reward,
};
} else {
return {
cardState: new Array(reward.quantity).fill({
handle: getCondition(0).products[0].handle,
variant: getCondition(0).products[0].variants[0],
checked: true,
}),
reward,
};
}
} else {
if (
"combination" in reward &&
reward.combination === "DIFFERENT_PRODUCTS"
) {
return {
cardState: reward.products.slice(0, reward.quantity).map((p) => ({
handle: p.handle,
variant: p.variants[0],
checked: true,
})),
reward,
};
} else {
return {
cardState: new Array(reward.quantity).map(() => ({
handle: reward.products[0].handle,
variant: reward.products[0].variants[0],
checked: true,
})),
reward,
};
}
}
}) || []
);
and I'm trying to update only one 'checked' property of cardState, but I don't know why it's mutating the 'checked' value of all 'checked' of the array, even if it's said in docs that produce should apply localized mutation... What I'm doing wrong ? I cannot mutate the complete array because I trigger fetch when cardState.handle change, and I don't want to trigger a refetch if checked change because it doesn't make sense.
setState(
"selectionByReward",
rewardIdx,
"cardState",
produce((cardState) => {
cardState[cardIndex].checked = !cardState[cardIndex].checked;
})
);
My mistake was the use of the .fill()
method to init the state, because it creates an array with references, so changing one item state was changing them all because it was the same reference.
Initiate the state in an other way, like this:
return {
reward,
cardStates: Array.from({ length: reward.quantity }, () => ({
variant: products[0].variants[0].toString(),
checked: true,
})),
handles: Array.from(
{ length: reward.quantity },
() => products[0].handle
),
};
did the trick