Is it intended behavior that array context is converted to an object after "assign"? #5411
-
|
Hi!👋 I noticed that when I use an Array as the context in XState v5, it gets converted into an Object after an assign action is executed. I understand that assign performs a shallow merge, but this behavior makes it impossible to use Array methods (like .map or .filter) on the context after an update, which seems like a potential pitfall for users. Here is a minimal reproduction code: import { setup, assign, createActor } from "xstate";
const arrayMachine = setup({
types: {
context: [] as string[],
events: {} as { type: "ADD"; item: string },
},
}).createMachine({
context: [],
initial: "active",
states: {
active: {
on: {
ADD: {
actions: assign(({ context, event }) => {
// Returning a new Array
return [...context, event.item];
}),
},
},
},
},
});
const actor = createActor(arrayMachine);
actor.start();
console.log("Initial:", Array.isArray(actor.getSnapshot().context)); // true
actor.send({ type: "ADD", item: "test" });
const nextContext = actor.getSnapshot().context;
console.log("After assign:", nextContext); // { '0': 'test' }
console.log("Is Array?", Array.isArray(nextContext)); // false I looked into the source code and found that Object.assign({}, ...) is used in resolveAssign, which seems to be the cause. const updatedContext = Object.assign({}, snapshot.context, partialUpdate);Question
I couldn't find a clear mention of this in the documentation, so I would appreciate your clarification. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
|
Yes, it is expected that context is always an object, so the second option is the preferable one. I'll update the docs to reflect this. |
Beta Was this translation helpful? Give feedback.
Yes, it is expected that context is always an object, so the second option is the preferable one. I'll update the docs to reflect this.