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

前端状态管理:Redux、Zustand 与 Jotai 方案对比

综述由AI生成探讨了前端状态管理中常见的 props 传递混乱问题,对比了 Redux Toolkit、Zustand 和 Jotai 三种主流解决方案。通过具体代码示例,展示了如何集中管理状态、简化组件通信,并分析了各方案的适用场景,旨在帮助开发者构建更清晰、可维护的前端应用架构。

未来可期发布于 2026/4/6更新于 2026/5/2025 浏览

前端状态管理:Redux、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、Zustand 与 Jotai 方案对比
  2. 问题分析
  3. 为什么你需要状态管理
  4. 反面教材
  5. 正确姿势
  6. 1. Redux Toolkit
  7. 2. Zustand
  8. 3. Jotai
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • AIGC 技术现状、应用场景与未来趋势
  • AI 大模型入门:文心一言与百度 AI 战略
  • ComfyUI Photoshop 插件配置与使用指南
  • 双指针算法:快乐数与盛水最多的容器
  • 二叉树转字符串的递归解法核心逻辑与代码实现
  • 低成本运行 Claude Code:通过 LiteLLM 接入 GitHub Copilot Chat API
  • TradingView 基础账户免费 Webhook 警报配置实战
  • Faster-Whisper-GUI 日语语音识别异常问题排查与修复
  • 前端开发指南:如何优雅管理 Import 语句避免满屏导入
  • 基于 Rokid 灵珠平台搭建旅游 AR 智能体实战指南
  • ROS2 Humble 环境下 Mid360 雷达 FAST-LIO 算法部署教程
  • Cursor 实战:Web 版背单词应用开发
  • 麦橘超然与主流 AI 绘画模型对比实测
  • WebStorm 开发卡顿问题排查与性能优化方案
  • Python 基于随机森林的心脏衰竭风险预测系统开发
  • LLaMA 大模型开源论文阅读笔记
  • Python AI 开发环境搭建:Anaconda + PyCharm + Claude Code 配置教程
  • Pandas 数据合并与拼接:merge、join 与 concat 详解
  • OpenClaw 技能精选:本地 AI 助手超级插件市场指南
  • 【火】Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这

相关免费在线工具

  • 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