跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端

前端状态管理指南:Redux Toolkit、Zustand 与 Jotai 对比

对比了三种主流前端状态管理方案:Redux Toolkit、Zustand 和 Jotai。通过反面教材展示传统组件传参的弊端,并分别提供基于这三种库的正确实现代码。Redux Toolkit 适合大型复杂应用,Zustand 轻量灵活,Jotai 基于原子化状态。帮助开发者根据项目需求选择合适的状态管理工具,避免状态混乱。

清酒独酌发布于 2026/4/6更新于 2026/7/2143 浏览

前端状态管理指南:Redux Toolkit、Zustand 与 Jotai 对比

问题剖析

这状态管理得跟蜘蛛网似的,谁能理得清?

各位前端同行,咱们今天聊聊前端状态管理。别告诉我你还在使用 setState 管理所有状态,那感觉就像在没有地图的情况下寻宝——能找,但累死你。

为什么你需要状态管理

最近看到一个项目,组件之间传递状态需要经过 5 层,修改一个状态要修改多个地方。我就想问:你是在做状态管理还是在做传递游戏?

反面教材
// 反面教材:混乱的状态管理
function App() {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState([]);
  const [comments, setComments] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchData() {
      setLoading(true);
      try {
        const userResponse = await fetch('/api/user');
        const userData = await userResponse.json();
        setUser(userData);
        const postsResponse = await fetch('/api/posts');
        const postsData = await postsResponse.json();
        setPosts(postsData);
        const commentsResponse =  ();
         commentsData =  commentsResponse.();
        (commentsData);
      }  (error) {
        .(, error);
      }  {
        ();
      }
    }
    ();
  }, []);

   (
    
  );
}

 () {
   ;
}

 () {
   (
    
  );
}

 () {
   postComments = comments.( comment. === postId);
   (
    
  );
}
await
fetch
'/api/comments'
const
await
json
setComments
catch
console
error
'Error fetching data:'
finally
setLoading
false
fetchData
return
<div> {loading ? <div>加载中...</div> : ( <div> <UserHeader user={user} /> <PostList posts={posts} comments={comments} /> </div> )} </div>
function
UserHeader
{ user }
return
<h1>Welcome, {user?.name}</h1>
function
PostList
{ posts, comments }
return
<div> {posts.map(post => ( <div key={post.id}> <h2>{post.title}</h2> <p>{post.content}</p> <CommentList postId={post.id} comments={comments} /> </div> ))} </div>
function
CommentList
{ postId, comments }
const
filter
comment =>
postId
return
<div> {postComments.map(comment => ( <div key={comment.id}>{comment.content}</div> ))} </div>

方案总结:这状态管理,就像在玩传球游戏,球传来传去都不知道传到哪里了。

正确姿势

1. Redux Toolkit
// 正确姿势:Redux Toolkit
// 1. 安装依赖
// npm install @reduxjs/toolkit react-redux

// 2. 创建 store
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './slices/userSlice';
import postsReducer from './slices/postsSlice';
import commentsReducer from './slices/commentsSlice';

export const store = configureStore({
  reducer: {
    user: userReducer,
    posts: postsReducer,
    comments: commentsReducer,
  },
});

// 3. 创建 slices
// store/slices/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk('user/fetchUser', async () => {
  const response = await fetch('/api/user');
  return response.json();
});

const userSlice = createSlice({
  name: 'user',
  initialState: {
    data: null,
    loading: false,
    error: null,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.loading = false;
        state.data = action.payload;
      })
      .addCase(fetchUser.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message;
      });
  },
});

export default userSlice.reducer;

// 4. 使用 store
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './store';

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider store={store}>
    <App />
  </Provider>
);

// 5. 使用状态
// App.jsx
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUser } from './store/slices/userSlice';
import { fetchPosts } from './store/slices/postsSlice';
import { fetchComments } from './store/slices/commentsSlice';
import UserHeader from './components/UserHeader';
import PostList from './components/PostList';

function App() {
  const dispatch = useDispatch();
  const { loading } = useSelector((state) => state.user);

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

  return (
    <div>
      {loading ? <div>加载中...</div> : (
        <div>
          <UserHeader />
          <PostList />
        </div>
      )}
    </div>
  );
}

// components/UserHeader.jsx
import React from 'react';
import { useSelector } from 'react-redux';

