Reputation: 1285
So in my react redux project I am updating an array in my state like this:
this.setState(fromJS(this.state).set(e.target.id, fromJS(this.state).get(e.target.id).push(e.target.value)).toJS());
So just to briefly break it down I am taking a plain js state object turning it immutable then setting the chosen value with a new immutable copy of the array with a new value pushed in.
This seemed to me the only way to do this while making sure I treated the state as an immutable value. I was thinking I can do this:
this.setState(fromJS(this.state).set(e.target.id, this.state[e.target.id].push(e.target.value)).toJS());
The above I assume mutates the original state so I figured I shouldn't use it. Is the method I choose first the most effective way of making sure everything is immutable? I feel like going in and creating a new object again just to get a new array value seems overly complicated so I am wondering if there is a better way to do this.
Again my main focus is on this line: .set(e.target.id, fromJS(this.state).get(e.target.id).push(e.target.value)
where I create an immutable object twice
Upvotes: 1
Views: 838
Reputation: 3020
If you're trying to use immutable.js, you should use it throughout your application, because calling fromJS() and toJS() is bad for performance and require tedious syntax as in your example.
If you like to keep your state as plain JS objects, you should use Object.assign(), Immutability Helpers or other libraries such as immutable-assign created by me. Example usage:
var newState = iassign(this.state,
function(state, context) { return state[context.id]; },
function(prop) { prop.push(e.target.value); return prop; },
{ id: e.target.id }
)
this.setState(newState);
// The first parameter is a function that return the property you need
// to modify in your state. This function must be **pure function**,
// therefore "id" need to be passed in via the context parameter.
//
// The second parameter is a function that modify selected property of your
// state, it doesn't need to be pure, therefore you can access
// "e.target.value" directly
//
// The third parameter is the context used in the first function (pure function)
Upvotes: 0
Reputation: 686
Use the List
structure, docs here :
https://facebook.github.io/immutable-js/docs/#/List
It has a push
operation.
So if you have this.state
containing an array called rayy
(this.state.rayy
), hypothetically you could say:
this.setState({ rayy: this.state.rayy.push(e.target.value)})
That's not going to mutate the original it will just return a new copy and assign it to rayy
.
Remember there are two distinct state
s when working with React together with Redux. There is the Redux state
store which transcends any particular component and should be accessible from anywhere, and then there is the state
specific to individual Components. I use Immutable with Redux but in the components the state
is not immutable. So:
[...][coffeescript here]
# components' state (not immutable)
getInitialState: ->
some_ui_thing: 42
another_ui_thing: 43
# for Redux's connect: (Redux's state is immutable, transition it to JS for props & render stuff
mapStateToProps: (state) ->
state.toJS()
Now inside my components when I call @setState
it's just plain mutable JS, which isn't any kind of issue because these vars are private to the component, and typically relate only to transient UI stuff, so the typical reasons for using Immutables arent compelling.
On the other hand in my reducers (Redux), I might have a function :
do_something = (state, action) ->
state = state.setIn ['rayy'], state.rayy.push(action.payload.whatever)
state
I could make it more explicit:
do_something = (state, action) ->
some_list = state.getIn ['rayy']
some_list = some_list.push action.payload.whatever
state = state.setIn ['rayy'], some_list
return state
Or more terse:
do_something = (state, action) ->
state.setIn ['rayy'], state.rayy.push(action.payload.whatever)
That last (terse) version is possible in coffeescript because it has implicit return.
Upvotes: 1