Focused
With the power of our new proxy knowledge in hand, let’s turn to a library that leverages proxies behind the scenes. Focused is a library that uses similar techniques to get properties using proxies which allows us to do somewhat magical operations on deeply nested state.
It’s worth noting that we will no longer be getting in setting the properties directly, instead we will be combining functions with our proxies to allow us to attack a plethora of use cases.
First, install focused
npm i focused
We’ll start with a basic person
:
let person = {name: 'John',}
Now we can start building out our functions to manipulate our person
:
import { lensProxy, set } from 'focused'let person = {name: 'John',}let name = lensProxy().namelet mindyify = set(name, 'Mindy')let mindy = mindyify(person)console.log(mindy)
Notice how the
lensProxy
allows us to access a property,name
, that doesn’t exist yet.Then
set
is a function that acts on that property and uses the second value,"Mindy"
as the value to set to. Passing in only to values toset
returns a function expecting the “state”.We now have a
mindyify
function that can change thename
of any object to"Mindy"
.
Note: This creates a new object with the new name
property. The previous person
is left untouched.
Try It Out!
Create any object with a name
property and mindyify
it!
https://codesandbox.io/embed/qx01vlnp9j?view=editor
A Deeply Nested set
Let’s update our code to have more nesting in our state:
let state = {people: [{name: {first: 'John',},},],}
So how are we going to dig all the way into the state to set
the first
property? Easy!
let first = lensProxy().people[0].name.first
All together now:
import { lensProxy, set } from 'focused'let state = {people: [{name: {first: 'John',},},],}let first = lensProxy().people[0].name.firstlet mindyify = set(first, 'Mindy')let mindyiedState = mindyify(state)console.log(mindyiedState)//Logs out an Object with {people:[{name: {first: "Mindy"}}]}
So far, this is really neat, but we’re locked in by that people[0]
to only be able to access the first value in the people
array. But fear not! Our lensProxy
provides us with a special $
function which allows us to pass in functions that can traverse all the values!
import { lensProxy, set, each } from 'focused'let first = lensProxy().people.$(each).name.first
So now, we’re able to update all first
properties to "Mindy"
:
import { lensProxy, set, each } from 'focused'let state = {people: [{name: {first: 'John',},},{name: {first: 'Ben',},},],}let first = lensProxy().people.$(each).name.firstlet mindyify = set(first, 'Mindy')let mindyiedState = mindyify(state)console.log(mindyiedState)
It’s difficult to represent data structures much bigger than this in a blog post, but I’m sure you can imagine some deeply nested data sets where this could really help out. But as one last step, let’s refactor a bit to reinforce what we’ve learned and add an age
property and functions for zeroing out each age
:
import { lensProxy, set, each } from 'focused'let state = {people: [{name: {first: 'John'}age: 37},{name: {first: 'Ben',},age: 12}]}let _ = lensProxy() //only need to call oncelet setEachFirst = set(_.people.$(each).name.first)let setEachAge = set(_.people.$(each).age)let mindyify = setEachFirst('Mindy')let zeroEachAge = setEachAge(0)let mindyiedState = mindyify(state)console.log(mindyiedState)let zeroedMindy = zeroEachAge(mindyiedState)console.log(zeroedMindy)
Oh, So That’s a Lens!
You’ve just used multiple lenses! Anything you’ve created with a lensProxy
like _.people.$(each).name.first
is a “lens” which will focus on a property inside of a function. A lens works with functions, like set
and many others, to manipulate those properties.
Prove It!
Create a last
property on each person, then write a lens and a set
function to change all the last
names to "Lindquist":
https://codesandbox.io/embed/mo8znzwz5j?module=%2Fsrc%2Findex.js&view=editor