In React, useState and useReducer are commonly used for managing state. While useImmer is a popular alternative to useState, in this article, we wi...
For further actions, you may consider blocking this person and/or reporting abuse
I gotta say, 'useImmer' looks way easier to use than 'useReducer'. Nice job on the article, dude!
Do keep in mind that people tend to over-complicate useReducer by writing redux style reducer functions with switch statements. If you use the most simple reducer function, it works exactly like useImmer:
It's definitely a more readable approach of using useReducer. You have also used useCallback to avoid unnecessary re-renders. However, with useImmer, useCallback is not necessary when you are not passing the state as props, because Immer uses a proxy object that keeps track of changes and only applies the changes when necessary. Additionally, with useImmer, you can write code in a mutable way.
Apologies, I realize I made it sound like there is no use for useImmer, this was not my intention! Immer and useImmer hook are great. I just wanted to point out that people usually project all kinds of unnecessary redux madness onto the useReducer hook π
Thank you for pointing that out because people tend to do 'over-kill'
Thank you. π
I don't agree it's better. Also it's not 'more javascript-like' if it looks like mutable JavaScript code, but it's not. Details of what is going on are hidden from the coder. The fact is that you can avoid mutations explicitly in just few more keystrokes, which would be
*more readable
*more performant - you just return new object, instead of watching object for changes (however immer does it) and then returning new object anyway (for react to update ui)
*saving yourself and the planet few kb'sΓtraffic of useless code transfer
*saving the planet again by less runtime computation = clientsΓruningtime less energy
*saving your fellow/future collaborators from extra complexity and upkeep of extra dependency
Totally bad idea to use it in my opinion.
Thank you for sharing your opinion. I appreciate your feedback. However, I don't think useImmer is less performant than returning a new object explicitly. Because it only creates new objects for the parts of the state that have changed and reuses the rest. Also, immer uses structural sharing to optimize the comparison of the old and new state, which can improve the performance of React's rendering. You can read more about these features and benefits of immer in their documentation. Moreover, immer is very popular and widely used in some of the most popular and widely used state management libraries for React, such as redux toolkit and zustand. This shows that immer is a reliable and well-supported library that has been adopted by many developers and projects in the JavaScript community. Of course, you are free to use whatever tool or technique works best for you and your project.
I have never seen any use case for an extensive unpersistent state client-side. Local data should be stored in a cache and ui-related state (dropdowns etc ;p) is usually super simple and working perfectly with built-in 'useState'.
With each library we add to overall complexity and become less 'portable'
Removing such a library in case of compatibility problems, that may arise in the future, would be a nightmare, because this impacts ALOT.
I mean, this is very bold decision in a project, if we don't have performance issues, I'd say it's better to stick to standard. If you have, then moving data out of state should help :)
Thanks for a well written introduction to
useImmer
. I wasn't aware of this library before. I've looked through the comments and see that there is some disagreement over whether or not this is a good library to use as opposed touseReducer
and the arguments are worth considering. This post has given me some things to think about, but I might give it a try to see what I think of it.Thank you for your feedback. You can certainly give
useImmer
a try, especially for local state management and state of reusable component.Great article. I'm personally not a fan of mutable state.
How does useImmer handle batching? For example, updating a cart object field just after another update (inside the same function). Would it re-render two times or wait for the function to finish?
Edit: it seems like I was wrong, I wasn't introduced to Immer before so I thought it was managing mutable state, when in fact it allows you to manage immutable state by modifying only a draft version of your object:
With Immer, this process is more straightforward. We can leverage the produce function, which takes as first argument the state we want to start from, and as second argument we pass a function, called the recipe, that is passed a draft to which we can apply straightforward mutations. Those mutations are recorded and used to produce the next state once the recipe is done. produce will take care of all the necessary copying, and protect against future accidental modifications as well by freezing the data.
Thanks for your comment. You are right about Immer's approach to state management, it allows for straightforward mutations while maintaining immutability.
immer
is possibly the worst thing that happened to the JavaScript world recently.Thanks for sharing your opinion. But I don't know why would think that
immer
is the worst thing that happened to the JavaScript world recently. What specific issues have you encountered or what do you think are the drawbacks of usingimmer
?I would guess that updating the state in a "mutable" manner would hide bugs where you accidentally mutate the state without meaning to. Where with reducer you would get an error or warning that you mutated the state.
That's a good point but it is also possible to accidentally update the state immutably in a reducer, especially with complex or nested state objects.
On the other hand, Immer can help make your code more readable and make it harder to write incorrect code.
Ok, then I have no idea why he would say that immer is the worst. Maybe he is just trolling...
immer
encourages procedural style of programming. It's a regression from the more functional style of updating state.If you ever used lenses in Haskell, or even those offered by
ramda
, you'll know how big of a regressionimmer
is.I think we're all extremely eager now to know why that is so ... care to explain?
It simply encourages a more procedural and mutable style of programming.
It also forces you to hold several pieces of state in your mind.
Compare this with lenses.
I think it simply allows people to write the code they would naturally write - the kind of "immutable" code you'd write in more complicated scenarios is anything but natural ... and the resulting code is more concise, easier to understand, and easier to maintain - only pluses in my book.
(I don't see how it forces you to "keep more pieces of state in your mind", when all it does is let you write the same piece of code, accomplishing the same thing, but more concisely - and of course the underlying assumption is that you have sufficient comprehension of how this works so that you know that under the hood you're still in fact writing immutable code - it's just a tool to accomplish that more simply)
I'm not sure what you mean by natural way of writing code: or if that at all exists?
I'd disagree that the way
immer
allows state updates is in anyway concise.It forces to think about different pieces of state individually; thus keeping several things in mind. On the other hand, a functional programming style allows you to think of state as data pipeline: one piece a time.
maybe yes, maybe no, at this point it's not really tangible
What stops someone from using UpdateCart outside of the actions?
Great work on this article!!!!
Actually, it's not possible to stop someone from updating the state outside the defined actions. However, this is not unique to
useImmer
. I learned from a comment in this article that it's possible to update the state withuseReducer
too without defining actions. If you look through the comments, you'll find the following code:So, ultimately it is a matter of personal preference whether to only use defined actions for a more structured approach or not.
Thanks for the reference!
I can't understand all sir sorry all I know is call and text thank I'm tired
Thank you for your feedback. Actually, I didn't provide any syntax for both the useState and useReducer hooks, assuming that readers are already familiar with them. I am not sure, but I am guessing that if someone is not completely familiar with these hooks, specially useReducer, it can be challenging to understand the comparison that I have made with useImmer.
Well explained and good demo.
Thank you. π
useImmer seems the best way to go
Never been a big fan of useReducer. Will be looking at this for my projects. Cheers.
This works when state and the component that uses it, are both defined in the same file.
How do you work when you want to share state among many components?
For global state, we can use
createContext
anduseContext
to share the state among other components.Suppose we are using local state in a component or creating a reusable component. The component is becoming large, and so we have divided it into multiple child components. Now, in the parent component, we will create the state with
useImmer
. Then, we will share the state with the child components through props.Nice article, but what do you think about preact/signals-react?
Thanks for asking! Actually, I haven't had the chance to try
preact/signals-react
yet, but I have plans to explore it soon.I don't see any crucial benefits why I'd use useImmer yet, useReducer can perform same tasks with flexibility, mutability & readability Im looking for, maybe some devs violate the use of useReducer, also keep in mind that we're adding extra kilobytes to our bundle which may not be worth it and instead use built in ones as appropriate.
If bundle size is a concern, you can certainly skip using the Immer library or useImmer hook. However, without using Immer, you'll need to update state in an immutable way, which can make it harder to write and read code. By using useImmer, you can write mutable code which can be more readable and less error-prone.
Additionally, just using useReducer can cause unnecessary re-renders, and you may need to use hooks like useCallback to optimize performance. But with useImmer, if you are not passing state as props, you don't need to worry about re-renders.
Also if you are dealing with large data in react application when you might want to manipulate and populate data, then you might want to consider useImmer for mutation without getting into unpredictable data presentation.
It looks both useReducer and useImmer goes against type inference. For a typescript project, I would recommend using custom hooks with useState and useCallbacks.
Thanks for your feedback. But Iβm afraid thatβs not correct. Both useImmer and useReducer support TypeScript.
Why? This is why I hate web development. Instead of having a simple and clean way to update the state why don't we use this new thing and make it all way less safe and write error prone code. As I know I am a human being I am grateful when patterns help me prevent shooting myself in the foot. But noooo, let's get a bazooka and shoot our selves in the head because switch statements are hard to read. And I ask, according to who are switch statements bad?
There is nothing wrong with switch statements and reducers. Many developers prefer them, while many others do not. You can certainly use reducers and switch statements. However, if you want to write mutable code, you can try useImmerReducer, where you write code exactly like useReducer, but can change the state in a mutable way.