Reputation: 27713
I know using Immutable is a great way to deeply update React state, but I was wondering if there are any drawbacks I'm not seeing with this approach:
Assuming this.state.members
has the shape Array<MemberType>
where MemberType
is { userId: String, role: String }
.
If the user changes a user's role, the following method is executed:
changeMemberRole = (userId, event, key, value) => {
const memberIndex = _findIndex(this.state.members,
(member) => member.userId === userId);
if (memberIndex >= 0) {
const newMembers = [...this.state.members];
newMembers[memberIndex].role = value;
this.setState({ members: newMembers });
}
};
Would there be any advantage to replacing this with Immutable's setIn
, other than potentially more terse syntax?
Upvotes: 0
Views: 285
Reputation: 5742
The difference between using or not Immutable.js
is, of course, immutability¹ :)
When you declare const newMembers = [...this.state.members]
you're copying an array of references, this is indeed a new array (modifying a direct child by index like 0
,1
,2
is not reflected) but filled with the same object references, so inner/deep changes are shared. This is called a shallow copy.
newMembers
are not so newTherefore any changes to any newMembers
element are also made in the corresponding this.state.members
element. This is fine for your example, no real advantages so far.
Its true benefits are not easily observed in small snippets because it's more about the mindset. Taken from the Immutable.js homepage:
Much of what makes application development difficult is tracking mutation and maintaining state. Developing with immutable data encourages you to think differently about how data flows through your application.
Immutability brings many of the functional paradigm benefits such as avoiding side effects or race conditions since you think of variables as values instead of objects, making it easier to understand their scope and lifecycle and thus minimizing bugs.
One specific advantage for react is to safely check for state changes in shouldComponentUpdate
while when mutating:
// assume this.props.value is { foo: 'bar' }
// assume nextProps.value is { foo: 'bar' },
// but this reference is different to this.props.value
this.props.value !== nextProps.value; // true
When working with objects instead of values nextProps
and this.props.value
will be considered distinct references (unless we perform a deep comparison) and trigger a re-render, which at scale could be really expensive.
¹Unless you're simulating your own immutability, for what I trust Immutable.js
better
Upvotes: 3
Reputation: 3826
You're not copying role, thus if one of your components taking the role as prop (if any) cannot take benefit of pure render optimization (overriding shouldComponentUpdate and detecting whenever props have been actually changed).
But since you can make a copy of the role without immutablejs, there is no any effective difference except that you have to type more (and thus having more opportunities to make a mistake). Which itself is a huge drawback reducing your productivity.
Upvotes: 0
Reputation: 798
From the setIn
docs:
Returns a new Map having set value at this keyPath. If any keys in keyPath do not exist, a new immutable Map will be created at that key.
This is probably not what you are looking for since you may not want to insert a new member with the given role if it does not exist already. This comes down to whether you are able to control the userId
argument passed in the function and verify whether it exists beforehand.
This solution is fine. You can replace it with update instead, if you want to.
Upvotes: -1