Coding

ReactJS / Redux Tutorial – #4 Working with State and Immutability

  • 00:00:00 in the last video we ended up with our
  • 00:00:03 basics redox flow here where we had an
  • 00:00:07 initial state of a number of one and
  • 00:00:09 then we just patched some actions to add
  • 00:00:12 and subtract values to that value and as
  • 00:00:16 you can see this works fine now
  • 00:00:18 typically your application doesn't use a
  • 00:00:22 number as a state it might use an object
  • 00:00:27 instead and you might want to change
  • 00:00:30 your values in that object it also might
  • 00:00:34 use arrays and since objects and arrays
  • 00:00:37 are reference types which means they are
  • 00:00:41 no primitives which get copied but
  • 00:00:44 instead have one place in memory and
  • 00:00:47 then pointers pointing to that place we
  • 00:00:51 want to make sure that we're changing
  • 00:00:52 the state in an immutable way which
  • 00:00:55 means we're always taking the old state
  • 00:00:58 make a copy edit this copy and return a
  • 00:01:01 new state so that the old state stays
  • 00:01:03 untouched let's see how we do that
  • 00:01:06 I'll make some changes here I'll create
  • 00:01:08 a new constant which I'll name initial
  • 00:01:11 state and this will be a JavaScript
  • 00:01:15 object this initial state here well
  • 00:01:19 let's say have a result of 1 so before
  • 00:01:23 we had this initial state of 1 now this
  • 00:01:25 is one property in the initial state
  • 00:01:27 object and then it has the last values
  • 00:01:31 array which is empty at the beginning
  • 00:01:34 like this next in my reducer here I can
  • 00:01:40 use the es6 addition of default values
  • 00:01:45 or default parameters in methods to set
  • 00:01:49 my state equal to initial state in the
  • 00:01:52 case that no state is added or is sent
  • 00:01:56 to reducer so once we dispatch actions
  • 00:02:00 read acts will automatically pass the
  • 00:02:02 current state to the reducer so the
  • 00:02:05 initial state is then ignored but if we
  • 00:02:07 first set up our store and we don't have
  • 00:02:12 a state there
  • 00:02:14 or yet then the initial state object
  • 00:02:17 here is used to initialize the state
  • 00:02:19 that's just some ESX work and if you're
  • 00:02:22 not sure how all of this works well I
  • 00:02:25 got a es6 video on this channel and I
  • 00:02:28 even got a es6 course on udemy so you
  • 00:02:30 might want to check these out if you
  • 00:02:32 want to learn more links in the
  • 00:02:34 description so initial state is setup
  • 00:02:37 here and since I'm setting it up here I
  • 00:02:39 can remove the second argument in the
  • 00:02:42 create store method so now I'm only
  • 00:02:44 passing the reducer because the reducer
  • 00:02:47 on its own handles the initializes
  • 00:02:49 initialization of the state here so far
  • 00:02:53 so good we change the state to be an
  • 00:02:56 object and we change the way we
  • 00:02:58 initialize the state now with that
  • 00:03:01 I want to use this object to then change
  • 00:03:05 the state in the switch statement here
  • 00:03:07 whenever we dispatch an action now I'll
  • 00:03:09 leave the action the way we create them
  • 00:03:12 all the actions remain the same we still
  • 00:03:15 only pass values as Paulo payloads these
  • 00:03:18 are not adjusted to objects there is no
  • 00:03:20 need to do so because we're still only
  • 00:03:22 adding 100 we're not adding an object
  • 00:03:25 with 100 that's important to realize the
  • 00:03:28 payload here is always just a value you
  • 00:03:31 want to change in the reducer is the
  • 00:03:34 place where you then have to figure out
  • 00:03:36 how to correctly change the state so how
  • 00:03:39 would we correctly change the state for
  • 00:03:41 the add action here well we take the
  • 00:03:44 state object here and we could do the
  • 00:03:46 following thing we could simply stay say
  • 00:03:50 that state result is equal to action
  • 00:03:59 payload or is equal to old State result
  • 00:04:04 plus action dot payload now if I save
  • 00:04:07 this and go back to the application you
  • 00:04:09 see that my store is updated do result
  • 00:04:11 US 101 123 and then not a number because
  • 00:04:15 the subtract action here hasn't been
  • 00:04:18 updated yet so this looks fine ignore
  • 00:04:22 that the last values is not updated
  • 00:04:24 because I'm not implementing this yet so
  • 00:04:27 the result
  • 00:04:28 is updated but here's an interesting
  • 00:04:30 thing even though we see result 101 here
  • 00:04:35 if we expand the object we see result
  • 00:04:38 123 and the reason is because we're not
  • 00:04:43 doing this in an immutable way I'm
  • 00:04:45 simply taking the old property and
  • 00:04:48 changing the value there for all old
  • 00:04:52 objects or the state in the older
  • 00:04:55 objects here like the first action here
  • 00:04:58 is also changed because it's one of the
  • 00:05:00 same object it's the same place in the
  • 00:05:02 memory and hence we don't have an
  • 00:05:05 immutable approach here now why is an
  • 00:05:08 immutable approach better because
  • 00:05:11 currently we get no way of getting back
  • 00:05:15 to an older state we can't see how our
  • 00:05:18 state changed throughout the application
  • 00:05:20 and therefore we're back in the world
  • 00:05:23 where handling the state is a bit more
  • 00:05:26 complicated because it's always hard to
  • 00:05:28 know what the current state of the
  • 00:05:30 application is so a better way is to not
  • 00:05:34 do it this way not directly manipulate
  • 00:05:37 the property but instead create a new
  • 00:05:42 state here I do this by creating a new
  • 00:05:46 JavaScript object so state is now a new
  • 00:05:48 JavaScript object it's no longer the
  • 00:05:51 state we're passing here it's a new
  • 00:05:53 JavaScript object and then this
  • 00:05:55 JavaScript object I want to use all the
  • 00:05:58 properties of the old state now a quick
  • 00:06:02 and easy way in es6 to get all the
  • 00:06:06 properties of an object and add it as
  • 00:06:08 properties to a new object exactly what
  • 00:06:11 I want to do here is to use the spread
  • 00:06:15 operator the spread operator are free
  • 00:06:18 dots and here I take the state and this
  • 00:06:22 may basically tells JavaScript or es6
  • 00:06:26 give me all the properties of the state
  • 00:06:29 object this object here which has a
  • 00:06:32 result and the last value property and
  • 00:06:34 add them as properties to this new
  • 00:06:37 object so in this specific case here
  • 00:06:41 that
  • 00:06:42 exactly the same as if I would have
  • 00:06:44 written state result and then state last
  • 00:06:50 values but of course I would have needed
  • 00:06:52 to also set is equal to result and then
  • 00:06:56 here two last values like this now
  • 00:07:00 that's much longer and the big problem
  • 00:07:02 of course is if we change to sit here we
  • 00:07:05 have to change it all over the place
  • 00:07:07 here so that is a much better way to
  • 00:07:10 achieve the same now of course I don't
  • 00:07:12 want to simply get the old properties I
  • 00:07:15 want to change the result property that
  • 00:07:18 is why I now add result and set it equal
  • 00:07:22 to be State result this again is the old
  • 00:07:27 state here so the result of the old
  • 00:07:32 state and add my payload to it action
  • 00:07:36 payload that is why I simply pass the
  • 00:07:40 value here as a payload and not some
  • 00:07:43 kind of object because the dispatching
  • 00:07:45 here or the action is not responsible
  • 00:07:47 for passing the finished
  • 00:07:50 new state object that's the top of the
  • 00:07:52 reducer so the reducer always works with
  • 00:07:55 the payloads which are types like
  • 00:07:58 numbers strings may be objects of course
  • 00:08:01 but never the new state so now I set
  • 00:08:06 this or I created this new value
  • 00:08:08 consisting of the old result property
  • 00:08:11 and the payload of my action and I'm
  • 00:08:15 setting this to the result property now
  • 00:08:18 if you watch carefully you might think
  • 00:08:21 well I'm spreading my old state object
  • 00:08:25 here this old state object has a result
  • 00:08:28 and has lost values and now I'm setting
  • 00:08:31 result again so now I kind of created
  • 00:08:34 something like this result would be
  • 00:08:38 State result lost values would be State
  • 00:08:43 lost values so I have result twice and
  • 00:08:47 that exactly is what helps but that's no
  • 00:08:51 problem because the latter result
  • 00:08:54 property
  • 00:08:55 so the last one I specify here overrides
  • 00:08:58 all prior properties with the same name
  • 00:09:01 which is the behavior I want I first
  • 00:09:03 spread all the properties of my old
  • 00:09:05 state and then I override the ones I
  • 00:09:08 want to override now as you can see I'm
  • 00:09:11 not touching the last values yet and if
  • 00:09:13 my initial state would have much more
  • 00:09:15 values some of them which are never
  • 00:09:18 touched by an add action well then these
  • 00:09:21 properties would never be overwritten in
  • 00:09:23 the turn off this add action so if I
  • 00:09:27 save this reload my application here you
  • 00:09:30 now see store updated with results 101
  • 00:09:34 and 123 but now if I expand them you see
  • 00:09:38 that the value actually isn't changed
  • 00:09:41 because a brand new object is created
  • 00:09:43 all the time and we don't see the old
  • 00:09:47 object being overwritten instead as
  • 00:09:49 happened before now with that let's also
  • 00:09:53 implement this for the subtraction here
  • 00:09:55 so let's copy this simply subtract the
  • 00:09:59 payload save this now you can see the
  • 00:10:02 values being changed here again the
  • 00:10:06 result and the old objects is not
  • 00:10:08 touched and with that we get an
  • 00:10:13 immutable way of using strings eggs of
  • 00:10:18 using objects could be of using objects
  • 00:10:21 as our estate now we also have this last
  • 00:10:25 values array here so let's say in this
  • 00:10:29 last values array here I want to store
  • 00:10:31 well the value that was used in this
  • 00:10:35 action so I could use my newly created
  • 00:10:37 state remember I'm creating a new state
  • 00:10:40 here and set last values or use this
  • 00:10:43 last values here to push action dot
  • 00:10:46 payload payload like this and I'll also
  • 00:10:51 take this and do the same for this
  • 00:10:53 abstract action I'll save this reload my
  • 00:10:56 application you see everything works
  • 00:10:59 here you see the array here is growing
  • 00:11:01 we have an array where we have 122 and
  • 00:11:05 80 Oh
  • 00:11:08 again we have the same problem as before
  • 00:11:11 even though we get the information that
  • 00:11:14 this area has one element it actually
  • 00:11:16 has free because it was changed after
  • 00:11:20 the time this object was created because
  • 00:11:24 I'm not doing this in an immutable way
  • 00:11:26 I'm simply taking my state and then I
  • 00:11:29 push a new value here but since this
  • 00:11:33 last values array is the one we spread
  • 00:11:37 from the old state we're always using
  • 00:11:39 the same array which is stored somewhere
  • 00:11:41 in memory we're not recreating it so
  • 00:11:44 whilst the object the state object is
  • 00:11:46 handled in an immutable way the property
  • 00:11:50 this last values array here is not and
  • 00:11:54 this certainly is not the way we want to
  • 00:11:56 do it so we want to do this in an
  • 00:11:58 immutable way – and the way to do it is
  • 00:12:02 to overwrite the last values property
  • 00:12:05 just like we overwrite result here and
  • 00:12:08 then set this to be equal to you a new
  • 00:12:12 array where again use the spread
  • 00:12:15 operator to spread out the old last
  • 00:12:18 values array spread operators can be
  • 00:12:20 used on both arrays and objects to
  • 00:12:24 either fetch out all the properties in
  • 00:12:26 the case of objects or all the elements
  • 00:12:28 in the case of arrays so state last
  • 00:12:32 values fills this array with all the old
  • 00:12:36 values and then I add a new value action
  • 00:12:40 payload so that's kind of pushing in an
  • 00:12:44 immutable way and I'll do the same in
  • 00:12:46 the subtract case now important thing in
  • 00:12:50 this case here I could of course remove
  • 00:12:52 this spreading of my state object
  • 00:12:54 because I'm overwriting all the
  • 00:12:56 properties that exists anyways but I'm
  • 00:12:59 leaving it here because in reality you
  • 00:13:03 will oftentimes have a case where your
  • 00:13:06 action doesn't change all the properties
  • 00:13:08 of your state we might have an
  • 00:13:10 additional property like let's say
  • 00:13:12 username here set it equal to max and
  • 00:13:15 this is never touched so therefore we
  • 00:13:18 want to still spread the state and only
  • 00:13:20 change the values we need to
  • 00:13:22 change now if I save this and reload my
  • 00:13:25 application again well we see user name
  • 00:13:28 is always the same the array contains
  • 00:13:30 one two and then three elements which is
  • 00:13:33 of course the case in the last object
  • 00:13:35 but now the first object is also correct
  • 00:13:38 and at this point of time where we
  • 00:13:40 changed the state for the first time we
  • 00:13:43 only have the first value that was added
  • 00:13:46 100 in the second place here we have 122
  • 00:13:51 and then the last time we dispatch in
  • 00:13:54 action we get 122 and then 80 and the
  • 00:13:58 result has changed appropriately too so
  • 00:14:01 that is how you handle objects and
  • 00:14:03 arrays in an immutable way in your Redux
  • 00:14:08 state and that is a key thing to know
  • 00:14:11 and to use to make a predictable state
  • 00:14:15 or to have a predictable state in your
  • 00:14:17 application