{"id":13,"date":"2026-06-09T12:29:47","date_gmt":"2026-06-09T04:29:47","guid":{"rendered":"https:\/\/yykcj.com\/2026\/06\/09\/react%e7%8a%b6%e6%80%81%e7%ae%a1%e7%90%86%e6%96%b9%e6%a1%88%e6%b7%b1%e5%ba%a6%e5%af%b9%e6%af%94%ef%bc%9azustand-vs-jotai-vs-redux-toolkit%ef%bc%8c2025%e5%b9%b4%e9%80%89%e5%9e%8b%e6%8c%87%e5%8d%97\/"},"modified":"2026-06-09T12:29:47","modified_gmt":"2026-06-09T04:29:47","slug":"react%e7%8a%b6%e6%80%81%e7%ae%a1%e7%90%86%e6%96%b9%e6%a1%88%e6%b7%b1%e5%ba%a6%e5%af%b9%e6%af%94%ef%bc%9azustand-vs-jotai-vs-redux-toolkit%ef%bc%8c2025%e5%b9%b4%e9%80%89%e5%9e%8b%e6%8c%87%e5%8d%97","status":"publish","type":"post","link":"https:\/\/yykcj.com\/?p=13","title":{"rendered":"React\u72b6\u6001\u7ba1\u7406\u65b9\u6848\u6df1\u5ea6\u5bf9\u6bd4\uff1aZustand vs Jotai vs Redux Toolkit\uff0c2025\u5e74\u9009\u578b\u6307\u5357"},"content":{"rendered":"<h2>\u5f15\u8a00<\/h2>\n<p>\u5728React\u751f\u6001\u4e2d\uff0c\u72b6\u6001\u7ba1\u7406\u4e00\u76f4\u662f\u6838\u5fc3\u8bdd\u9898\u3002\u968f\u7740React 18\u548cServer Components\u7684\u666e\u53ca\uff0c\u4f20\u7edf\u65b9\u6848\u5982Redux\u9762\u4e34\u6311\u6218\uff0c\u800c\u8f7b\u91cf\u7ea7\u65b9\u6848Zustand\u548cJotai\u9010\u6e10\u6210\u4e3a\u65b0\u5ba0\u3002\u672c\u6587\u5c06\u4ece\u5b9e\u9645\u5f00\u53d1\u89d2\u5ea6\uff0c\u5bf9\u6bd4\u8fd9\u4e09\u79cd\u65b9\u6848\u57282025\u5e74\u7684\u9002\u7528\u573a\u666f\u3002<\/p>\n<h2>\u80cc\u666f\uff1a\u4e3a\u4ec0\u4e48\u9700\u8981\u72b6\u6001\u7ba1\u7406\uff1f<\/h2>\n<p>React\u7684useState\u548cuseContext\u9002\u5408\u5c0f\u578b\u5e94\u7528\uff0c\u4f46\u5f53\u72b6\u6001\u9700\u8981\u8de8\u7ec4\u4ef6\u5171\u4eab\u3001\u6301\u4e45\u5316\u6216\u590d\u6742\u5f02\u6b65\u903b\u8f91\u65f6\uff0c\u4e13\u7528\u72b6\u6001\u7ba1\u7406\u5e93\u80fd\u663e\u8457\u63d0\u5347\u5f00\u53d1\u6548\u7387\u3002<\/p>\n<h2>\u65b9\u6848\u6982\u89c8<\/h2>\n<p>| \u7279\u6027 | Zustand | Jotai | Redux Toolkit | |&#8212;&#8212;|&#8212;&#8212;&#8212;|&#8212;&#8212;-|&#8212;&#8212;&#8212;&#8212;&#8212;| | \u6838\u5fc3\u6982\u5ff5 | \u5355\u4e00store | \u539f\u5b50\u72b6\u6001 | \u5355\u4e00store + reducer | | \u5b66\u4e60\u66f2\u7ebf | \u4f4e | \u4e2d | \u9ad8 | | \u4f53\u79ef | ~1KB | ~2KB | ~12KB | | TypeScript\u652f\u6301 | \u4f18\u79c0 | \u826f\u597d | \u4f18\u79c0 | | \u4e2d\u95f4\u4ef6\u751f\u6001 | \u6709\u9650 | \u6709\u9650 | \u4e30\u5bcc |<\/p>\n<h2>\u5b9e\u6218\u5bf9\u6bd4<\/h2>\n<h3>1. \u8ba1\u6570\u5668\u793a\u4f8b<\/h3>\n<h4>Zustand<\/h4>\n<pre><code class=\"language-javascript\">\nimport { create } from &#x27;zustand&#x27;;\n\nconst useCounterStore = create((set) =&gt; ({\n  count: 0,\n  increment: () =&gt; set((state) =&gt; ({ count: state.count + 1 })),\n  decrement: () =&gt; set((state) =&gt; ({ count: state.count - 1 })),\n}));\n\nfunction Counter() {\n  const { count, increment, decrement } = useCounterStore();\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;{count}&lt;\/h1&gt;\n      &lt;button onClick={increment}&gt;+&lt;\/button&gt;\n      &lt;button onClick={decrement}&gt;-&lt;\/button&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/code><\/pre>\n<h4>Jotai<\/h4>\n<pre><code class=\"language-javascript\">\nimport { atom, useAtom } from &#x27;jotai&#x27;;\n\nconst countAtom = atom(0);\n\nfunction Counter() {\n  const [count, setCount] = useAtom(countAtom);\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;{count}&lt;\/h1&gt;\n      &lt;button onClick={() =&gt; setCount((c) =&gt; c + 1)}&gt;+&lt;\/button&gt;\n      &lt;button onClick={() =&gt; setCount((c) =&gt; c - 1)}&gt;-&lt;\/button&gt;\n    &lt;\/div&gt;\n  );\n}\n<\/code><\/pre>\n<h4>Redux Toolkit<\/h4>\n<pre><code class=\"language-javascript\">\nimport { configureStore, createSlice } from &#x27;@reduxjs\/toolkit&#x27;;\nimport { Provider, useDispatch, useSelector } from &#x27;react-redux&#x27;;\n\nconst counterSlice = createSlice({\n  name: &#x27;counter&#x27;,\n  initialState: { value: 0 },\n  reducers: {\n    increment: (state) =&gt; { state.value += 1; },\n    decrement: (state) =&gt; { state.value -= 1; },\n  },\n});\n\nconst store = configureStore({ reducer: counterSlice.reducer });\n\nfunction Counter() {\n  const count = useSelector((state) =&gt; state.value);\n  const dispatch = useDispatch();\n  return (\n    &lt;div&gt;\n      &lt;h1&gt;{count}&lt;\/h1&gt;\n      &lt;button onClick={() =&gt; dispatch(counterSlice.actions.increment())}&gt;+&lt;\/button&gt;\n      &lt;button onClick={() =&gt; dispatch(counterSlice.actions.decrement())}&gt;-&lt;\/button&gt;\n    &lt;\/div&gt;\n  );\n}\n\n\/\/ App\u9700\u5305\u88f9Provider\nfunction App() {\n  return (\n    &lt;Provider store={store}&gt;\n      &lt;Counter \/&gt;\n    &lt;\/Provider&gt;\n  );\n}\n<\/code><\/pre>\n<h3>2. \u5f02\u6b65\u64cd\u4f5c\uff08API\u8bf7\u6c42\uff09<\/h3>\n<h4>Zustand<\/h4>\n<pre><code class=\"language-javascript\">\nimport { create } from &#x27;zustand&#x27;;\n\nconst useUserStore = create((set) =&gt; ({\n  user: null,\n  loading: false,\n  fetchUser: async (id) =&gt; {\n    set({ loading: true });\n    const res = await fetch(`\/api\/users\/${id}`);\n    const user = await res.json();\n    set({ user, loading: false });\n  },\n}));\n<\/code><\/pre>\n<h4>Jotai (\u4f7f\u7528atomWithQuery)<\/h4>\n<pre><code class=\"language-javascript\">\nimport { atom } from &#x27;jotai&#x27;;\nimport { atomWithQuery } from &#x27;jotai\/query&#x27;;\n\nconst userIdAtom = atom(1);\nconst userAtom = atomWithQuery((get) =&gt; ({\n  queryKey: [&#x27;user&#x27;, get(userIdAtom)],\n  queryFn: async ({ queryKey: [, id] }) =&gt; {\n    const res = await fetch(`\/api\/users\/${id}`);\n    return res.json();\n  },\n}));\n<\/code><\/pre>\n<h4>Redux Toolkit (createAsyncThunk)<\/h4>\n<pre><code class=\"language-javascript\">\nimport { createAsyncThunk, createSlice } from &#x27;@reduxjs\/toolkit&#x27;;\n\nexport const fetchUser = createAsyncThunk(&#x27;user\/fetch&#x27;, async (id) =&gt; {\n  const res = await fetch(`\/api\/users\/${id}`);\n  return res.json();\n});\n\nconst userSlice = createSlice({\n  name: &#x27;user&#x27;,\n  initialState: { user: null, status: &#x27;idle&#x27; },\n  reducers: {},\n  extraReducers: (builder) =&gt; {\n    builder\n      .addCase(fetchUser.pending, (state) =&gt; { state.status = &#x27;loading&#x27;; })\n      .addCase(fetchUser.fulfilled, (state, action) =&gt; {\n        state.status = &#x27;succeeded&#x27;;\n        state.user = action.payload;\n      });\n  },\n});\n<\/code><\/pre>\n<h3>3. \u6027\u80fd\u4f18\u5316<\/h3>\n<h4>Zustand\uff1a\u81ea\u52a8\u7ec6\u7c92\u5ea6\u66f4\u65b0<\/h4>\n<p>Zustand\u9ed8\u8ba4\u4f7f\u7528\u5f15\u7528\u76f8\u7b49\u6027\u68c0\u67e5\uff0c\u5f53\u7ec4\u4ef6\u53ea\u8ba2\u9605\u90e8\u5206\u72b6\u6001\u65f6\uff0c\u4e0d\u76f8\u5173\u72b6\u6001\u53d8\u5316\u4e0d\u4f1a\u89e6\u53d1\u91cd\u6e32\u67d3\u3002<\/p>\n<pre><code class=\"language-javascript\">\n\/\/ \u7ec4\u4ef6\u53ea\u8ba2\u9605count\uff0c\u5176\u4ed6\u72b6\u6001\u53d8\u5316\u4e0d\u4f1a\u5bfc\u81f4\u91cd\u6e32\u67d3\nconst count = useCounterStore((state) =&gt; state.count);\n<\/code><\/pre>\n<h4>Jotai\uff1a\u539f\u5b50\u7ea7\u66f4\u65b0<\/h4>\n<p>\u6bcf\u4e2aatom\u72ec\u7acb\uff0c\u53ea\u6709\u4f9d\u8d56\u7684atom\u53d8\u5316\u624d\u66f4\u65b0\u7ec4\u4ef6\u3002<\/p>\n<h4>Redux Toolkit\uff1a\u9700\u8981\u624b\u52a8\u9009\u62e9<\/h4>\n<p>\u4f7f\u7528useSelector\u65f6\u9700\u6ce8\u610f\uff0c\u9ed8\u8ba4\u6d45\u6bd4\u8f83\uff0c\u53ef\u7ed3\u5408createSelector\u505a\u8bb0\u5fc6\u5316\u3002<\/p>\n<pre><code class=\"language-javascript\">\nimport { createSelector } from &#x27;@reduxjs\/toolkit&#x27;;\nconst selectUser = createSelector([state =&gt; state.user], user =&gt; user);\n<\/code><\/pre>\n<h2>\u9009\u578b\u5efa\u8bae<\/h2>\n<ul>\n<li><strong>\u5c0f\u578b\u9879\u76ee\u6216\u5fae\u524d\u7aef<\/strong>\uff1a\u4f18\u5148Zustand\uff0c\u96f6\u6a21\u677f\u4ee3\u7801\uff0cAPI\u7b80\u6d01\uff0cTypeScript\u53cb\u597d\u3002<\/li>\n<li><strong>\u9700\u8981\u7cbe\u7ec6\u63a7\u5236\u6e32\u67d3<\/strong>\uff1aJotai\u7684\u539f\u5b50\u6a21\u578b\u9002\u5408\u5927\u578b\u5e94\u7528\uff0c\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u91cd\u65b0\u6e32\u67d3\u3002<\/li>\n<li><strong>\u5927\u578b\u9879\u76ee\u6216\u56e2\u961f\u534f\u4f5c<\/strong>\uff1aRedux Toolkit\u751f\u6001\u6210\u719f\uff0c\u4e2d\u95f4\u4ef6\u4e30\u5bcc\uff0c\u4f46\u9700\u6ce8\u610f\u5b66\u4e60\u6210\u672c\u3002<\/li>\n<li><strong>\u670d\u52a1\u7aef\u6e32\u67d3(SSR)<\/strong>\uff1aZustand\u548cJotai\u652f\u6301\u826f\u597d\uff0cRedux\u9700\u989d\u5916\u914d\u7f6e\u3002<\/li>\n<\/ul>\n<h2>\u5e38\u89c1\u5751\u4e0e\u6700\u4f73\u5b9e\u8df5<\/h2>\n<ol>\n<li><strong>Zustand<\/strong>\uff1a\u907f\u514d\u5728store\u5916\u4fee\u6539\u72b6\u6001\uff0c\u4f7f\u7528<code>getState()<\/code>\u9700\u8c28\u614e\u3002<\/li>\n<\/ol>\n<p>&#8220;<code>javascript \/\/ \u4e0d\u63a8\u8350 const store = useCounterStore.getState(); store.count = 10; \/\/ \u4e0d\u4f1a\u89e6\u53d1\u66f4\u65b0 <\/code>&#8220;<\/p>\n<ol>\n<li><strong>Jotai<\/strong>\uff1a\u6d3e\u751f\u539f\u5b50\u6ce8\u610f\u4f9d\u8d56\u8ffd\u8e2a\uff0c\u907f\u514d\u5faa\u73af\u4f9d\u8d56\u3002<\/li>\n<li><strong>Redux Toolkit<\/strong>\uff1a\u4e0d\u8981\u76f4\u63a5\u4fee\u6539state\uff08Immer\u5185\u90e8\u5904\u7406\uff0c\u4f46\u9700\u9075\u5faareducer\u7eaf\u51fd\u6570\u539f\u5219\uff09\u3002<\/li>\n<\/ol>\n<h2>\u603b\u7ed3<\/h2>\n<p>\u6ca1\u6709\u94f6\u5f39\uff0c\u9009\u62e9\u53d6\u51b3\u4e8e\u9879\u76ee\u89c4\u6a21\u3001\u56e2\u961f\u7ecf\u9a8c\u548c\u6027\u80fd\u8981\u6c42\u3002Zustand\u9002\u5408\u5feb\u901f\u5f00\u53d1\uff0cJotai\u9002\u5408\u7cbe\u7ec6\u63a7\u5236\uff0cRedux Toolkit\u9002\u5408\u5927\u578b\u4f01\u4e1a\u7ea7\u5e94\u7528\u3002\u5efa\u8bae\u5c0f\u578b\u9879\u76ee\u5148\u7528Zustand\uff0c\u9047\u5230\u6027\u80fd\u74f6\u9888\u518d\u8003\u8651\u8fc1\u79fb\u3002<\/p>\n<h2>\u5ef6\u4f38\u9605\u8bfb<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.pmnd.rs\/zustand\/getting-started\/introduction\">Zustand\u5b98\u65b9\u6587\u6863<\/a><\/li>\n<li><a href=\"https:\/\/jotai.org\/docs\/introduction\">Jotai\u5b98\u65b9\u6587\u6863<\/a><\/li>\n<li><a href=\"https:\/\/redux-toolkit.js.org\/\">Redux Toolkit\u5b98\u65b9\u6587\u6863<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u672c\u6587\u4ece\u5f00\u53d1\u4f53\u9a8c\u3001\u6027\u80fd\u3001TypeScript\u652f\u6301\u3001\u5b66\u4e60\u66f2\u7ebf\u7b49\u7ef4\u5ea6\uff0c\u6df1\u5165\u5bf9\u6bd4Zustand\u3001Jotai\u548cRedux Toolkit\u4e09\u79cd\u4e3b\u6d41\u72b6\u6001\u7ba1\u7406\u65b9\u6848\u3002\u901a\u8fc7\u5b9e\u9645\u4ee3\u7801\u793a\u4f8b\u548c\u5e38\u89c1\u573a\u666f\u5206\u6790\uff0c\u5e2e\u52a9\u4f60\u6839\u636e\u9879\u76ee\u9700\u6c42\u505a\u51fa\u6700\u4f73\u9009\u578b\u3002<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,4],"tags":[14,11,15,13,16,12],"class_list":["post-13","post","type-post","status-publish","format-standard","hentry","category-3","category-4","tag-jotai","tag-react","tag-redux-toolkit","tag-zustand","tag-16","tag-12"],"_links":{"self":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts\/13","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13"}],"version-history":[{"count":0,"href":"https:\/\/yykcj.com\/index.php?rest_route=\/wp\/v2\/posts\/13\/revisions"}],"wp:attachment":[{"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yykcj.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}