Resolving React Error, "Tried to merge an object, instead got [object Object]"
Using JavaScript's spread operator, the state can be modified in a cleaner and shorter syntax in React.
Oct 8, 2020 • 6 Minute Read
Introduction
While working with state variables in React, you might run into an error stating Tried to merge an object, instead got [object Object]. This usually happens when you are directly modifying your state and altering its original structure incorrectly. For instance, your state variable has initialized an empty object and you are trying to assign an array to it directly. This guide demonstrates how you can alter or update your state correctly without running into any errors.
Modifying State in React
In React, the state is conceived to be immutable. This means that if you have this state in your component
state={
name: 'Margo'
}
you can't mutate the state directly as shown below.
this.state={
name:'Fuzzy'
}
You have to call the setState() method available on your state to update the state asynchronously. Not only does this immutability follow a structured React pattern of updating the state and re-rendering the DOM, but it also prevents you from writing bad code that can break your app. For instance, if your state is an object containing an array, you will call setState() to update that array, keeping the original structure of the state intact.
Example in React
In an empty React project, create a simple class component with some predefined state.
import React, { Component } from 'react'
export default class App extends Component {
state={
todos:[
{id:0,"status": 0, "title": "Wash Dishes"},
{id: 1,"status": 1, "title": "Play Piano"}
]
}
render() {
return (
<div>
</div>
)
}
}
The above class contains a simple state object with a property called todos. todos is an array of objects where each object represents information about a particular todo. Let's say you got a list of new todos back from the server and you want to append those todos to your state so you can output it on the DOM.
componentDidMount(){
var newTodos = [
{id:2,"status": 0, "tite": "Cook Dinner"},
{id: 3,"status": 0, "title": "Make Bed"}
];
}
newTodos is what you want to append to your state. Consider the following code that novice React developers write while merging a new object with the state.
componentDidMount(){
var newTodos = [
{id:2,"status": 0, "tite": "Cook Dinner"},
{id: 3,"status": 0, "title": "Make Bed"}
];
var newState = {};
newState = newTodos;
console.log(newState);
this.setState(newState);
}
You first create a newState variable as an empty object and assign it to newTodos. So now newState is an array of objects with data from newTodos. Then you call the setState() method and pass in the new state inside it directly. Your original state was
todos:[
{id:0,"status": 0, "title": "Wash Dishes"},
{id: 1,"status": 1, "title": "Play Piano"}
]
After merging newTodos into your state, you should expect your state to become
todos:[
{id:0,"status": 0, "title": "Wash Dishes"},
{id: 1,"status": 1, "title": "Play Piano"},
{id:2,"status": 0, "tite": "Cook Dinner"},
{id: 3,"status": 0, "title": "Make Bed"}
]
See if the new state actually looks like the above by logging it to the console inside componetDidUpdate()
componentDidUpdate(){
console.log(this.state)
}
If you inspect the console you will see that your state has deviated its original structure and it looks something like this
{id: 2
This isn't what you were expecting. Each element of the newly added todos is a direct child property of your state instead of the todos property. Not only does this badly structure your state, but it also leaves your code more prone to future bugs and errors. Additionally, it also becomes difficult to output all the todos on the DOM, as you have to loop through the properties separately depending on their data structure. You might also run into the error Tried to merge an object, instead got [object Object ] while updating the state. The correct way to do this is by maintaining the original structure of your state .
this.setState({...this.state,todos:[...this.state.todos,...newTodos]});
Using the spread operator, you first copy the original state to a new state and append the newly added todos to the todos property of the state. If you see the updated state logged on the console then your state looks exactly how it should, containing one single property called todos that contains all four todos as elements of an array. Now you can also easily output all todos by simply iterating over the todos property of the state and outputting the property you wish to render on the DOM .
render() {
return (
<div>
{
this.state.todos.map(todo=><p key={todo.id}>{todo.title}</p>)
}
</div>
)
}
}
Have a look at the entire code below.
import React, { Component } from 'react'
export default class App extends Component {
state={
todos:[
{id:0,"status": 0, "title": "Wash Dishes"},
{id: 1,"status": 1, "title": "Play Piano"}
]
}
componentDidMount(){
var newTodos = [
{id:2,"status": 0, "tite": "Cook Dinner"},
{id: 3,"status": 0, "title": "Make Bed"}
];
this.setState({...this.state,todos:[...this.state.todos,...newTodos]});
}
componentDidUpdate(){
console.log(this.state)
}
render() {
return (
<div>
{
this.state.todos.map(todo=><p key={todo.id}>{todo.title}</p>)
}
</div>
)
}
}
Conclusion
Modifying or updating the state of your React components should be done in the right manner to avoid potential bugs in your code. Using JavaScript's spread operator, the state can be modified in a cleaner and shorter syntax. A lot of good practices can be adopted by simply learning newer and more modern features of JavaScript and using them in your code. They help you write clean, short, readable, and maintainable code and mitigate your chances of running into errors.