Update State in React with Ramda's Evolve

Andy Van Slaars
InstructorAndy Van Slaars
Share this video with your friends

Social Share Links

Send Tweet

In this lesson we'll take a stateful React component and look at how we can refactor our setState calls to use an updater function and then leverage Ramda's evolve function to make our updater function a reusable utility that isn't tied to the React API.

[00:00] We have a simple react component that just has a counter with two buttons that either increase or decrease the count. If we look at our increase and decrease methods, they're both pretty straightforward. Each one calls this.setState, parses an object with count property. That count is based on the old count that's either added to, or subtracted from.

[00:18] When we want to update our state based on a previous value and state, we should parse an update or function to setState rather than an object. I'm going to update this call to setState in increase, and we're going to parse it a function.

[00:30] This function is going to accept two arguments. It's going to get the previous state and props. Then we'll just use an error function here, and I'm going to return this same object. I'm going to change the call here from this.state.count to previousstate.count.

[00:48] I'm also going to add one and return that value. With that update in place, I come up here and my increase still works. Then I can apply the same change to decrease by copying this down. Then I'll just update this operation, three subtraction, and everything still works as expected.

[01:09] I have included the Ramda library, so I'm going to import a couple of utility functions from Ramda. I'm going to say const, and I'm going to use destructuring here. I'm going to get the increase and decrease utility functions off of R.

[01:23] Then I can come down here and I can update this. I can just call increase on previousstae.count. We can get rid of the addition, and I can do the same thing down here using decrease.

[01:40] If I come up here we'll see that everything still works. The other thing I can do is, because we're not actually using props in here, is I can take these calls to props out. The argument still parses, but since we're ignoring it, we don't need to specify it in our signature.

[01:56] Now we're taking in our object. We're grabbing a property off of that. We're performing an operation. Then we're assigning that new value back to the same property name, and returning that object.

[02:07] As luck would have it, Ramda has a function that is perfect for this. It's called evolve, so I'm going to pull that in where I'm pulling in increase and decrease. What I'm going to do here is I'm going to change this to a call to evolve, parsing in count and inc.

[02:27] What's going to happen is evolve is going to return a function that'll accept an object, and it's going to map properties on the parse in object which in our case is previous state, to operation. It will take the count value, run it through increase, and give us back a new object where count has been updated to the new value.

[02:47] In order to get this to work, I just need to call it with the previous state argument. I can come in here and increase still works. Since we're taking our argument to this function and immediately parsing it in to the function that evolve gives us, we can actually cut this down and just parse that state for a partially applied call to evolve.

[03:11] Setstate will still parse in our previous state, evolve will receive that as its second argument. It will apply the changes and return our new value. I can still use my increase and that means I can come down here, and I can apply the same change to decrease.

[03:35] Now, I can increase and I can decrease, all of the nice simple function. Because this has nothing to do with react API, I can actually take this out and move it outside of my component. We'll call it decrease count and then I can just use that function here.

[04:04] That still works, then I can do the same thing for increase. Everything still works. Now I have reusable functions that don't necessarily have anything to do with react. I can test them individually, and I can use them as utilities in any project I want.