Guides
Async Actions
Handling Async Actions & APIs
Async Actions
In modern web apps, data doesn't just sit there—it flows from APIs. Magos makes handling asynchronous logic (like fetch or axios) feel like writing plain JavaScript. No middlewares, no complex patterns.
1. The Async Action Pattern
Since the actionFactory gives you access to the set function, you can call it multiple times within a single async function. This is perfect for managing Loading, Success, and Error states.
The Scenario: Fetching a User Profile
interface UserData {
id: number;
name: string;
email: string;
}
interface UserState {
data: UserData | null;
isLoading: boolean;
error: string | null;
}
const initialState: UserState = {
data: null,
isLoading: false,
error: null
};
const userBox = createBox(initialState, (set) => ({
fetchUser: async (userId) => {
// Step 1: Set loading to true to show a spinner in the UI
set(prev => ({ ...prev, isLoading: true, error: null }));
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) throw new Error("User not found");
const data = await response.json();
// Step 2: Success! Update data and turn off loading
set({ data, isLoading: false, error: null });
} catch (err) {
// Step 3: Handle errors gracefully
set(prev => ({ ...prev, isLoading: false, error: err.message }));
}
}
})
);const initialState = {
data: null,
isLoading: false,
error: null
};
const userBox = createBox(initialState, (set) => ({
fetchUser: async (userId) => {
// Step 1: Set loading to true to show a spinner in the UI
set(prev => ({ ...prev, isLoading: true, error: null }));
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) throw new Error("User not found");
const data = await response.json();
// Step 2: Success! Update data and turn off loading
set({ data, isLoading: false, error: null });
} catch (err) {
// Step 3: Handle errors gracefully
set(prev => ({ ...prev, isLoading: false, error: err.message }));
}
}
})
);2. How it works
The beauty of Magos lies in the set function's availability within the actionFactory. Since actions are standard JavaScript functions, they can be async by nature.
- Sequential Updates: You can update the
statemultiple times within a single action. For instance, updating a loading flag before and after an await call. - Encapsulated Logic: All the logic—from triggering the request to parsing the JSON and handling errors—is contained within the Box. Your UI components stay "clean" and only care about the final state.
- Native Performance: Magos processes each set call immediately. When your API returns data and you call set, Magos instantly notifies all subscribers to update the UI.