Reputation: 560
I've got an application which performs API actions when buttons are hit. When the action is ended I update a Recoil state. But the thing is when I try to update the state I replace the old one with the new updated one, and in an async context I don't know how to get the current state at the moment where my code is executed.
const [tasks, setTasks] = useRecoilState(tasksState);
const handleAction = async (task: Task): Promise<void> => {
try {
// some async stuff here with an API
// update the recoil state here
// MY ISSUE HERE is that the "tasks" state is not the one at the moment where the code is executed after the API response,
// but at the moment where handleAction has been called...
// So I can override the state with old values, previously updated from an other handleAction ended earlier.
const newTasks = updateTasks(tasks, anOtherParameterFromApiResponse);
setTasks(newTasks);
} catch(error){
console.log("error: ", error);
}
}
Can you please me how to approach such pattern and be able to update the state when my async actions are ended.
Note: my state is an array of objects, and my updateTasks() function is a function which update an object from this array so I can update the state with this computed array.
Thank you in advance for the precious help you will give me!
Upvotes: 3
Views: 3938
Reputation: 560
I've find a solution by self :
I've created a 'selector' from my tasks 'atom', and delegated in a custom 'set' method the aggreation of the new object with the object array state. Thanks to the 'get' method provided in parameter I can access to the object array state up to date.
selectors.ts :
/**
* Allow to update the tasksState by passing in parameter the task to update
* That way we can call this from an async context and updating value by agreagating to the eventual new ones
*/
export const taskUnitUpdaterSelector = selector<Task>({
key: "taskUnitUpdaterSelector",
get: () => {
throw new Error("Not implemented !");
},
set: ({ get, set }, newTask: Docker) => {
const tasks = get(tasksState);
// remove from tasks list the new one updated to add it then
const tasksCloneWithoutNewUpdatedOne = tasks.filter(
(t) => !(t.name === newTask.name && t.server === newTask.server),
);
const newTasks = [...tasksCloneWithoutNewUpdatedOne , newTask];
set(tasksState , newTasks);
});
component.ts
const taskUnitUpdater = useSetRecoilState(taskUnitUpdaterSelector);
const handleAction = async (task: Task): Promise<void> => {
try {
// some async stuff here with an API
// the new tasks array is computed inside the selector set function to be able to access to up to date data !
taskUnitUpdater(newTask );
} catch(error){
console.log("error: ", error);
}
}
Upvotes: 4