function UserHeader() {
  const user = useSelector((state) => state.user.data);
  return <h1>Welcome, {user?.name}</h1>;
}

export default UserHeader;

// components/PostList.jsx
import React from 'react';
import { useSelector } from 'react-redux';
import CommentList from './CommentList';

function PostList() {
  const posts = useSelector((state) => state.posts.data);
  return (
    <div>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
          <CommentList postId={post.id} />
        </div>
      ))}
    </div>
  );
}

export default PostList;

// components/CommentList.jsx
import React from 'react';
import { useSelector } from 'react-redux';

function CommentList({ postId }) {
  const comments = useSelector((state) => state.comments.data.filter(comment => comment.postId === postId));
  return (
    <div>
      {comments.map(comment => (
        <div key={comment.id}>{comment.content}</div>
      ))}
    </div>
  );
}

export default CommentList;
2. Zustand
// 正确姿势:Zustand
// 1. 安装依赖
// npm install zustand

// 2. 创建 store
// store/index.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(
  persist(
    (set, get) => ({
      user: null,
      posts: [],
      comments: [],
      loading: false,
      error: null,
      fetchUser: async () => {
        set({ loading: true, error: null });
        try {
          const response = await fetch('/api/user');
          const data = await response.json();
          set({ user: data, loading: false });
        } catch (error) {
          set({ error: error.message, loading: false });
        }
      },
      fetchPosts: async () => {
        set({ loading: true, error: null });
        try {
          const response = await fetch('/api/posts');
          const data = await response.json();
          set({ posts: data, loading: false });
        } catch (error) {
          set({ error: error.message, loading: false });
        }
      },
      fetchComments: async () => {
        set({ loading: true, error: null });
        try {
          const response = await fetch('/api/comments');
          const data = await response.json();
          set({ comments: data, loading: false });
        } catch (error) {
          set({ error: error.message, loading: false });
        }
      },
    }),
    { name: 'app-storage' }
  )
);

export default useStore;

// 3. 使用 store
// App.jsx
import React, { useEffect } from 'react';
import useStore from './store';
import UserHeader from './components/UserHeader';
import PostList from './components/PostList';

function App() {
  const { loading, fetchUser, fetchPosts, fetchComments } = useStore();

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

  return (
    <div>
      {loading ? <div>加载中...</div> : (
        <div>
          <UserHeader />
          <PostList />
        </div>
      )}
    </div>
  );
}

// components/UserHeader.jsx
import React from 'react';
import useStore from '../store';

function UserHeader() {
  const user = useStore((state) => state.user);
  return <h1>Welcome, {user?.name}</h1>;
}

export default UserHeader;

// components/PostList.jsx
import React from 'react';
import useStore from '../store';
import CommentList from './CommentList';

function PostList() {
  const posts = useStore((state) => state.posts);
  return (
    <div>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
          <CommentList postId={post.id} />
        </div>
      ))}
    </div>
  );
}

export default PostList;

// components/CommentList.jsx
import React from 'react';
import useStore from '../store';

function CommentList({ postId }) {
  const comments = useStore((state) => state.comments.filter(comment => comment.postId === postId));
  return (
    <div>
      {comments.map(comment => (
        <div key={comment.id}>{comment.content}</div>
      ))}
    </div>
  );
}

export default CommentList;
3. Jotai
// 正确姿势:Jotai
// 1. 安装依赖
// npm install jotai

// 2. 创建 atoms
// store/atoms.js
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';

// 状态 atoms
const userAtom = atomWithStorage('user', null);
const postsAtom = atomWithStorage('posts', []);
const commentsAtom = atomWithStorage('comments', []);
const loadingAtom = atom(false);
const errorAtom = atom(null);

// 动作 atoms
const fetchUserAtom = atom(
  null,
  async (_, set) => {
    set(loadingAtom, true);
    set(errorAtom, null);
    try {
      const response = await fetch('/api/user');
      const data = await response.json();
      set(userAtom, data);
    } catch (error) {
      set(errorAtom, error.message);
    } finally {
      set(loadingAtom, false);
    }
  }
);

const fetchPostsAtom = atom(
  null,
  async (_, set) => {
    set(loadingAtom, true);
    set(errorAtom, null);
    try {
      const response = await fetch('/api/posts');
      const data = await response.json();
      set(postsAtom, data);
    } catch (error) {
      set(errorAtom, error.message);
    } finally {
      set(loadingAtom, false);
    }
  }
);

