DEV Community

Robert Aguilera
Robert Aguilera

Posted on

Spread Operator Tricks

I'm going to butter your bread

I recently came across some handy patterns using the spread operator so I thought I’d write up a quick blog post sharing some.

For this blog post, I’m not going to cover the basics of the syntax. If you need a refresher, the MDN docs are a great resource.

Immutability

Javascript has this lovely thing it does with objects. Whenever you attempt to make a copy of an object you might inadvertently make a reference to it instead.

let oldNed = {
  name: 'Ned Stark',
  job: 'Warden of the North'
};
let newNed = oldNed;
newNed.job = 'Dead';
// oldNed variable is also mutated
console.log(oldNed) // { name: 'Ned Start', job: 'Dead' }

Mutating data can lead to some hard to find bugs, so it’s worth the time and effort to ensure that you prevent this by properly copying any data that you need to change. One way is through the use of the spread operator.

let newNed = {...oldNed};

Any changes to newNed will not mutate the oldNed variable. However, there is one exception. The spread operator does not preform a deep clone of a nested object.

let oldNed = {
  name: 'Ned Stark',
  job: 'Warden of the North',
  kids: ['John', 'Rob', 'Bran', 'Sansa', 'Arya', 'Rickon']
};
let newNed = { ...oldNed };
newNed.kids.splice(5)
// oldNed is now also missing Rickon :(

To get around this you have to also spread out the nested array

let newNed = { ...oldNed, kids: [...oldNed.kids] };

Keep in mind that if you have a deeply nested object you might want to reach for some kind of custom function or library to help you with deep cloning.


Here’s some other nifty immutable tricks.

Combining multiple arrays (pieces or the whole thing).

let dontChangeMe = ['Apples', 'Peaches', 'Detergent', 'Flowers'];
let meNeither = ['A shiny red polo', 'coffee', 'milk'];
let shoppingList = [
    ...dontChangeMe,
    'diapers',
    ...meNeither.slice(1)
]

Copying an object and simultaneously updating properties.

let nedStark = {
  name: 'Ned Stark',
  job: 'Warden of the North'
};
let newNed = { ...nedStark, job: 'Dead' };

Converting a nodeList into an actual array.

var divs = document.querySelectionAll('div')
var arrayOfDivs = [...divs] // returns an array not a nodelist

The Rest Operator

So, I haven’t personally found many use cases for the Rest Operator yet. However, I did stumble across this pattern for creating authenticated routes in React using React-Router. Here’s a basic example.

const AuthenticatedRoute = ({ ...rest }) => {
  const id = this.state;
  if (!id) {
    return <Redirect to={{ pathname: '/home' }} />;
  }
  return <Route {...rest} />;
};
// In Use
<AuthenticatedRoute
  path='/dashboard'
  data={this.state.data}
  render={() => (
    <SomeComponent someProps={this.someProps} />
  )}
/>

The rest operator magic happens when you return <Route {...rest} /> . Basically, what’s going on is a function AuthenticatedRoute is called and it checks for an id on the state object. If it fails, it returns a <Redirect/> component. Otherwise, it returns a <Route> component and passes through all its props (in this example path, data, and render).

Pretty handy right? Got anymore? Share them below please!

Top comments (2)

Collapse
 
kepta profile image
Kushan Joshi

The most important use case of rest is

const wrapper = (...args) => someFunc.apply(null, args)

You don’t have resort to using weird hacks to slice the argument object anymore, to apply the args to another function.

Collapse
 
robaguilera profile image
Robert Aguilera

Definitely! I just personally haven't come across needing to do that. Only time I ever needed to mess with the argument object was to log it out to see what was being passed in.