In this lesson we'll learn the basics of using lenses in Ramda and see how they enable you to focus changes on specific properties of an object while keeping your data immutable.
Here, I've included the Ramda library and created a simple person object with a first name and a last name property. I'm going to drop down and create a variable called flens, and I'm going to set flens equal call to r.lens.
To create a lens in Ramda, you're going to give it two functions. The first function is a getter. We're just going to use Ramda's prop function and give it the name of the first name property. The second function that you pass to lens is a setter. We're going to use r.assoc, passing it that first name property name.
Now with the lens defined, I'm going to drop down here and I'm going to declare a variable called result. I'm going to set that to equal r.view. I'm going to pass view a reference to my lens, and I'm going to pass it my person object that I want to use the lens on.
Now I'm going to drop down and just log-out result, so we can see what view does. I'll go to the terminal. I'll run this, and the output will be the string "fred," which is pulling from the first name in our person object.
Let's see what else we can do with a lens. I'm going to take this result and duplicate it, and comment out the first one for reference. I'm going to replace this call to r.view with a call to r.set. Set is going to take the lens as its first argument, just like with view.
The second argument here is going to be a value that we want to set on the property that the lens focuses on. We want to set the first name of person to Wilma, and third argument then becomes our object that we want to actually operate on.
Let's take a look at that in the console. When I run this, you'll see I get back an entire person object, where the first name is Wilma, last name is Flintstone. I'm going to drop down to where I'm logging out results. I want to add a second log statement, and I'm going to log our original person object.
When I run this, you'll see that I get back two objects, one with the first name Fred and one with the first name Wilma. I did this just to demonstrate that these operations treat the data as immutable. It's never going to mutate your original object. It's going to create a new one that reflects the changes.
Let's jump back into the code, and I'm going to comment this one out. We don't need to log-out person any more.
Let's say I need to take an object with a first name property, convert it to all caps, and get back a new object that reflects the chain. Using what we already know about lenses, I could do that. I could come in here. I could say const first name, and I could set that equal to r.view and have lens with my person.
Now that I have my first name, I could say upper name equals r.to upper first name. Finally, I could clear const results and set that equal to r.set, passing it flens again, my value, which is upper name, and my person object.
Let's take a quick look at the result. I'm going to run this, and we'll see I get back an object, where the first name Fred has been capitalized. If you haven't already guessed, there's a cleaner way to write this. I'm going to come back into the code, and I'm going to keep these three lines for reference. I'm going to declare a new result, and I'm going to set that to equal call to r.over.
Over is going to take our lens, and it's going to run a function over the focus of that lens. I'm going to start with my lens, followed by the function that I want to run against the data, and finally, the object that I want to run this on. I can save that, jump back into the terminal.
You'll see that we get the same results from running r.over, passing it the to upper function and our object, as we got for these three lines, except now we don't have all those intermediate variables. Using a lens like this, where our getter is a call to r.prop with a property name, and the setter is a call to r.assoc, where the property name is so common that there's a shortcut for this.
I'm going to duplicate this line and leave the original one for reference. I can change this to a lens prop, and pass it the property name. Internally, that'll do essentially what we did with our longhand lens definition. If I save that and I run it, you'll see that I get the same result. Everything works just like it did before.