There are two main ways to append an item to the end of an array in JavaScript, they are .push and .concat.

Both .push and .concat live on Array.prototype, that means that all instances of Array have access to both the .push and .concat methods.

let friends = ["Mikenzi", "Addison"];
friends.push; // ƒ push() { [native code] }
friends.concat; // ƒ concat() { [native code] }

.push

Now, how exactly do you use .push? Whenever you invoke the .push method, any arguments you pass to it will be appended to the end of the original array. What .push returns is the new length of the array once the new elements are appended to it.

let friends = ["Mikenzi", "Addison"];
const newLength = friends.push("Joshy", "Stacey"); // 4
friends; // ['Mikenzi', 'Addison', 'Joshy', 'Stacey']
newLength === friends.length; // true

Simple enough. Whenever you want to append one or more items to the end of an array, you can use .push.

Do you see any downsides with this approach? Notice that we're mutating the original friends array. Generally it's a good idea to avoid direct mutations when you can. This brings us to the next method we can use, .concat.

.concat

.concat is used to merge two or more arrays together. What's nice about concat is it doesn't mutate the original array but instead returns a new array.

const oldFriends = ["Mikenzi", "Addison"];
const friends = oldFriends.concat(["Joshy", "Stacey"]);
oldFriends; // ['Mikenzi', 'Addison']
friends; // ['Mikenzi', 'Addison', 'Joshy', 'Stacey']

Notice we get the same result we had with .push, but now we're not mutating the original array. It's because of this that you should prefer .concat over .push.

Because concat doesn't modify the original array and instead returns a new array, it's commonly used in React apps, Redux apps, or anywhere else mutations are frowned upon.

addFriend(friend) {
this.setState((prevState) => ({
friends: prevState.concat([friend])
}))
}