首頁 > web前端 > js教程 > 面向 React 開發人員的綜合 Redux 工具包說明

面向 React 開發人員的綜合 Redux 工具包說明

Barbara Streisand
發布: 2025-01-15 07:37:43
原創
271 人瀏覽過

Comprehensive Redux Toolkit Notes for React Developers

? Redux 工具包註解?

Redux 是什麼?
Redux 是 JS 應用程式的靈活狀態容器,可單獨管理我們的應用程式狀態。它在單一儲存中管理應用程式狀態,從而更輕鬆地處理整個應用程式中的複雜狀態邏輯。

為什麼要 Redux?
在正常流程中,我們需要進行道具鑽探以在元件之間傳遞狀態。有些關卡不需要這裡的狀態,這是一種負擔。此外,提升大型中型應用程式的狀態並不是可擴展的解決方案,因為它需要進行結構性變更。這就是為什麼我們需要 redux 來管理狀態。這裡的所有狀態都保存在儲存中,無論哪個元件需要,它們都可以訂閱該儲存。 Redux 透過強制執行單向資料流來確保可預測的狀態管理、更輕鬆的偵錯並提高可擴展性。

Redux 核心元件:

操作: 描述發生的事情的物件。它通常包含一個類型和一個可選的有效負載。 (命令)
調度: 用於向儲存發送操作以更新狀態的函數。 (事件發生)
Reducer: 一個純函數,它接受目前狀態和一個操作,然後傳回一個新狀態。 (動作調度時觸發的函數)

安裝: npm i @reduxjs/toolkit react-redux

Redux 工作流程:

建立切片:
切片是單一功能的 Redux 減速機邏輯和操作的集合。準備回調允許我們在操作有效負載到達減速器之前對其進行自訂。

import { createSlice, nanoid } from "@reduxjs/toolkit";

const postSlice = createSlice({
 name: "posts",
 initialState: [],
 reducers: {
   addPost: {
     reducer: (state, action) => {
       state.push(action.payload);
     },
     prepare: (title, content) => ({
       payload: { id: nanoid(), title, content },
     }),
   },
   deletePost: (state, action) => {
     return state.filter((post) => post.id != action.payload);
   },
 },
});

export const { addPost, deletePost } = postSlice.actions;

export default postSlice.reducer;
登入後複製
登入後複製

正在建立商店:

import { configureStore } from "@reduxjs/toolkit";
import postReducer from "../features/posts/postSlice";

export const store = configureStore({
   reducer: {
       posts: postReducer
   },
 });

登入後複製
登入後複製

與提供者一起包裹:

import { Provider } from "react-redux";
import { store } from "./app/store.jsx";

createRoot(document.getElementById("root")).render(
 <StrictMode>
   <Provider store={store}>
     <App />
   </Provider>
 </StrictMode>
);
登入後複製
登入後複製

在組件中使用:

const PostList = ({ onEdit }) => {
 const posts = useSelector((state) => state.posts);
 const dispatch = useDispatch();

 return (
   <div className="w-full grid grid-cols-1 gap-6 mt-12">
     {posts.map((post) => (
       <div key={post.id}></div>
     ))}
   </div>
 );
};
登入後複製
登入後複製

Redux 瀏覽器擴充: Redux DevTools

const store = configureStore({
  reducer: rootReducer,
  devTools: process.env.NODE_ENV !== 'production',
});
登入後複製
登入後複製

Redux 中的非同步操作(Redux Thunk):

在 Redux 中,非同步操作(如 API 呼叫)是使用中間件處理的,因為 Redux 預設僅支援同步狀態更新。用於處理非同步操作的最常見中間件是 Redux Thunk、帶有 createAsyncThunk 的 Redux Toolkit (RTK) 和 Redux Saga。

實作:

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

// Fetch all posts
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  return response.json();
});

// Initial State
const initialState = {
  posts: [],
  post: null,
  loading: false,
  error: null,
};

// Slice
const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      // Fetch all posts
      .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;
      })

      },
});

export default postsSlice.reducer;
登入後複製
登入後複製

用例:

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchPosts, createPost, updatePost, deletePost } from './postsSlice';

const Posts = () => {
  const dispatch = useDispatch();
  const { posts, loading, error } = useSelector((state) =>state.posts);

  useEffect(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  const handleCreate = () => {
    dispatch(createPost({ title: 'New Post', body: 'This is a new post' }));
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <div>
      <h1>Posts</h1>
      <button onClick={handleCreate}>Create Post</button>
     </div>
  );
};

export default Posts;
登入後複製
登入後複製

中介軟體
Redux 中的中介軟體攔截分派的操作,允許日誌記錄、崩潰報告或處理非同步邏輯。中間件讓我們可以自訂調度過程。

const blogPostMiddleware = (storeAPI) => (next) => (action) => {
  if (action.type === 'posts/publishPost') {
    const contentLength = action.payload.content.length;

    if (contentLength < 50) {
      console.warn('Post content is too short. Must be at least 50 characters.');
      return;
    }
    console.log('Publishing post:', action.payload.title);
  }
  return next(action);
};

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(blogPostMiddleware),
});
登入後複製
登入後複製

選擇器
選擇器有助於訪問該州的特定部分。

export const selectCount = (state) =>狀態.計數器.值;

錯誤處理
透過適當的狀態管理有效地處理錯誤。

import { createSlice, nanoid } from "@reduxjs/toolkit";

