# createAsyncThunk Lifecycle — Redux Toolkit / Zustand

Source: https://www.skillbyai.com/en/redux-zustand/a-thunk

> pending, fulfilled, rejected.

## Three actions from one async function

`createAsyncThunk(type, payloadCreator)` returns a thunk action creator. When dispatched, it first dispatches a `pending` action, runs your async `payloadCreator`, then dispatches `fulfilled` with the resolved value as `payload`, or `rejected` if it throws. A slice handles these in `extraReducers` with `builder.addCase(thunk.pending, ...)`. The payload creator receives the argument and a `thunkAPI` object with `dispatch`, `getState`, `signal` (an AbortSignal), `rejectWithValue` and more.

## Side effects live outside reducers

Reducers stay pure; thunks and listeners handle the async work.

![Three ideas: createAsyncThunk lifecycle, loading and error state, listener middleware.](assets/figures/redux-zustand/section-3-map.svg) — Figure 3.1 — A thunk dispatching pending, fulfilled and rejected actions.

## Fetching a user

A thunk and its slice cases.

```typescript
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

type User = { id: string; name: string };

export const fetchUser = createAsyncThunk(
  'user/fetch',
  async (id: string, { signal }) => {
    const res = await fetch(`/api/users/${id}`, { signal });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return (await res.json()) as User;
  }
);

type UserState = { data: User | null; status: 'idle' | 'loading' | 'succeeded' | 'failed' };

const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, status: 'idle' } as UserState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => { state.status = 'loading'; })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.data = action.payload;
      })
      .addCase(fetchUser.rejected, (state) => { state.status = 'failed'; });
  },
});
```

## A parcel tracking page

Order placed (pending), delivered (fulfilled) or returned to sender (rejected): the UI shows whichever status the latest update reports.

**Quiz:** Which actions can a createAsyncThunk dispatch for one call?

- [x] pending, then either fulfilled or rejected
- [ ] start and end only
- [ ] request, success, failure and retry
- [ ] Only fulfilled

*Answer:* pending, then either fulfilled or rejected. The lifecycle actions are generated automatically.
