Redux 工具包 - createAsyncThunk()

**createAsyncThunk()** 是 Redux Toolkit 中的一个函数,用于处理异步操作,例如 API 调用。此函数自动处理三个主要阶段:

  • Pending:当 API 请求发起时。
  • 已完成:当请求成功并且收到数据时。
  • 被拒绝:当请求失败时。
  • 本文是上一篇文章的续篇,您可以在此处阅读。

    创建 postSlice

    import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
    import axios from 'axios';
    
    interface Post {
      id: number;
      title: string;
      body: string;
    }
    
    interface PostState {
      posts: Post[];
      loading: boolean;
      error: string | null;
    }
    
    const initialState: PostState = {
      posts: [],
      loading: false,
      error: null,
    };
    
    // Create a thunk to fetch data
    export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
      const response = await axios.get(
        'https://jsonplaceholder.typicode.com/posts'
      );
    
      return response.data;
    });
    
    // Create slice
    const postSlice = createSlice({
      name: 'posts',
      initialState,
      reducers: {},
      extraReducers: (builder) => {
        builder
          .addCase(fetchPosts.pending, (state) => {
            state.loading = true;
          })
          .addCase(fetchPosts.fulfilled, (state, action) => {
            state.loading = false;
            state.posts = action.payload;
          })
          .addCase(fetchPosts.rejected, (state, action) => {
            state.loading = false;
            state.error = action.error.message || 'Failed to fetch posts';
          });
      },
    });
    
    export default postSlice.reducer;

    帖子/fetchPosts

    “posts/fetchPosts” 是 “createAsyncThunk” 生成的动作的类型。

    通用格式:''/“”

    为什么要使用这种格式?

  • 避免大型应用程序中的动作名称冲突。
  • Redux DevTools 使用此名称进行调试。
  • Reducer 和 extraReducers 之间的区别

    什么是 builder 和 addCase

    `builder` 是 Redux Toolkit 的一个特殊 API,用于 `extraReducers` 中,用来有组织地添加 action handlers。其中最主要的方法是 `addCase`,通过指定 action type 和对应的 Reducer 函数来处理具体的 action。

    更新 store.ts

    import { configureStore } from '@reduxjs/toolkit';
    import counterReducer from './slice/counterSlice';
    import storage from 'redux-persist/lib/storage';
    import { persistReducer, persistStore } from 'redux-persist';
    import postsReducer from './slice/postSlice';
    
    const persistConfig = {
      key: 'root',
      storage,
    };
    
    const persistedCounterReducer = persistReducer(persistConfig, counterReducer);
    
    export const store = configureStore({
      reducer: {
        counter: persistedCounterReducer,
        posts: postsReducer,
      },
    });
    
    export const persistor = persistStore(store);
    export type RootState = ReturnType;
    export type AppDispatch = typeof store.dispatch;

    在组件中使用

    import { useDispatch, useSelector } from 'react-redux';
    import { AppDispatch, RootState } from './state/store';
    import {
      decrement,
      increment,
      incrementByAmount,
    } from './state/slice/counterSlice';
    import { useEffect } from 'react';
    import { fetchPosts } from './state/slice/postSlice';
    
    export default function App() {
      const count = useSelector((state: RootState) => state.counter.value);
      const { posts, error, loading } = useSelector(
        (state: RootState) => state.posts
      );
      const dispatch: AppDispatch = useDispatch();
    
      useEffect(() => {
        dispatch(fetchPosts());
      }, [dispatch]);
    
      return (
        
    {count}
    {loading ? (

    Loading...

    ) : error ? (

    Error: {error}

    ) : (
      {posts.map((post) => { return (
    • {post.title.length > 20 ? post.title.slice(0, 20) + '...' : post.title}

      {post.body.length > 150 ? post.body + '...' : post.body}

    • ); })}
    )}
    ); }

    结果

    result

    如果收到此错误,请更新 store.ts 并添加中间件。

    Error

    添加中间件

    import { configureStore } from '@reduxjs/toolkit';
    import counterReducer from './slice/counterSlice';
    import storage from 'redux-persist/lib/storage';
    import { persistReducer, persistStore } from 'redux-persist';
    import postsReducer from './slice/postSlice';
    
    const persistConfig = {
      key: 'root',
      storage,
    };
    
    const persistedCounterReducer = persistReducer(persistConfig, counterReducer);
    
    export const store = configureStore({
      reducer: {
        counter: persistedCounterReducer,
        posts: postsReducer,
      },
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          serializableCheck: {
            ignoredActions: ['persist/PERSIST'],
          },
        }),
    });
    
    export const persistor = persistStore(store);
    export type RootState = ReturnType;
    export type AppDispatch = typeof store.dispatch;

    结论

    通过在 Redux Toolkit 中使用 `createAsyncThunk()`,管理 API 调用等异步操作变得更加轻松、更有条理。这种方法简化了数据获取,同时确保了干净且可扩展的 Redux 状态管理结构。

    希望本指南能帮助您更好地了解 Redux Toolkit,尤其是其异步处理功能。如果您有任何问题或反馈,请随时发表评论!

    GitHub 仓库:https://github.com/rfkyalf/redux-toolkit-learn

    此外,如果您有兴趣,请随时访问我的投资组合网站 www.rifkyalfarez.my.id 以探索我的更多项目。感谢您的阅读。