首页 > web前端 > js教程 > 面向 React 开发人员的综合 Redux 工具包说明

面向 React 开发人员的综合 Redux 工具包说明

Barbara Streisand
发布: 2025-01-15 07:37:43
原创
213 人浏览过

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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板