Categories
JavaScript Basics

Spreading Arrays with JavaScript

The spread operator is one of the best recent JavaScript features.

In this article, we’ll look at what we can do with the spread operator.

Spread Operator

Rhe spread syntax lets us expand iterable objects like arrays and strings in various situations.

Merging Arrays

We can merge arrays with it.

For example, we can write:

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [...a, ...b[;

We put all the items from a and b into a new array and assign it to c .

So c is:

[1, 2, 3, 4, 5, 6]

Clone Array

Another way we can use it is to shallow copy an array.

For example, we can write:

const arr = [1, 2, 3];
const arrCopy = [...arr];

We made a copy with the spread operator. It expands the arr entries into a new array.

So arrCopy is also [1, 2, 3] .

But they reference different objects in memory.

Arguments to Array

The arguments object is an iterable object that has the arguments passed into a JavaScript function.

It’s only available in a traditional function.

For instance, we can write:

function foo() {
  const args = [...arguments];
  console.log(args);
}

args is an array.

So if we have:

foo(1, 2, 3)

Then args is [1, 2, 3] .

A more modern alternative that works with all functions is the rest operator:

const foo = (...args) => {
  console.log(args);
}

Then if we call it the same way:

foo(1, 2, 3)

args would have the same value.

String to Array

We can convert a string into an array of characters with the spread operator since string are iterable.

For example, we can write:

const string = 'hello world';
const array = [...string];

Then array is:

["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

Set to Array

A set is an iterable object that can’t have duplicate entries.

Since it’s iterable, we can use the spread operator with it.

For example, we can write:

const set = new Set([1, 2, 2, 3, 3]);
const arr = [...set];

Then arr is [1, 2, 3] since the duplicates are removed from the set.

Map to Array

Maps are key-value pairs that’s stored in an object.

It’s also iterable so we can use the spread operator with it.

For example, we can write:

const map = new Map([
  ['foo', 1],
  ['bar', 2]
]);
const arr = [...map];

We spread the map with the operator and arr would be:

[
  ['foo', 1],
  ['bar', 2]
]

Node List to Array

Node lists are a list of DOM nodes.

It’s an iterable object but it’s not an array.

To convert them to an array, we can write:

const nodeList = document.querySelectorAll('div');
const nodeArr = [...nodeList];

We convert the node list returned from querySelectorAll to an array with the spread operator.

Conclusion

We can use the spread operator to spread or copy arrays and convert iterable objects to arrays.

Categories
JavaScript Basics

JavaScript Concepts We Should Learn to Master React — Spread and Rest

Knowledge of the latest JavaScript syntax is essential to understand and master React.

It takes reading the manual much easier and writing React code much shorter and cleaner.

Once we master some new JavaScript syntax, writing React code would be a breeze.

In this article, we’ll look at the use of the spread and rest operators in React apps.

Spread Operator

The spread operator comes in handy when we need to pass in lots of props, but we don’t want to write them all out in the JSX code.

This operator can be used with arrays or objects. With objects, we can use it to make a copy of an object as follows:

const obj = {
  a: 1
};
const copy = {
  ...obj
};

In the code above, we used the spread operator to make a shallow copy of the obj object by copying the keys and values into the copy object.

A shallow copy means that only the top-level is copied, the rest are still referencing the original object.

Therefore, obj and copy are different objects with the same keys and values.

We can also use it to merge multiple objects together. For instance, we can use it as follows to merge multiple objects into one:

const obj1 = {
  a: 1
};
const obj2 = {
  b: 2
};
const obj3 = {
  a: 3,
  c: 3,
};
const merged = {
  ...obj1,
  ...obj2,
  ...obj3
};

In the code above, we have 3 objects, obj1 , obj2 , and obj3 which are merged together with the spread operator into one object, which is the merged object.

If there’re 2 values with the same corresponding key, then the one that’s merged in later overwrites the one that’s added earlier.

Therefore, merged is {a: 3, b: 2, c: 3} .

To use the spread operator with arrays, we can use it as follows:

const arr = [1, 2, 3];
const copy = [...arr];

In the code above, we have the copy array, which we copied from the arr array by using the spread operator.

It also makes a shallow copy, so nested objects and arrays are still referencing the items in the original array.

We can also merge in arrays with the spread operator. For instance, we can write:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2];

Then we get the that the merged array is:

[1, 2, 3, 4, 5, 6]

The values are just appended in the order they’re spread.

For instance, a frequently used example of this is the following:

import React from "react";

const props = {
  greeting: "hi",
  firstName: "jane",
  lastName: "doe"
};

const Greeting = ({ greeting, firstName, lastName }) => (
  <p>
    {greeting}, {firstName} {lastName}
  </p>
);

const App = () => {
  return <Greeting {...props} />;
};
export default App;

In the code above, we have the Greeting component, which takes the greeting , firstName , and lastName props.

Then we have the App component, which uses the spread operator by writing:

<Greeting {...props} />

The expressions {...props} is for spreading the properties of props into props that are passed into the Greeting component.

Therefore, we’ll see that the props will be rendered with their values.

Rest Operator

The rest operator is used to keep parameters that haven’t been added as named parameters in an array if we’re using the rest parameter on parameters or an object if we’re using the rest operators on an object.

For instance, if we have some props that we don’t always want to reference. We can use the rest operator on it as follows:

import React from "react";

const props = {
  firstName: "jane",
  lastName: "doe",
  age: 20,
  gender: "female",
  job: "waitress"
};

const Person = ({ firstName, lastName, ...restProps }) => (
  <p>
    {firstName} {lastName}, {restProps.age}, {restProps.gender}, {restProps.job}
  </p>
);

const App = () => {
  return <Person {...props} />;
};
export default App;

In the code above, we used the rest operator to put the props that we didn’t destructure into one big object.

The props object we have above had the age , gender , and job properties were spread with the spread operator inside the App component, so they’re all passed in as props.

However, in the Person component, we have the restProps variable with the rest operator before it, which converts it to an object with the age , gender , and job properties inside it.

Therefore, we can reference those properties in the restProps variable like we did inside the Greeting component.

Conclusion

The spread and rest operators are very useful for React and general JavaScript code. The spread operator lets us make shallow copies of objects and arrays and also merge them together.

Also, the rest operator is useful for storing properties or array entries that haven’t been destructured or listed as arguments into an object or array respectively.

Categories
JavaScript

Why We Should All Use the JavaScript Spread Operator?

The JavaScript spread operator is very useful for many things that we may not have known it can do.

In this article, we’ll look at why it’s useful.

Spreading Function Calls

The spread operator can be used to spread an array of objects and values into arguments.

For example, we can write:

const min = Math.min(...[1, 2, 2, 3, 5]);

to find the minimum number from an array.

It’s much better than using apply to do the same thing since we don’t have to pass in the value of this as the first argument.

Copying Arrays

We can use the spread operator to shallow copy one array into another.

For example, if we have:

const arr = [1, 2, 3];
const arrCopy = [...arr];

When we log the values of both, we’ll see that they have the same value, but when we log the value of:

arr === arrCopy

We see that it’s false . Therefore, we know that they aren’t referencing the same array.

Concatenate Arrays

We can apply the spread operator to concatenate multiple arrays by applying it to multiple arrays.

For instance, we can write:

const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const arr = [...arr1, ...arr2];

Then we get that the value of arr is:

[0, 1, 2, 3, 4, 5]

It’s much easier than using the concat method to attach 2 arrays together.

Copying Objects

We can also use the spread operator to copy objects. For example, we can write:

const obj = {
  a: 1,
  b: 2
};
const objCopy = {
  ...obj
};

Then when we log the value of both, we’ll get the same value.

And when we log the value of:

obj === objCopy

We’ll get see false log. This means that obj and objCopy aren’t referencing the same object but have the same content.

Merging Objects

We can use the spread operator to merge objects into one. If a property has the same name in multiple objects, then the value of the last one will overwrite the previous ones.

For example, if we write the following, then we get:

const obj = {
  a: 1,
  b: 2
};

const obj2 = {
  a: 3,
  c: 2
};
const mergedObj = {
  ...obj,
  ...obj2
};

We get the value of mergedObj is:

{a: 3, b: 2, c: 2}

Photo by Louis Hansel on Unsplash

Converting Array-Like Objects to Arrays

We can convert array-like objects to arrays with the spread operator.

Array-like objects include objects like Sets , Map s, arguments object, Node lists, and anything else that has a Symbol.iterator method.

For example, we can use it to convert a Node list to an array of DOM nodes objects as follows.

Given that we have the following HTML:

<div>
  foo
</div>
<div>
  bar
</div>

We can find the div with the text ‘bar’ inside as follows:

const divs = [...document.querySelectorAll('div')];
const barDiv = divs.find(div => div.innerText === 'bar');

Once we converted the Node list returned by querySelectorAll with the spread operator, we can use any array methods like find to do what we want.

Node list do not have any array methods, but they can be looped through with loops, has a length property and each entry have an index.

Likewise, we can convert Set s to arrays as follows:

const arr = [...new Set([1, 2, 3, 3])];

Then we get that the value of arr is:

[1, 2, 3]

We can do the same with the other kinds of array-like objects.

Set Operations

Since arrays have many methods for filtering data, we can use these methods to do common set operations that can’t be done with the Set instance itself since they don’t have methods to do those things.

We can do things like set unions and intersections by convert Sets to arrays and then do the operations with array methods, and then we can convert the array result back to a set.

For instance, if we want to find an intersection of 2 Sets, we can write:

const setA = new Set([1, 2, 3]);
const setB = new Set([3, 4, 5]);
const intersection = [...setA, ...setB].filter(el => [...setA].includes(el) && [...setB].includes(el));
console.log(new Set(intersection));

Then we get that intsection has the element 3 in it only since 3 is in both setA and setB .

What we did was that we converted setA and setB to arrays and then called filter on the merged array with both Sets spread into one big array.

Then we called filter on the array with the predicate:

[...setA].includes(el) && [...setB].includes(el)

to find the elements that are in both sets.

Finally, we converted the resulting array back to a Set by passing it back in the Set constructor.

Conclusion

The spread operator is useful for shallow copying arrays and objects.

It can also be used for merging both arrays and objects.

We can also convert array-like objects easily to arrays with it so that we can call arrays methods on it which aren’t available on array-like objects.

This makes finding things in them and doing operations with Sets much easier.

Categories
JavaScript Basics

Using the Spread Operator in JavaScript

The spread syntax allows us to break up a collection of objects, like arrays, into individual arguments or insert them into a different iterable object, like an array.

With the 2018 version of JavaScript, we can also spread properties of an object into another object, with keys and values spread into another object. The spread syntax is denoted by three periods before your object.

For example, we can write:

...arr

The spread syntax works by copying the values of the original array and then inserting them into another array, or putting them in the order they appeared in the array as the list of arguments in a function in the same order.

When the spread operator is used with objects, the key-value pairs appear in the same order they appeared in in the original object.

We can use the spread syntax to spread an array of values as arguments of a function. For example, we can write:

const arr = [1,2,3];
const add = (a,b,c) => a+b+c;
add(...arr) // returns 6

In the example above, the spread operator spreads the variables into the argument in the same order they appeared in in the array. So 1 is passed into a, 2 is passed into b, and 3 is passed into c.


Spread Arrays

For arrays, we can also use the spread syntax to insert one array’s values into another array. For example, we can write:

const arr = [1,2,3];
const arr2 = ['a','b','c',...arr,'d']; // arr2 is ['a','b','c',1,2,3,'d']

As we can see, the spread operator inserts the values exactly where we spread the array, in the same order they appeared in the array.

So, 1 is inserted between a and d, then 2 is inserted between 1 and d, and 3 is inserted between 2 and d. The result is that we copied an array’s values into another array with the spread operator in the same order they appeared in, and exactly where you put the array spread expression.

Without the spread operator, we have to write loops to insert them into the position we want. We slice the array into two and then call concat on the three parts, then assign the result to the array you inserted the stuff into. It sounds painful just thinking about it.

Note that with the spread operator, only the first level of the array is spread. If we have nested or multi-dimensional arrays, it’s going to copy the references as-is. It will not do anything to nested items.

With ES2018, we can do the same thing with objects, like the following:

const obj = {a: 1, b: 2};
let objClone = { ...obj }; // objClone is {a: 1, b: 2}

This creates a shallow copy of the object. It means that only the first level of the object is copied.

For nested objects, it’s going to copy the references as-is. It will not do anything to nested items. The top-level keys and values of the object will be copied to objClone.

So, if we have nested objects, we get:

const obj = {
  a: 1,
  b: {
    c: 2
  }
};
let objClone = {
  ...obj
};
console.log(objClone)

In objClone, we get:

{
  a: 1,
  b: {
    c: 2
  }
}

So, nested objects will reference the same ones as the original.

The spread operator can be used as an alternative to other functions that existed before.

For example, we can use it to replace the apply function for passing in arguments to a function. The apply function takes an array of arguments for the function it’s called on as the second argument.

With the apply function, we call it as follows:

const arr = [1,2,3]
const sum = (a,b,c)=> a+b+c;
sum.apply(null, arr); // 6

With the spread syntax, we can write the following instead:

const arr = [1,2,3]
const sum = (a,b,c)=> a+b+c;
sum(...arr)

The spread operator also work with strings. We apply the spread operator to strings, we get an array with the individual characters of the string.

For example, if we write:

const str = 'abcd';
const chars = [...str];

We get [“a”, “b”, “c”, “d”] as the value of chars.


Using Spread Operator Multiple Times

We can use the spread syntax multiple times in one place. For example, we can have the following:

const arr = [1,2,3];
const arr2 = [4,5];
const sum = (a,b,c,d,e,f)=> a+b+c+d+e+f;
sum(...arr, ...arr2, 6)

As usual, the spread syntax will spread the array of numbers into arguments of the array in the order as they appeared in.

So, sum(…arr, …arr2, 6) is the same as sum(1,2,3,4,5,6).

1, 2, and 3 are the first three arguments, which are the entries of arr in the same order, and 4 and 5 are the fourth and fifth arguments, which are spread after 1, 2, and 3.

Then, in the end, we have 6 as the last argument. We can also see the spread syntax work with the normal function call syntax.


Use It in Constructors

We can use the spread operator as arguments for object constructors. For example, if we want to create a new Date object, we can write:

let `dateFields = [2001, 0, 1];
`let `date = new Date(...dateFields);`

The items in the dateFields array are passed into the constructors as arguments in the order they appeared in. The alternative way to write that would be much longer, something like:

let `dateFields = [2001, 0, 1];
const year = dateFields[0];
const month = dateFields[1];
const day = dateFields[2];
`let `date = new Date(year, month, day);`

Copying Items

The spread syntax can also be used to make a shallow copy of an array or an object as it works by creating copies of the top-level elements of an array or key-value pairs of an object, and then inserting them into the place you used the spread operator with.

For copying arrays, we can write:

const arr = [1, 2, 3];
const arr2 = [...arr, 4, 5];

The above example, arr2, is [1,2,3,4,5], while arr1 is still [1,2,3].

arr1 is not referenced by arr2 because the spread operator actually makes a copy of the array and then inserts the values. Note that this doesn’t work with multi-dimensional arrays as it only makes copies of the top-level elements.

We can apply the spread syntax multiple times in one array or object. An example for array would be:

let `arr = [1, 2, 3];
`let `arr2 = [4, 5];
`let `arr3 = [...arr2, ...arr];`

In the above example, we get [4,5,1,2,3]. arr1 and arr2 are unaffected as a copy of the values from arr1 and arr2 are inserted into arr3.


Spread Operator and Objects

With ES2018, the spread operator works with object literals. Then, key-value pairs of an object can be inserted into another object with the spread operator.

If there are two objects with the same key that the spread operator is applied to in the same object, the one that’s inserted later will overwrite the one that’s inserted earlier.

For example, if we have the following:

let obj1 = {foo: 'bar', a: 1};
let obj2 = {foo: 'baz', b: 1};
let obj3 = {...obj1, ...obj2 }

Then we get {foo: “baz”, a: 1, b: 1} as the value of obj3 because obj1 is spread before obj2.

They both have foo as a key in the object. First, foo: 'bar' is inserted by the spread operator to obj3. Then, foo: 'baz' overwrites the value of foo after obj2 is merged in, as it has the same key foo but inserted later.

This is great for merging objects as we don’t have to loop through the keys and put in the values, which is much more than one line of code.

One thing to note is that we can’t mix the spread operator between regular objects and iterable objects. For example, we will get TypeError if we write the following:

let `obj = {foo: 'bar'};
`let `array = [...obj];`

Conclusion

As we can see, the spread syntax is a great convenience feature of JavaScript. It lets us combine different arrays into one.

Also, it lets us pass arrays into a function as arguments with just one line of code. With ES2018, we can also use the same operator to spread key-value pairs into other objects to populate one object’s key-value pairs into another object.

The spread operator works by copying the top-level items and populating them in the place you use the spread operator, so we can also use it to make shallow copies of arrays and objects.

Categories
React

React Patterns — Improving Performance and Avoid Antipatterns

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at how to improve the performance and avoiding antipatterns when we create React apps.

Reconciliation and keys

We’ve to add a key to the key prop that’s unique.

Otherwise, React can’t keep track of the list items properly.

For instance, we can write:

{items.map(item => <li key={item.id}>{item.name}</li>)}

We got to have an id property that’s unique with for each items entry.

The items that are inserted can’t be tracked without a unique ID in the key prop.

useEffect

We should watch the items that we need to watch to update a derived value.

To do that we use the useEffect hook.

For instance, we write:

useEffect(() => {
  doSomething(foo);
}, [foo]);

Now we call doSomething only when foo updates.

This is the hooks equivalent of shouldComponentUpdate and componentWillReceiveProps .

It works with both props and state changes.

Stateless Function Components

Stateless function components don’t give any benefits with regards to performance.

It just helps us make presentation only components to separate logic from components with states.

useMemo

We can use the useMemo hook to store results from expensive computations.

For instance, we can write:

const memoizedValue = useMemo(() => compute(a, b), [a, b]);

Now React won’t compute the value again unless a or b changed.

Refactoring and Good Design

We should have states with descriptive names.

items is a good name for a state that stores some items.

If we have something more specific then we should name it with that.

We should only render when something changes.

If props and state change, then we render.

Immutability

We should make things immutable when we can,

This way, they can’t be mutated accidentally.

Then we can avoid this kind of bugs, which may be hard to trace.

To avoid mutation, we can make a copy of an object and then change it.

We can use Object.assign or spread to do that:

const newObj = Object.assign({}, obj, { foo: 'bar' });

or:

const newObj = {...obj,  foo: 'bar' };

Likewise, we can do the same with arrays.

For instance, we can write:

const newArr = [...arr, 1];

We used the spread operator to spread the arr array entries into a new array and add 1 to it.

Initializing the State using Props

We shouldn’t initialize the state using props.

Instead, we should watch for prop changes and then update the state accordingly.

This way, we’ll make sure our props are updated with the state.

To do that, we use the useEffect hook as follows:

useEffect(() => {
  setBar(foo);
}, [foo]);

If foo is a prop, then we can set the bar state with setBar by calling it with foo so that the bar state is updated when foo is updated.

Mutating the State

Also, we shouldn’t mutate the state directly.

If we have a state, then we shouldn’t assign it with a new value direcyly.

Instead, we call the function to set the state.

For instance, we can write:

setCount(2);

top set the state, where setCount is the function returned by useState to set the count state.

Or we can write:

setCount(count => count + 1);

if we want to set a state based on the previous count state’s value.

We should do that as little as possible to improve performance.

Using Indexes as a Key

Indexes shouldn’t be used as the key if possible.

This is because tracking can’t be done properly with indexes as keys, then if we modify the array of elements or components, then we would have problems.

The best value for the key prop is a unique ID of the item.

Spreading Props on DOM Elements

We should avoid spreading props to DOM elements to avoid spreading unknown HTML attributes, which is a bad practice.

We may get errors from React telling us to remove unknown attributes.

Instead, we should just write them out explicitly unlike props.

Conclusion

We should think about performance and antipatterns when we’re writing React components.

It’s hard to create components that are speedy and do everything we want.

But if we take into account some good practices, we can do it easily.