const postSlice = createSlice({
 name: "posts",
 initialState: [],
 reducers: {
   addPost: {
     reducer: (state, action) => {
       state.push(action.payload);
     },
     prepare: (title, content) => ({
       payload: { id: nanoid(), title, content },
     }),
   },
   deletePost: (state, action) => {
     return state.filter((post) => post.id != action.payload);
   },
 },
});

export const { addPost, deletePost } = postSlice.actions;

export default postSlice.reducer;
登入後複製
登入後複製

RTK 查詢(簡化資料取得)

RTK 查詢簡化了資料取得、快取和同步。 RTK 查詢自動快取請求並避免不必要的重新獲取,從而提高效能。

設定 RTK 查詢

import { configureStore } from "@reduxjs/toolkit";
import postReducer from "../features/posts/postSlice";

export const store = configureStore({
   reducer: {
       posts: postReducer
   },
 });

登入後複製
登入後複製

組件中的使用

import { Provider } from "react-redux";
import { store } from "./app/store.jsx";

createRoot(document.getElementById("root")).render(
 <StrictMode>
   <Provider store={store}>
     <App />
   </Provider>
 </StrictMode>
);
登入後複製
登入後複製

使用 Immer 進行不可變更新

Immer 允許我們編寫直接「改變」狀態的邏輯,同時保持更新在幕後不可變。

const PostList = ({ onEdit }) => {
 const posts = useSelector((state) => state.posts);
 const dispatch = useDispatch();

 return (
   <div className="w-full grid grid-cols-1 gap-6 mt-12">
     {posts.map((post) => (
       <div key={post.id}></div>
     ))}
   </div>
 );
};
登入後複製
登入後複製

變異與不可變

Mutate:直接變更資料。例如,修改物件或陣列。
不可變:我們不是直接修改數據,而是創建一個應用更改的新副本,保持原始數據不變。

Immer 的工作原理
Immer 幫助我們編寫看起來像是在改變資料的程式碼(即直接更改資料),但它會自動使變更在幕後保持不變。這對於在處理 JavaScript 中的不可變資料結構時避免常見錯誤很有用。
範例:沒有 Immer(突變):

const store = configureStore({
  reducer: rootReducer,
  devTools: process.env.NODE_ENV !== 'production',
});
登入後複製
登入後複製

使用 Immer(不變性):

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

// Fetch all posts
export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  return response.json();
});

// Initial State
const initialState = {
  posts: [],
  post: null,
  loading: false,
  error: null,
};

// Slice
const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      // Fetch all posts
      .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;
      })

      },
});

export default postsSlice.reducer;
登入後複製
登入後複製

這使得使用 Redux(或任何狀態管理)變得更容易,因為我們不必手動複製和更新狀態; Immer 會自動為我們做這件事。

Redux 持久化:

為了在頁面刷新時保持 Redux 狀態,我們可以整合 Redux Persist。這會將您的 Redux 狀態儲存在本機儲存或會話儲存中,並在刷新應用程式時重新載入它。

安裝:
npm install redux-persist

實作:

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchPosts, createPost, updatePost, deletePost } from './postsSlice';

const Posts = () => {
  const dispatch = useDispatch();
  const { posts, loading, error } = useSelector((state) =>state.posts);

  useEffect(() => {
    dispatch(fetchPosts());
  }, [dispatch]);

  const handleCreate = () => {
    dispatch(createPost({ title: 'New Post', body: 'This is a new post' }));
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <div>
      <h1>Posts</h1>
      <button onClick={handleCreate}>Create Post</button>
     </div>
  );
};

export default Posts;
登入後複製
登入後複製

用 Persisit Gate 包裹:

const blogPostMiddleware = (storeAPI) => (next) => (action) => {
  if (action.type === 'posts/publishPost') {
    const contentLength = action.payload.content.length;

    if (contentLength < 50) {
      console.warn('Post content is too short. Must be at least 50 characters.');
      return;
    }
    console.log('Publishing post:', action.payload.title);
  }
  return next(action);
};

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(blogPostMiddleware),
});
登入後複製
登入後複製

選購增強功能

使用 sessionStorage 而不是 localStorage:
將儲存變更為基於會話(瀏覽器關閉時清除):

initialState: {
  items: [],
  status: 'idle',
  error: null,
},

.addCase(fetchData.rejected, (state, action) => {
  state.status = 'failed';
  state.error = action.error.message;
});
登入後複製

選擇性堅持:
只保留狀態的特定部分:

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

const api = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com' }),
  endpoints: (builder) => ({
    getPosts: builder.query({
      query: () => '/posts',
    }),
    getPostById: builder.query({
      query: (id) => `/posts/${id}`,
    }),
    createPost: builder.mutation({
      query: (newPost) => ({
        url: '/posts',
        method: 'POST',
        body: newPost,
      }),
    }),
    updatePost: builder.mutation({
      query: ({ id, ...updatedPost }) => ({
        url: `/posts/${id}`,
        method: 'PUT',
        body: updatedPost,
      }),
    }),
    deletePost: builder.mutation({
      query: (id) => ({
        url: `/posts/${id}`,
        method: 'DELETE',
      }),
    }),
  }),
});

export const {
  useGetPostsQuery,
  useGetPostByIdQuery,
  useCreatePostMutation,
  useUpdatePostMutation,
  useDeletePostMutation,
} = api;
export default api;
登入後複製

我建立了一個簡單的部落格項目,其中包含react、redux和具有CRUD功能的ant design。你可以去看看。
專案連結 - Redux 部落格應用程式

?掌握 Redux Toolkit 並提升您的 React 應用程式!

以上是面向 React 開發人員的綜合 Redux 工具包說明的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板