{"id":10571,"date":"2024-03-30T15:23:10","date_gmt":"2024-03-30T15:23:10","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=10571"},"modified":"2024-03-31T10:11:33","modified_gmt":"2024-03-31T10:11:33","slug":"zustand-state-management","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/zustand-state-management\/","title":{"rendered":"Zustand state management"},"content":{"rendered":"<p>I&#8217;m used to using Redux and more recently Redux Toolkit for global state management in React, however along with state management libraries such as Mobx there&#8217;s another library of interest to me, named Zustand. Let&#8217;s see how to set up and project and use Zustand and take a very high level look at how to set-up a project with Zustand&#8230;<\/p>\n<p>Create yourself a React application, as usual I&#8217;m using TypeScript.<\/p>\n<ul>\n<li>Add Zustand using <em>yarn add zustand<\/em><\/li>\n<li>Our store is a hook, and to create the store we use the <em>create<\/em> method, for example\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { create } from &quot;zustand&quot;;\r\n\r\ninterface CounterState {\r\n    counter: number;\r\n    increment: () =&gt; void;\r\n    decrement: () =&gt; void;\r\n}\r\n\r\nexport const useCounterStore = create&lt;CounterState&gt;(set =&gt; ({\r\n    counter: 0,\r\n    increment: () =&gt; set(state =&gt; ({ counter: state.counter + 1 })),\r\n    decrement: () =&gt; set(state =&gt; ({ counter: state.counter - 1 })),\r\n}));\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>The above creates a simple store, with state and methods to interact with the state. As we&#8217;re using TypeScript, we&#8217;ve declared the interface matching our state.<\/p>\n<p>To use this state we simply use the hook like this (change App.tsx to look like the following)<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport &#039;.\/App.css&#039;;\r\nimport { useCounterStore } from &quot;.\/store&quot;;\r\n\r\nfunction App() {\r\n  const { counter, increment, decrement } = useCounterStore();\r\n\r\n  return (\r\n    &lt;div className=&quot;App&quot;&gt;\r\n      &lt;button onClick={increment}&gt;+&lt;\/button&gt;\r\n      &lt;div&gt;{counter}&lt;\/div&gt;\r\n      &lt;button onClick={decrement}&gt;-&lt;\/button&gt;\r\n    &lt;\/div&gt;\r\n  );\r\n}\r\n\r\nexport default App;\r\n<\/pre>\n<p>We can also get slices of our state using the hook like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nconst counter = useCounterStore(state =&gt; state.counter);\r\n<\/pre>\n<p>Before we move on, unlike RTK we need to enable redux devtools if we want to view the state in the Redux DevTools in our Browser, so to add the dev tool extensions do the following<\/p>\n<ul>\n<li>yarn add @redux-devtools\/extension<\/li>\n<li>We need to import the devtools and change our store a little, so here&#8217;s the store with all the additions\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nimport { create } from &quot;zustand&quot;;\r\nimport { devtools } from &quot;zustand\/middleware&quot;\r\nimport type {} from &quot;@redux-devtools\/extension&quot;;\r\n\r\ninterface CounterState {\r\n  counter: number;\r\n  increment: () =&gt; void;\r\n  decrement: () =&gt; void;\r\n}\r\n\r\nexport const useCounterStore = create&lt;CounterState&gt;()(\r\n  devtools (\r\n    set =&gt; ({\r\n      counter: 0,\r\n      increment: () =&gt; set(state =&gt; ({ counter: state.counter + 1 })),\r\n      decrement: () =&gt; set(state =&gt; ({ counter: state.counter - 1 })),\r\n    }),\r\n    {\r\n      name: &quot;counter-store&quot;,\r\n    }\r\n  )\r\n);\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>Zustand also has the ability to wrap our global state within a persistence middleware. This allows us to save to various types of storage. We simply wrap our state in <em>persist<\/em> like this <\/p>\n<pre class=\"brush: java; highlight: [5]; title: ; notranslate\" title=\"\">\r\nimport { devtools, persist } from &quot;zustand\/middleware&quot;\r\n\r\nexport const useCounterStore = create&lt;CounterState&gt;()(\r\n  devtools (\r\n    persist (\r\n      set =&gt; ({\r\n        counter: 0,\r\n        increment: () =&gt; set(state =&gt; ({ counter: state.counter + 1 })),\r\n        decrement: () =&gt; set(state =&gt; ({ counter: state.counter - 1 })),\r\n      }),\r\n      {\r\n        name: &quot;counter-store&quot;,\r\n      }\r\n    )\r\n  )\r\n);\r\n<\/pre>\n<p>By default (as in the above code) this state will be persisted to localStorage.<\/p>\n<p>Go check your Application | Local Storage in Edge or Chrome developer tools, for example for Local Storage I have a key <em>counter-store<\/em> with the value <em>{&#8220;state&#8221;:{&#8220;counter&#8221;:4},&#8221;version&#8221;:0}<\/em>.<\/p>\n<p><strong>Code<\/strong><\/p>\n<p>Code from this post is available on <a href=\"https:\/\/github.com\/putridparrot\/blog-projects\/tree\/master\/UseZustand\" rel=\"noopener\" target=\"_blank\">github<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m used to using Redux and more recently Redux Toolkit for global state management in React, however along with state management libraries such as Mobx there&#8217;s another library of interest to me, named Zustand. Let&#8217;s see how to set up and project and use Zustand and take a very high level look at how to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[243,720],"tags":[],"class_list":["post-10571","post","type-post","status-publish","format-standard","hentry","category-react","category-zustand"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10571","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=10571"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10571\/revisions"}],"predecessor-version":[{"id":10773,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/10571\/revisions\/10773"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=10571"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=10571"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=10571"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}