Action Logic Flow #4831
Replies: 3 comments 1 reply
-
PS: I would understand if the main logic body (e.g. finding the item, cloning, etc) could be done beforehand, but this would require read access to the context data of the actor, which seems not available on the actor object. |
Beta Was this translation helpful? Give feedback.
-
Keep in mind that the action you created does not do anything; So the code should be: editItem: {
actions: assign(({ context, event }) => {
const newItemData = event?.itemData;
const itemId = event?.id;
if (!itemId) return {}; // No changes
const itemFoundIndex = context.lists.findIndex(
(item) => item?.id === itemId
);
if (!itemFoundIndex) return {}; // No changes
const itemFound = structuredClone(context.lists?.[itemFoundIndex]);
const newItem = { ...itemFound, ...newItemData };
const newList = structuredClone(context.lists);
newList.splice(newItem, itemFoundIndex, 1);
return { lists: newList }; // <- would make sense to do it here
})
} Regarding your initial point of not assigning until you need to, you can use editItem: {
actions: enqueueActions(({ context, event, enqueue }) => {
const newItemData = event?.itemData;
const itemId = event?.id;
if (!itemId) return; // No changes
const itemFoundIndex = context.lists.findIndex(
(item) => item?.id === itemId
);
if (!itemFoundIndex) return; // No changes
const itemFound = structuredClone(context.lists?.[itemFoundIndex]);
const newItem = { ...itemFound, ...newItemData };
const newList = structuredClone(context.lists);
newList.splice(newItem, itemFoundIndex, 1);
enqueue.assign({ lists: newList }); // <- Doing it here!
})
} |
Beta Was this translation helpful? Give feedback.
-
Hey David, your reply is much appreciated and thank you in general for the terrific work you all have done!
That being said, I'm currently at a conceptual crossroad on what the most architecturally clean solution is: should all app/business logic stay within xState (as above), or only keep xState to a minium/as pure as possible by doing all the logic beforehand (reading data using getSnapshot) and then only call xState to mutate state when necessary. E.g.:: // beforehand-business-logic.js
if (action === 'edit') {
const listsActorSnapshot = listsActor.getSnapshot()
const listsData = listsActorSnapshot?.context?.lists
const itemId = event?.id;
if (!itemId) return; // No changes
const itemFoundIndex = context.lists.findIndex(
(item) => item?.id === itemId
);
if (!itemFoundIndex) return; // No changes
const itemFound = structuredClone(context.lists?.[itemFoundIndex]);
const newItem = { ...itemFound, ...newItemData };
const newList = structuredClone(context.lists);
newList.splice(newItem, itemFoundIndex, 1);
return listsActor.send({
type: 'editItem',
// // additional data
id: itemId,
newList,
})
} // listsMachine.js
editItem: {
actions: assign({
lists: function ({ context, event }) {
lists: event?.newList
},
}),
}, I'd appreciate to hear what you consider the best approach? EDITED: |
Beta Was this translation helpful? Give feedback.
-
I'm starting out with xState, and it seems strange that actions: would need to be followed immediately by a assign in order to change context data. In some cases you might have a super lengthy function and only want to actually do an assign/change if all checks work out. If the checks do not work out, one would need to assign /return the already existing state in order for the context to not get corrupted.
Example:
This would be more idiomatic yet it doesn't work if not the whole function is wrapped in the assign.
Beta Was this translation helpful? Give feedback.
All reactions