const fetchCommentsAtom = atom(
  null,
  async (_, set) => {
    set(loadingAtom, true);
    set(errorAtom, null);
    try {
      const response = await fetch('/api/comments');
      const data = await response.json();
      set(commentsAtom, data);
    } catch (error) {
      set(errorAtom, error.message);
    } finally {
      set(loadingAtom, false);
    }
  }
);

export { userAtom, postsAtom, commentsAtom, loadingAtom, errorAtom, fetchUserAtom, fetchPostsAtom, fetchCommentsAtom };

// 3. 使用 atoms
// App.jsx
import React, { useEffect } from 'react';
import { useAtomValue, useSetAtom } from 'jotai';
import { loadingAtom, fetchUserAtom, fetchPostsAtom, fetchCommentsAtom } from './store/atoms';
import UserHeader from './components/UserHeader';
import PostList from './components/PostList';

function App() {
  const loading = useAtomValue(loadingAtom);
  const fetchUser = useSetAtom(fetchUserAtom);
  const fetchPosts = useSetAtom(fetchPostsAtom);
  const fetchComments = useSetAtom(fetchCommentsAtom);

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

  return (
    <div>
      {loading ? <div>加载中...</div> : (
        <div>
          <UserHeader />
          <PostList />
        </div>
      )}
    </div>
  );
}

// components/UserHeader.jsx
import React from 'react';
import { useAtomValue } from 'jotai';
import { userAtom } from '../store/atoms';

function UserHeader() {
  const user = useAtomValue(userAtom);
  return <h1>Welcome, {user?.name}</h1>;
}

export default UserHeader;

// components/PostList.jsx
import React from 'react';
import { useAtomValue } from 'jotai';
import { postsAtom } from '../store/atoms';
import CommentList from './CommentList';

function PostList() {
  const posts = useAtomValue(postsAtom);
  return (
    <div>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
          <CommentList postId={post.id} />
        </div>
      ))}
    </div>
  );
}

export default PostList;

// components/CommentList.jsx
import React from 'react';
import { useAtomValue } from 'jotai';
import { commentsAtom } from '../store/atoms';

function CommentList({ postId }) {
  const comments = useAtomValue(commentsAtom);
  const postComments = comments.filter(comment => comment.postId === postId);
  return (
    <div>
      {postComments.map(comment => (
        <div key={comment.id}>{comment.content}</div>
      ))}
    </div>
  );
}

export default CommentList;

方案总结:这才叫前端状态管理,集中管理状态,组件之间共享状态,再也不用担心状态传递的问题了。

目录

  1. 前端状态管理指南:Redux Toolkit、Zustand 与 Jotai 对比
  2. 问题剖析
  3. 为什么你需要状态管理
  4. 反面教材
  5. 正确姿势
  6. 1. Redux Toolkit
  7. 2. Zustand
  8. 3. Jotai
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 基础知识入门:命名空间、引用与函数重载
  • Git 代码上传 Gitee 实战指南
  • ROS1 TF 坐标系广播与监听编程实现
  • Xilinx FPGA 实现 RISC-V 五级流水线 CPU 设计实战
  • AIGC 时代的核心协议:深入理解 Model Context Protocol (MCP)
  • Spring Boot 分组校验、自定义注解与 Redis 登录验证实战
  • GitNexus 核心引擎深度解析
  • 基于 Rokid CXR-M SDK 的 AR 演讲提词器开发实战
  • C++ STL list 双向链表实现与迭代器详解
  • Llama-Factory 是否支持 RLHF?现状与实践路径
  • 基于 Rokid CXR-M SDK 的 AR 演讲提词器开发
  • MySQL 表约束实战指南:从概念到落地
  • 从零构建天气提醒机器人:Claude Code 如何重塑开发工作流
  • 自然语言处理在社交媒体分析中的应用与实战
  • Visual C++运行库缺失导致程序启动失败解决方案
  • 大模型训练核心概念:预训练、后训练与持续训练详解
  • Llama-Factory 强化学习微调支持与 RLHF 模块进展解析
  • iOS 设备管理工具与越狱助手精选
  • C++ 图论最短路径算法详解
  • C++/Qt 智能指针核心分类、原理与实战避坑

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online