Asynchronous Actions and Data Fetching
Unlike Redux, which requires middleware helpers (like Redux Thunk or Saga) to process async operations, Zustand allows you to write asynchronous actions directly in your store.
1. Defining Asynchronous Actions
Let us build a user directories store that fetches details from a remote API. The store manages three states:
data(The returned payload array).isLoading(A boolean indicating if the request is loading).error(Contains any connection error message strings).
// src/stores/useUsersStore.ts
import { create } from "zustand";
interface User {
id: number;
name: string;
email: string;
}
interface UsersState {
users: User[];
isLoading: boolean;
error: string | null;
fetchUsers: () => Promise<void>;
}
export const useUsersStore = create<UsersState>((set) => ({
users: [],
isLoading: false,
error: null,
// Async action
fetchUsers: async () => {
// Set loading indicator
set({ isLoading: true, error: null });
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error("Network response failed");
}
const data = await response.json();
// Save data to store
set({ users: data, isLoading: false });
} catch (err: any) {
// Catch and log error
set({ error: err.message || "Unknown error", isLoading: false });
}
},
}));2. Consuming Async State in React Components
Once defined, you can read the loading state, show error warnings, or render the data grid, and trigger the fetch when the component mounts:
// src/components/UsersList.tsx
import { useEffect } from "react";
import { useUsersStore } from "../stores/useUsersStore";
export default function UsersList() {
const { users, isLoading, error, fetchUsers } = useUsersStore();
// Trigger fetch users when component loads
useEffect(() => {
fetchUsers();
}, [fetchUsers]);
if (isLoading) return <p>Loading users profiles...</p>;
if (error) return <p className="text-red-500">Error: {error}</p>;
return (
<ul className="divide-y">
{users.map((user) => (
<li key={user.id} className="py-3">
<p className="font-bold">{user.name}</p>
<p className="text-sm text-gray-500">{user.email}</p>
</li>
))}
</ul>
);
}Published on Last updated: