Redux - Async Thunks

Async logic (like fetching data) should live in thunks. Redux Toolkit’s createAsyncThunk simplifies loading and error handling.

Try it: Simulated fetch

View source
const { createSlice, configureStore, createAsyncThunk } = RTK;
const fetchGreeting = createAsyncThunk('greet/fetch', async () => {
  await new Promise(r => setTimeout(r, 500));
  if (Math.random() < 0.1) throw new Error('Random failure');
  return { message: 'Hello from thunk!' };
});
const slice = createSlice({
  name: 'greet',
  initialState: { status: 'idle', data: null, error: null },
  reducers: {},
  extraReducers: b => {
    b.addCase(fetchGreeting.pending, (s) => { s.status='loading'; s.error=null; })
     .addCase(fetchGreeting.fulfilled, (s, a) => { s.status='succeeded'; s.data=a.payload; })
     .addCase(fetchGreeting.rejected, (s, a) => { s.status='failed'; s.error=a.error.message; });
  }
});
const store = configureStore({ reducer: { greet: slice.reducer } });
function App(){
  const { Provider, useSelector, useDispatch } = ReactRedux;
  function Panel(){
    const st = useSelector(s => s.greet);
    const dispatch = useDispatch();
    return (
      <div>
        <button onClick={() => dispatch(fetchGreeting())} disabled={st.status==='loading'}>Fetch</button>
        <div style={{marginTop:8}}>Status: {st.status}</div>
        {st.data && <div>Data: {st.data.message}</div>}
        {st.error && <div style={{color:'salmon'}}>Error: {st.error}</div>}
      </div>
    );
  }
  return <Provider store={store}><Panel /></Provider>;
}
ReactDOM.createRoot(document.getElementById('thunk-root')).render(<App />);

Syntax primer

  • createAsyncThunk(type, payloadCreator) emits pending/fulfilled/rejected actions.
  • Handle those in extraReducers to set status, data, and error.