Home > Article > Web Front-end > Comparing React Mutative vs. React Immer
Managing state in React apps is an important part of creating dynamic and responsive user interfaces. Traditionally, developers depended on immutable updates, which produce a new copy of the state with the necessary modifications. While this method provides predictability and facilitates debugging, it may have a performance penalty, particularly when dealing with big or complicated data structures.
This article covers two popular React frameworks for handling state; React Mutative and Immer. Both libraries promote immutability, albeit through distinct means.
Mutative's implementation is very comparable to that of Immer, although more robust. Mutative handles data more efficiently than Immer and native reducers. According to the Mutative team, this state management solution makes immutable updates easier. It is approximately two to six times faster than an average handcrafted reducer as well as more than 10 times faster than Immer.
Here are some benefits of Mutative.js:
For example, suppose there is a state object that contains a list. We intend to mark the final item on the list as done and then add a new item:
const state = { list: [ { text: 'Learn JavaScript', done: true }, { text: 'Learn React', done: true }, { text: 'Learn Redux', done: false }, ], };
If we were to use regular immutable data updates, we could write it as follows:
const nextState = { ...state, list: [ ...state.list.slice(0, 2), { ...state.list[2], done: true, }, { text: 'Learn Mutative', done: true }, ], };
But while using the Mutative, we can write it this way:
import { create } from 'mutative'; const nextState = create(state, (draft) => { draft.list[2].done = true; draft.list.push({ text: 'Learn Mutative', done: true }); });
This is the fundamental use of Mutative, which allows us to implement immutable updates more easily.
Immer, which means always in German, is a little package that makes working with an immutable state more convenient. Winner of the 2019 JavaScript Open Source Award for "Most impactful contribution".
These benefits tend to be attained by ensuring you always create an edited copy of an object, array, or map rather than changing any of its properties. This can make writing code very difficult, and it's simple to break such restrictions unintentionally. Through the resolution of these issues, Immer will assist you in adhering to the immutable data approach. Here are some benefits of React Immer:
Immer will report an error if it detects an unintentional mutation.
Immer eliminates the requirement for the customary boilerplate code required when creating deep modifications to immutable objects. Without Immer, object duplicates must be made by hand at all levels. Typically, by doing a large number of... spread operations. When utilizing Immer, modifications are made to a draft object, which records them and creates the appropriate duplicates without changing the original object.
Immer does not require you to master certain APIs or data structures to profit from the paradigm. Immer allows you to access plain JavaScript data structures as well as the well-known mutable JavaScript APIs, all while remaining secure.
below is a simple example for a quick comparison:
const baseState = [ { title: "Learn JavaScript", done: true }, { title: "Try Immer", done: false } ]
Assume we have the previous base state, and we need to update the second todo and add a third one. However, we do not want to change the original baseState and avoid deep cloning (to maintain the first todo).
Without Immer, maintaining immutability requires us to copy every impacted level of the state object.
const nextState = baseState.slice() // shallow clone the array nextState[1] = { // replace element 1... ...nextState[1], // with a shallow clone of element 1 done: true // ...combined with the desired update } //Since nextState was freshly cloned, using push is safe here, // but doing the same thing at any arbitrary time in the future would // violate the immutability principles and introduce a bug! nextState.push({title: "Tweet about it"})
Immer simplifies this process. We can use the generate function, which takes as its first argument the state we wish to start in, and as its second parameter a function called the recipe, which is handed a draft to which we can apply simple modifications. Once the recipe is complete, the mutations are recorded and used to create the next state. generate will handle all of the necessary copying while also protecting the data from future unintentional alterations by freezing it.
import {produce} from "immer" const nextState = produce(baseState, draft => { draft[1].done = true draft.push({title: "Tweet about it"}) })
Are you looking for an Immer with React? You are welcome to go directly to the React + Immer website.
Both Mutative and Immer achieve immutable updates in conceptually similar ways, but with key implementation differences that affect performance. Here's a breakdown:
Secret Sauce: This speed advantage boils down to how each library creates the final immutable state object. Mutative employs a highly optimized algorithm that efficiently builds a new data structure reflecting the changes you made in the draft, prioritizing raw speed.
Immer's Overhead: Immer, on the other hand, utilizes a proxy object to track mutations on the draft state. This approach offers more flexibility but comes with an overhead that can significantly slow things down, particularly when dealing with large datasets. It's like adding an extra step in the process.
Auto-Freeze and the Tradeoff: Immer offers an optional feature called auto-freeze, which helps prevent accidental modifications to the original state. This is great for safety, but it comes at a performance cost. Disabling auto-freeze can bring Immer closer to Mutative's speed, but then you lose the safety net.
Both Mutative and Immer offer an intuitive way to write state updates that appear to mutate the state but ultimately result in immutable updates. However, there are some differences in syntax and potential for errors:
Syntax Mutative: Leverages familiar syntax that resembles traditional mutations. You write code as if you're directly modifying the state object.
Example:
const draft = createDraft(currentState); draft.todos.push({ text: 'Buy milk' }); const newState = commit(draft);
Immer Syntax: Requires using specific Immer functions like produce to wrap your update logic.
Example:
const newState = produce(currentState, draft => { draft.todos.push({ text: 'Buy milk' }); });
Draft escapes occur when you unintentionally modify the original state object instead of the draft copy in libraries like Mutative and Immer.
Mutative: While Mutative's syntax might feel familiar, there's a higher risk of accidentally modifying the original state object (draft escapes). This can happen if you forget to use the commit function to finalize the changes and create the new state. It requires stricter discipline to ensure all modifications go through the draft.
Immer: Immer's syntax explicitly forces you to work within the draft state using functions like produce. This reduces the chance of accidentally modifying the original state, making it inherently safer.
Ultimately, the best choice depends on your specific project requirements and team preferences. Consider trying both libraries on a small project to see which one feels more comfortable for your developers.
The above is the detailed content of Comparing React Mutative vs. React Immer. For more information, please follow other related articles on the PHP Chinese website!