Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 959 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Change Object Properties with Ramda Lenses

4:46 JavaScript lesson by

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.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

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.

Avatar
peterschussheim

Loving these ramda clips, more please!

Avatar
Mike

Thank you for your excellent explanation. Any plans on doing a complete series on Ramda?

Avatar
Andrew Van Slaars

Mike, Thanks for watching! I do have plans to make quite a few more Ramda videos.

In reply to Mike
Avatar
Sen

Excellent explanation. Loving this series. Off topic question: what font is used in the shell? Menlo?

Avatar
Andrew Van Slaars

Sen,

Great question... I have probably changed my font since then, so I'm guessing, but my most recent terminal fonts have been Operator Mono, Roboto Mono and Source Code Pro so I'm sure it's one of those, just can't say for sure which one it is... the differences in terminal are subtle enough that I can't tell by looking at the video. Hope this is helpful.

In reply to Sen

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.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?