Update Component State in React With Ramda Lenses

Andy Van Slaars
InstructorAndy Van Slaars

Share this video with your friends

Send Tweet
Published 7 years ago
Updated 5 years ago

In this lesson, we'll refactor a React component to use Ramda lenses to update our component state. We'll create a lens to focus on the property we want to target and use over to apply the existing state value to a utility function and we'll get back a new state that will be reflected in our rendered UI.

[00:00] We have a simple counter component built with React using a couple of the utility functions from the Ramda library to increase and decrease our count when we update our state. If I click the plus button, the number will go up, and if I click minus, it'll go back down.

[00:14] To do this, we're passing an updater function into our set state calls, and that receives the previous state, and then we're using our increase or decrease utility to act on the previous state's count property and assign that back into our new count.

[00:29] I'd like to replace these updater functions using Ramda's lenses, so I'm going to make some updates. I'm going to come up here, and I'm going to start by importing lensProp from Ramda.

[00:37] I'm going to create a lens that allows us to focus on the count property of an object, so I'll define that as count L, and we're just going to use lensProp, passing it in the name of the property we want to create a lens for.

[00:56] Now that I have a lens defined, I'm going to come back up here, and I'm also going to import Over from Ramda, and Over is going to allow us to apply a function to a value from a lens. I'm going to come down here, and I'm going to update the updater function for my increase.

[01:13] What I'm going to do is I'm going to call Over, and I'm going to pass Over my lens, which is going to be that Count L constant we just defined, and then I'm going to pass a function that I want to apply to my value, which in this case is just our increase utility.

[01:28] Then I want to pass it in the object that it's going to apply this to, so read previous state. Now if I come up here, we'll see that increase still works. Of course, decrease still works because I haven't changed it.

[01:40] I can apply this same thing down here for decrease, and I just have to change the function that I'm applying to my state. In this case it'll be decrease, and we'll see that if I come up here, both buttons still work as expected.

[01:56] Now that we have this working, we can clean this up a little bit. Every function in Ramda is automatically curried, meaning if I pass it fewer arguments than it needs to execute, it'll return a new function, and it'll then wait for the next argument.

[02:11] What I can do is I can basically break this up into two pieces. I can break it up into passing in the lens in the function that I want to apply, get back a function, and then I can call that function with the object that's going to execute everything. With that change, all I've done is added some parentheses, but we can see that everything still works.

[02:35] Because I'm just taking previous state, creating a new function and applying previous state to that immediately, I can shorten this even more by taking previous state out of here. I can just use my partially applied call to Over as my updater function for setState, so I can remove this and everything will still work as expected.

[03:01] Everything here is working fine, but we can clean this up and remove a little bit more duplication. I'm going to come up here where I've defined my lens, and I'm going to define a new function. I'm going to call it Transform Count.

[03:14] I'm going to set this to equal a call to Over with just my lens, and that's going to give me back a function that's then going to expect two more arguments, the transformation function and the object to act on. Because that's also curried, I can pass that one more argument and get back yet another function that'll just wait for an object.

[03:35] I'm going to take this. I'm going to copy it, and I'm going to come down here, and I'm going to replace the call to Over with the Count, with Transform Count, and I'm just going to pass it in the respective transformation function, so I have one call with inc, one call with dec, and if I come up here, I can still use both buttons and everything works just fine.

[04:01] If I wanted to remove this from React altogether, I can cut that. I can come up here, and I can define a new variable which I'll call Increase Count, and then I could do the same thing for Decrease, and then down here I can just use these functions and everything works, but I've taken most of my behavior, pulled it out of React into reusable utility functions.