What do these three dots in React do?
...
(three dots in JavaScript) is called the Spread Syntax or Spread Operator. This allows an iterable such as an array expression or string to be expanded or an object expression to be expanded wherever placed. This is not specific to React. It is a JavaScript operator.
All these answers here are helpful, but I want to list down the mostly used practical Use Cases of the Spread Syntax (Spread Operator).
1. Combine Arrays (Concatenate Arrays)
There are a variety of ways to combine arrays, but the spread operator allows you to place this at any place in an array. If you'd like to combine two arrays and place elements at any point within the array, you can do as follows:
var arr1 = ['two', 'three'];
var arr2 = ['one', ...arr1, 'four', 'five'];
// arr2 = ["one", "two", "three", "four", "five"]
2. Copying Arrays
When we wanted a copy of an array, we used to have the Array.prototype.slice()
method. But, you can do the same with the spread operator.
var arr = [1,2,3];
var arr2 = [...arr];
// arr2 = [1,2,3]
3. Calling Functions without Apply
In ES5, to pass an array of two numbers to the doStuff()
function, you often use the Function.prototype.apply()
method as follows:
function doStuff (x, y, z) {}
var args = [0, 1, 2];
// Call the function, passing args
doStuff.apply(null, args);
However, by using the spread operator, you can pass an array into the function.
doStuff(...args);
4. Destructuring Arrays
You can use destructuring and the rest operator together to extract the information into variables as you'd like them:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
5. Function Arguments as Rest Parameters
ES6 also has three dots (...
) which indicates a rest parameter that collects all remaining arguments of a function into an array.
function f(a, b, ...args) {
console.log(args);
}
f(1, 2, 3, 4, 5); // [3, 4, 5]
6. Using Math Functions
Any function where spread is used as the argument can be used by functions that can accept any number of arguments.
let numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
7. Combining Two Objects
You can use the spread operator to combine two objects. This is an easy and cleaner way to do it.
var carType = {
model: 'Toyota',
yom: '1995'
};
var carFuel = 'Petrol';
var carData = {
...carType,
carFuel
}
console.log(carData);
// {
// model: 'Toyota',
// yom: '1995',
// carFuel = 'Petrol'
// }
8. Separate a String into Separate Characters
You can use the spread operator to spread a string into separate characters.
let chars = ['A', ...'BC', 'D'];
console.log(chars); // ["A", "B", "C", "D"]
You can think of more ways to use the Spread Operator. What I have listed here are the popular use cases of it.
...
are called spread attributes which, as the name represents, it allows an expression to be expanded.
var parts = ['two', 'three'];
var numbers = ['one', ...parts, 'four', 'five']; // ["one", "two", "three", "four", "five"]
And in this case (I'm going to simplify it).
// Just assume we have an object like this:
var person= {
name: 'Alex',
age: 35
}
This:
<Modal {...person} title='Modal heading' animation={false} />
is equal to
<Modal name={person.name} age={person.age} title='Modal heading' animation={false} />
So in short, it's a neat short-cut, we can say.
The three dots represent the spread operator in ES6. It allows us to do quite a few things in JavaScript:
Concatenate arrays
var shooterGames = ['Call of Duty', 'Far Cry', 'Resident Evil']; var racingGames = ['Need For Speed', 'Gran Turismo', 'Burnout']; var games = [...shooterGames, ...racingGames]; console.log(games) // ['Call of Duty', 'Far Cry', 'Resident Evil', 'Need For Speed', 'Gran Turismo', 'Burnout']
Destructuring an array
var shooterGames = ['Call of Duty', 'Far Cry', 'Resident Evil']; var [first, ...remaining] = shooterGames; console.log(first); //Call of Duty console.log(remaining); //['Far Cry', 'Resident Evil']
Combining two objects
var myCrush = { firstname: 'Selena', middlename: 'Marie' }; var lastname = 'my last name'; var myWife = { ...myCrush, lastname } console.log(myWife); // {firstname: 'Selena', // middlename: 'Marie', // lastname: 'my last name'}
There's another use for the three dots which is known as Rest Parameters and it makes it possible to take all of the arguments to a function in as one array.
Function arguments as array
function fun1(...params) { }
That's property spread notation. It was added in ES2018 (spread for arrays/iterables was earlier, ES2015), but it's been supported in React projects for a long time via transpilation (as "JSX spread attributes" even though you could do it elsewhere, too, not just attributes).
{...this.props}
spreads out the "own" enumerable properties in props
as discrete properties on the Modal
element you're creating. For instance, if this.props
contained a: 1
and b: 2
, then
<Modal {...this.props} title='Modal heading' animation={false}>
would be the same as
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
But it's dynamic, so whatever "own" properties are in props
are included.
Since children
is an "own" property in props
, spread will include it. So if the component where this appears had child elements, they'll be passed on to Modal
. Putting child elements between the opening tag and closing tags is just syntactic sugar — the good kind — for putting a children
property in the opening tag. Example:
class Example extends React.Component {
render() {
const { className, children } = this.props;
return (
<div className={className}>
{children}
</div>
);
}
}
ReactDOM.render(
[
<Example className="first">
<span>Child in first</span>
</Example>,
<Example className="second" children={<span>Child in second</span>} />
],
document.getElementById("root")
);
.first {
color: green;
}
.second {
color: blue;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Spread notation is handy not only for that use case, but for creating a new object with most (or all) of the properties of an existing object — which comes up a lot when you're updating state, since you can't modify state directly:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});
That replaces this.state.foo
with a new object with all the same properties as foo
except the a
property, which becomes "updated"
:
const obj = {
foo: {
a: 1,
b: 2,
c: 3
}
};
console.log("original", obj.foo);
// Creates a NEW object and assigns it to `obj.foo`
obj.foo = {...obj.foo, a: "updated"};
console.log("updated", obj.foo);
.as-console-wrapper {
max-height: 100% !important;
}