{"id":1367,"date":"2025-02-07T00:00:00","date_gmt":"2025-02-06T23:00:00","guid":{"rendered":"https:\/\/demo.sidekick.be\/itenium\/reduxjs-toolkit-immer\/"},"modified":"2025-11-28T13:31:41","modified_gmt":"2025-11-28T12:31:41","slug":"reduxjs-toolkit-immer","status":"publish","type":"post","link":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/","title":{"rendered":"ReduxJS\/Toolkit: Immer"},"content":{"rendered":"<h1 id=\"redux-bugs\">Redux Bugs<\/h1>\n<p>Redux bugs are almost always cases where you didn\u2019t quite spread enough and\/or did an accidental mutation of the state.<\/p>\n<p>This is exactly the problem immer addresses and does so in a way that you basically don\u2019t know you\u2019re using immer until you inspect the type and see <code>WritableDraft&lt;T&gt;<\/code>.<\/p>\n<h1 id=\"example\">Example<\/h1>\n<h2 id=\"without-immer\">Without Immer<\/h2>\n<p>Do you really want to be doing this\u2026<\/p>\n<pre><code class=\"language-js\">function reducerSpreadHell(state, action) {\n  return {\n    ...state,\n    first: {\n      ...state.first,\n      second: {\n        ...state.first.second,\n        [action.someId]: {\n          ...state.first.second[action.someId],\n          fourth: action.someValue,\n        },\n      },\n    },\n  }\n}\n<\/code><\/pre>\n<p>One could argue that you should be normalizing your store instead of writing reducers like that, and you\u2019d be right.<\/p>\n<h2 id=\"with-immer\">With Immer<\/h2>\n<p>Still, with immer, all that becomes just this:<\/p>\n<pre><code class=\"language-js\">state.first.second[action.someId].fourth = action.someValue;\n<\/code><\/pre>\n<h1 id=\"immer-reducers\">Immer Reducers<\/h1>\n<p>You\u2019d write them as if you just didn\u2019t care about immutability!<\/p>\n<pre><code class=\"language-ts\">import { current, PayloadAction } from \"@reduxjs\/toolkit\";\n\nreducers: {\n  addTodo: (state: WritableDraft&lt;Todo&gt;[], action: PayloadAction&lt;Todo&gt;) =&gt; {\n    \/\/ ReduxJS\/Toolkit wraps the Todo[] state in a WritableDraft\n    \/\/ \"[].push()\" does NOT mutate!\n    \/\/ Same for pop, shift, splice etc...\n    state.push(action.payload);\n  },\n\n  removeTodo: (state, action: PayloadAction&lt;number&gt;) =&gt; {\n    \/\/ ATTN: state = newState does NOT work!\n    \/\/ In such case, return the newState\n    return state.filter(todo =&gt; todo.id !== action.payload);\n  },\n\n  \/\/ ATTN: Mutate or Return, but not both!\n  altAddTodo: (state, action: PayloadAction&lt;Todo&gt;) =&gt; void state.push(action.payload),\n\n  toggleTodo: (state, action: PayloadAction&lt;number&gt;) =&gt; {\n    \/\/ If you want to look at the current state, you need to use current()\n    \/\/ There is also original()\n    console.log('current(state)', current(state));\n\n    const todo = state.find(todo =&gt; todo.id === action.payload)!;\n    todo.done = !todo.done;\n  },\n\n  updateTodo: (state, action: PayloadAction&lt;Todo&gt;) =&gt; {\n    const index = state.findIndex(todo =&gt; todo.id === action.payload.id);\n    if (index !== -1) {\n      state[index] = action.payload;\n    }\n  },\n},\n<\/code><\/pre>\n<h2 id=\"caveats\">Caveats<\/h2>\n<p>There are some caveats like using <code>current()<\/code> when you want to look at the state.<\/p>\n<h3 id=\"replacing-the-entire-state\">Replacing the entire state<\/h3>\n<p>As in the case of removeTodo, you cannot completely replace <code>state<\/code>.<\/p>\n<pre><code class=\"language-ts\">\/\/ \u26a0\ufe0f\u26a0\ufe0f DOES NOT WORK \u26a0\ufe0f\u26a0\ufe0f\nremoveTodo: (state, action: PayloadAction&lt;number&gt;) =&gt; {\n  \/\/ This could only work if state would be \"by ref\"\n  \/\/ which JavaScript doesn't have\n  state = state.filter(todo =&gt; todo.id !== action.payload);\n}\n\n\/\/ \u2714\ufe0f\u2714\ufe0f DOES WORK \u2714\ufe0f\u2714\ufe0f\nremoveTodo: (state, action: PayloadAction&lt;number&gt;) =&gt; {\n  return state.filter(todo =&gt; todo.id !== action.payload);\n}\n<\/code><\/pre>\n<h3 id=\"reducers-without-curly-braces\">Reducers without curly braces<\/h3>\n<p>Use <code>void<\/code> for your one-liner reducers:<\/p>\n<pre><code class=\"language-ts\">\/\/ \u26a0\ufe0f\u26a0\ufe0f TypeScript ERROR \u26a0\ufe0f\u26a0\ufe0f\n\/\/ [].push() returns a number which is not a valid new state\naddTodo: (state, action: PayloadAction&lt;Todo&gt;) =&gt; state.push(action.payload)\n\n\/\/ \u2714\ufe0f\u2714\ufe0f BOTH WORK \u2714\ufe0f\u2714\ufe0f\naddTodo: (state, action: PayloadAction&lt;Todo&gt;) =&gt; void state.push(action.payload)\naddTodo: (state, action: PayloadAction&lt;Todo&gt;) =&gt; {\n  state.push(action.payload);\n}\n<\/code><\/pre>\n<h3 id=\"primitives-cannot-be-wrapped\">Primitives cannot be wrapped<\/h3>\n<p>If you extract a primitive value (number, bool, string) from the state and then manipulate it, you\u2019re no longer working with a WritableDraft and are just mutating the local variable.<\/p>\n<pre><code class=\"language-ts\">addMessage: (state, action: PayloadAction&lt;any&gt;) =&gt; {\n  \/\/ \u26a0\ufe0f\u26a0\ufe0f DOES NOT WORK \u26a0\ufe0f\u26a0\ufe0f\n  let { newMessagesCount } = state;\n  newMessagesCount++;\n\n  \/\/ \u2714\ufe0f\u2714\ufe0f DOES WORK \u2714\ufe0f\u2714\ufe0f\n  state.newMessagesCount++;\n}\n<\/code><\/pre>\n<h1 id=\"under-the-hood\">Under the hood<\/h1>\n<p>Immer\u2019s bread and butter is the <code>produce(baseState, recipe)<\/code> function. It takes your <code>baseState<\/code>, wraps it in a <code>WritableDraft<\/code> and executes a <code>recipe<\/code> against it, which means calling your reducer with the dispatched action. It then creates the new state by re-applying the steps done in the recipe to the baseState, but in a non-mutating way.<\/p>\n<p>The ReduxJS\/Toolkit reducers have already called <code>produce<\/code>, so this has been abstracted away for us.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/itenium-be.github.io\/blog-posts-new\/assets\/blog-images\/reduxjs-toolkit-immer-flow.png\" alt=\"The immer flow\" title=\"The immer flow\" class=\"img-responsive\" \/><\/p>\n<h2 id=\"produce-example\">Produce Example<\/h2>\n<p>Small code example to illustrate how <code>produce<\/code> works. In the accompanying git repository, the code is a bit more involved and includes tests to prove that only the objects that changed actually have different references!<\/p>\n<pre><code class=\"language-ts\">import { produce } from \"immer\";\n\ninterface UpdatePizzaTopping {\n  type: \"\ud83c\udf44\" | \"\ud83c\udf36\ufe0f\" | \"\ud83e\udd53\";\n  doubleIt: boolean;\n}\n\nconst reducerTastyPizza = (baseState: PizzaState, action: UpdatePizzaTopping) =&gt; {\n  const recipe = (draft: WritableDraft&lt;PizzaState&gt;) =&gt; {\n    const topping = draft.toppings.find(topping =&gt; topping.type === action.type);\n    if (!topping)\n      return;\n\n    topping.doubleIt = action.doubleIt;\n  }\n\n  const newState: PizzaState = produce(baseState, recipe);\n  return newState;\n}\n<\/code><\/pre>\n<p>Which you would typically just write like so:<\/p>\n<pre><code class=\"language-ts\">const reducerTastyPizza = (state: PizzaState, action: UpdatePizzaTopping) =&gt; {\n  return produce(state, draft =&gt; { \/* do stuff here! *\/ });\n}\n<\/code><\/pre>\n<h1 id=\"outside-of-reduxjstoolkit\">Outside of ReduxJS\/Toolkit<\/h1>\n<p>Immer can be useful even if you are not using ReduxJS\/Toolkit. Or just outside your reducers \u2013 you already have the dependency anyway!<\/p>\n<p>In a form Component, you might have something like<\/p>\n<pre><code class=\"language-ts\">const [title, setTitle] = useState(\"\");\nconst [text, setText] = useState(\"\");\n\/\/ If you've got 10 properties, then 10x useState???\n<\/code><\/pre>\n<h2 id=\"nimmer\">Nimmer!<\/h2>\n<pre><code class=\"language-ts\">import { produce } from \"immer\";\n\nconst TodoAdd = () =&gt; {\n  const [todo, setTodo] = useState&lt;Todo&gt;(produce(() =&gt; ({\n    title: '',\n    text: '',\n  })));\n\n  return (\n    &lt;&gt;\n      &lt;input\n        value={todo.title}\n        onChange={e =&gt; setTodo(produce(todo, draft =&gt; {draft.title = e.target.value}))}\n      \/&gt;\n      &lt;textarea\n        value={todo.text}\n        onChange={e =&gt; setTodo(produce(todo, draft =&gt; {draft.text = e.target.value}))}\n      \/&gt;\n    &lt;\/&gt;\n  );\n}\n<\/code><\/pre>\n<p>Uhoh, <code>setTodo(produce(todo, draft...))<\/code>, might as well stick with my 10x useState!<\/p>\n<p>You can make this a lot nicer with a helper function, while still keeping everything type-safe:<\/p>\n<pre><code class=\"language-ts\">const updateTodo = &lt;K extends keyof Todo&gt;(key: K, value: Todo[K]) =&gt; {\n  setTodo(produce(todo, draft =&gt; {\n    draft[key] = value;\n  }));\n}\n\nreturn (\n  &lt;input value={todo.title} onChange={e =&gt; updateTodo('title', e.target.value)} \/&gt;\n)\n<\/code><\/pre>\n<h2 id=\"useimmer\">useImmer<\/h2>\n<p>But of course there is a package for that!<\/p>\n<p><a href=\"https:\/\/github.com\/immerjs\/use-immer\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/immerjs\/use-immer.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/immerjs\/use-immer\">immerjs\/use-immer<\/a>: Use immer to drive state with a React hooks<\/p>\n<pre><code class=\"language-ts\">import { useImmer } from \"use-immer\";\n\nconst TodoAdd = () =&gt; {\n  const [todo, setTodo] = useImmer&lt;Todo&gt;({\n    title: '',\n    text: '',\n  });\n\n  return (\n    &lt;&gt;\n      &lt;input\n        value={todo.title}\n        onChange={e =&gt; setTodo(draft =&gt; draft.title = e.target.value)}\n      \/&gt;\n      &lt;textarea\n        value={todo.text}\n        onChange={e =&gt; setTodo(draft =&gt; draft.text = e.target.value)}\n      \/&gt;\n    &lt;\/&gt;\n  );\n}\n<\/code><\/pre>\n<p><code>use-immer<\/code> also exposes <code>useImmerReducer<\/code> to replace your <code>useReducer<\/code>s.<\/p>\n<h1>Also in this series<\/h1>\n<ul>\n<li>Part 1: <a href=\"\/javascript\/reduxjs-toolkit\/\">ReduxJS\/Toolkit<\/a><\/li>\n<li>This Part: ReduxJS\/Toolkit: Immer<\/li>\n<li>Part 3: <a href=\"\/javascript\/reduxjs-toolkit-createslice\/\">ReduxJS\/Toolkit: createSlice and configureStore<\/a><\/li>\n<li>Part 4: <a href=\"\/javascript\/reduxjs-toolkit-createasyncthunk\/\">ReduxJS\/Toolkit: createAsyncThunk<\/a><\/li>\n<li>Part 5: <a href=\"\/javascript\/reduxjs-toolkit-typescript\/\">ReduxJS\/Toolkit: TypeScript<\/a><\/li>\n<li>Part 6: <a href=\"\/javascript\/reduxjs-toolkit-createselector\/\">ReduxJS\/Toolkit: createSelector<\/a><\/li>\n<\/ul>\n<h1>Extras<\/h1>\n<p><b>Stuff that came into being during the making of this post<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/itenium-be\/reduxjs-toolkit\">The &#8216;Mythical Zoos&#8217; example code and the talk pptx<\/a><\/li>\n<\/ul>\n<h1> Package Versions <i class=\"fa fa-info-circle\" style=\"float: right; color: cornflowerblue; font-size: 28px\" title=\"Package versions used for this post and in the accompanying code on Github\"><\/i><\/h1>\n<div><a href=\"https:\/\/github.com\/immerjs\/immer\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/immerjs\/immer.svg?style=social&#038;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/immerjs\/immer\">immerjs\/immer<\/a>: v9.0.21 <\/div>\n","protected":false},"excerpt":{"rendered":"<p><a href=\"https:\/\/github.com\/immerjs\/immer\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/immerjs\/immer.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/immerjs\/immer\">immerjs\/immer<\/a>: Create the next immutable state by mutating the current one<\/p>\n<p>Immer is the solution the ReduxJS\/Toolkit has adopted to enforce pure reducers: it allows you to write reducers while (almost) not having to think about immutability anymore!<\/p>\n<p>Awards!? \ud83c\udfc6\ud83e\udd47<\/p>\n<ul>\n<li>React: <a href=\"https:\/\/osawards.com\/react\/2019\">Breakthrough of the year 2019<\/a><\/li>\n<li>JavaScript: <a href=\"https:\/\/osawards.com\/javascript\/2019\">Most impactful contribution 2019<\/a><\/li>\n<\/ul>\n","protected":false},"author":1,"featured_media":1969,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[3],"tags":[22,6],"class_list":["post-1367","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","tag-react","tag-tutorial"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>ReduxJS\/Toolkit: Immer - Itenium<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ReduxJS\/Toolkit: Immer - Itenium\" \/>\n<meta property=\"og:description\" content=\"immerjs\/immer: Create the next immutable state by mutating the current oneImmer is the solution the ReduxJS\/Toolkit has adopted to enforce pure reducers: it allows you to write reducers while (almost) not having to think about immutability anymore!Awards!? \ud83c\udfc6\ud83e\udd47React: Breakthrough of the year 2019JavaScript: Most impactful contribution 2019\" \/>\n<meta property=\"og:url\" content=\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/\" \/>\n<meta property=\"og:site_name\" content=\"Itenium\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-06T23:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-28T12:31:41+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png\" \/>\n\t<meta property=\"og:image:width\" content=\"360\" \/>\n\t<meta property=\"og:image:height\" content=\"300\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Usdevelop\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Usdevelop\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/\",\"name\":\"ReduxJS\/Toolkit: Immer - Itenium\",\"isPartOf\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png\",\"datePublished\":\"2025-02-06T23:00:00+00:00\",\"dateModified\":\"2025-11-28T12:31:41+00:00\",\"author\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\"},\"breadcrumb\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png\",\"contentUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png\",\"width\":360,\"height\":300,\"caption\":\"A futuristic glass cube encapsulating dynamic swirling data streams, but the cube itself remains frozen in time. The background is a digital environment with blue and white neon elements, symbolizing immutable state updates in JavaScript\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/demo.sidekick.be\/itenium\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ReduxJS\/Toolkit: Immer\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/\",\"name\":\"Itenium\",\"description\":\"We build software. We build careers.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\",\"name\":\"Usdevelop\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"caption\":\"Usdevelop\"},\"sameAs\":[\"https:\/\/demo.sidekick.be\/itenium\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ReduxJS\/Toolkit: Immer - Itenium","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":"ReduxJS\/Toolkit: Immer - Itenium","og_description":"immerjs\/immer: Create the next immutable state by mutating the current oneImmer is the solution the ReduxJS\/Toolkit has adopted to enforce pure reducers: it allows you to write reducers while (almost) not having to think about immutability anymore!Awards!? \ud83c\udfc6\ud83e\udd47React: Breakthrough of the year 2019JavaScript: Most impactful contribution 2019","og_url":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/","og_site_name":"Itenium","article_published_time":"2025-02-06T23:00:00+00:00","article_modified_time":"2025-11-28T12:31:41+00:00","og_image":[{"width":360,"height":300,"url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png","type":"image\/png"}],"author":"Usdevelop","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Usdevelop","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/","url":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/","name":"ReduxJS\/Toolkit: Immer - Itenium","isPartOf":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#website"},"primaryImageOfPage":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage"},"image":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage"},"thumbnailUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png","datePublished":"2025-02-06T23:00:00+00:00","dateModified":"2025-11-28T12:31:41+00:00","author":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022"},"breadcrumb":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#primaryimage","url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png","contentUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/reduxjs-toolkit-immer.png","width":360,"height":300,"caption":"A futuristic glass cube encapsulating dynamic swirling data streams, but the cube itself remains frozen in time. The background is a digital environment with blue and white neon elements, symbolizing immutable state updates in JavaScript"},{"@type":"BreadcrumbList","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/javascript\/reduxjs-toolkit-immer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/demo.sidekick.be\/itenium\/"},{"@type":"ListItem","position":2,"name":"ReduxJS\/Toolkit: Immer"}]},{"@type":"WebSite","@id":"https:\/\/demo.sidekick.be\/itenium\/#website","url":"https:\/\/demo.sidekick.be\/itenium\/","name":"Itenium","description":"We build software. We build careers.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022","name":"Usdevelop","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","caption":"Usdevelop"},"sameAs":["https:\/\/demo.sidekick.be\/itenium"]}]}},"_links":{"self":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1367","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/comments?post=1367"}],"version-history":[{"count":2,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1367\/revisions"}],"predecessor-version":[{"id":2149,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1367\/revisions\/2149"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media\/1969"}],"wp:attachment":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media?parent=1367"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/categories?post=1367"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/tags?post=1367"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}