{"resource":{"author":{"id":"h2so9H8jPMmgUKGghoNl","name":"Yomesh Gupta","username":"yomeshgupta"},"content":{"link":"https://devtools.tech/understanding-react-setstate/","difficulty":2,"domain":2,"type":1,"isInternal":true,"body":"There are a lot of concepts when it comes to React. State management is one of those which is most widely used and it is a way to hold, process and describe our UI in terms of data. The state is nothing more than a JavaScript object which we can update as per user actions, API responses or any sort of trigger.\n\nWith the introduction of React Hooks, we can use state in functional components too. However, in this blog post, we are going to focus on Class-based components and understand how to use setState and their behaviour. Moreover, some of the mentioned behaviours hold for React < 17.\n\n```js{4}\nclass App extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {}; // Initializing state\n  }\n}\n```\n\n## Updating state\n\nThe state can be directly mutated via `this.state`. However, it will not cause a re-render and will eventually lead to state inconsistency. You can check this behaviour using this [codesandbox](https://codesandbox.io/s/react-state-update-direct-yksbg \"Direct state mutation codesandbox example\").\n\nTherefore, it is recommended to use `setState` to perform any state updates. For the rest of the blog post, we are going to use the following example as our base.\n\n```js\nclass App extends Component {\n  state = { items: [], counter: 0 };\n\n  handleClick = () => {\n    // some processing\n  };\n\n  render() {\n    const { items } = this.state;\n    console.log(\"Rendering\", items);\n\n    return (\n      <div className=\"App\">\n        {items.length ? (\n          <h2>Items are {JSON.stringify(items)}</h2>\n        ) : (\n          <Fragment>\n            <p>No items found</p>\n            <button onClick={this.handleClick}>Add items</button>\n          </Fragment>\n        )}\n      </div>\n    );\n  }\n}\n```\n\n### Different setState function signatures\n\n`setState` can be used in two different ways\n\n1. Passing an object as an argument\n\n```js{4-9}\n...\nhandleClick = () => {\n  const { items } = this.state;\n\n  this.setState({\n    items: [\n      ...items,\n      \"apple\"\n    ]\n  });\n}\n...\n```\n\nIn this case, we are passing an object to the `setState` function which contains a part of the overall state which we want to update. React takes this value and merges it into the final state. Like, in the above code snippet, we are appending an item `apple` to our items array in the state. After the merging by React, our final state would look like the following\n\n```js\n{\n  \"items\": [\"apple\"],\n  \"counter\": 0\n}\n```\n\nReact's state merging is shallow. Hence, it has no impact on the `counter` variable in the state.\n\n2. Passing function as an argument\n\n```js{3-11}\n...\nhandleClick = () => {\n  this.setState((state, props) => {\n    const { items } = state;\n\n    return {\n      items: [\n        ...items,\n        \"apple\"\n      ]\n    }\n  });\n}\n...\n```\n\nIn this case, we are passing a function to the `setState`. This function will receive the previous state as the first argument, and the props at that time the update is applied as the second argument. When we talk about the previous state here then it means the most up-to-date state then (we will see how this is helpful later). It returns an object which would be merged into the final state by React.\n\n## Usecases\n\nNow, we are going to observe the behaviour of `setState` invocation in different circumstances and try to understand why it is behaving in that way.\n\n#### 1. Multiple state updates in one scope\n\nIn our earlier code snippets, we were appending item(s) to our items array in the state. Suppose, we have a case where we want to make successive setState calls in one function scope. You can use this [codesandbox](https://codesandbox.io/s/react-setstate-batching-click-handler-2y1f8 \"Multiple successive setState calls codesandbox example\") to follow along.\n\n```jsx\n...\nhandleClick = () => {\n  const { items } = this.state;\n\n  this.setState({\n    items: [...items, 'apple']\n  });\n  this.setState({\n    items: [...items, 'mango']\n  });\n  this.setState({\n    items: [...items, 'orange']\n  });\n  this.setState({\n    items: [...items, 'pear']\n  });\n};\n...\n```\n\nOpen the above-mentioned codesandbox link and check the console.\n\n1. We will see that the initial output would be `Rendering []`.\n\n![Initial Render](https://ik.imagekit.io/devtoolstech/understanding-react-setstate/1_eJKAfL-EO.jpg?ik-sdk-version=javascript-1.4.3&updatedAt=1642956381569)\n\n2. Once we click the button then the output would be `Rendering [\"pear\"]`.\n\n![After button click](https://ik.imagekit.io/devtoolstech/understanding-react-setstate/2_6hk3gG4q0__.jpg?ik-sdk-version=javascript-1.4.3&updatedAt=1642956381722)\n\n##### Why does this happen?\n\nTurns out React understands the execution context (important to note) and batches the `setState` calls as per that. No matter how many successive `setState` calls we make in a React event handler, it will only produce a single re-render at the end of the event and only last, as the order is preserved, reflects the state.\n\n#### 2. Multiple state updates in one scope using function argument signature\n\nAs we have seen above, only the last `setState` call is reflected. However, we can rectify this using the function argument signature of `setState`</span> rather than object-based. You can use this [codesandbox](https://codesandbox.io/s/react-state-batching-cb-dc6uy \"Multiple successive setState calls using callback codesandbox example\") to follow along.\n\n```jsx\nhandleClick = () => {\n  this.setState((state) => ({\n    items: [...state.items, \"apple\"],\n  }));\n  this.setState((state) => {\n    console.log(state);\n    return {\n      items: [...state.items, \"mango\"],\n    };\n  });\n  this.setState((state) => ({\n    items: [...state.items, \"orange\"],\n  }));\n  this.setState((state) => ({\n    items: [...state.items, \"pear\"],\n  }));\n};\n```\n\n![setState with callback](https://ik.imagekit.io/devtoolstech/understanding-react-setstate/3_YbdXzkaNhG.jpg?ik-sdk-version=javascript-1.4.3&updatedAt=1642956381926)\n\nIn this approach, React queues up the callbacks provided to different `setState` calls and each callback receives the most up-to-date state at that moment as their execution is synchronous. This is confirmed by the following code snippet\n\n```js{6}\nhandleClick = () => {\n  this.setState(state => ({\n    items: [...state.items, 'apple']\n  }));\n  this.setState(state => {\n    console.log(state); // { \"items\": [\"apple\"] }\n    return {\n      items: [...state.items, 'mango']\n    };\n  });\n  ...\n};\n```\n\nAs you can see the `state` received by the second `setState` callback already has the item `apple` in the items array. Since we are still in the React event handler, all the `setState` calls will cause a single re-render.\n\n#### 3. Multiple state updates in lifecycle methods\n\nAs we have seen above React batches `setState` calls. However, in current versions (< 17), this is only true inside **event handlers** and **lifecycle methods**. You can use this [codesandbox](https://codesandbox.io/s/react-setstate-promise-object-8hsjw \"Multiple successive setState calls in lifecycle methods codesandbox example\") to follow along.\n\n```js\n...\ncomponentDidMount() {\n  const data = [\"apple\", \"orange\", \"mango\", \"pear\"];\n  this.setState(state => {\n    return {\n      items: { ...state.items, 1: { id: 1, value: data[0] } }\n    };\n  });\n  this.setState(state => {\n    return {\n      items: { ...state.items, 2: { id: 2, value: data[1] } }\n    };\n  });\n  this.setState(state => {\n    return {\n      items: { ...state.items, 3: { id: 3, value: data[2] } }\n    };\n  });\n  this.setState(state => {\n    return {\n      items: { ...state.items, 4: { id: 4, value: data[3] } }\n    };\n  });\n}\nrender() {\n  const { items } = this.state;\n  console.log(\"Rendering...\", items);\n...\n```\n\n![setState in lifecycle methods](https://ik.imagekit.io/devtoolstech/understanding-react-setstate/4_9Tw2mPouTtr.jpg?ik-sdk-version=javascript-1.4.3&updatedAt=1642956382435)\n\nThere is only one re-render despite multiple state updates. It only happens in React controlled synthetic event handlers.\n\n#### 4. Multiple state updates in AJAX, promises, and setTimeouts\n\nReact understands the execution context. No matter where your AJAX, promise or setTimeout is happening as in inside lifecycle methods or event handlers, React will not batch leading to multiple re-renders. You can use this [codesandbox](https://codesandbox.io/s/react-setstate-batching-click-handler-promise-v5ii9 \"Multiple successive setState calls in promises codesandbox example\") to follow along.\n\n```jsx\n...\nhandleClick = () => {\n  this.setState(state => ({\n    items: [...state.items, \"single\"]\n  }));\n  this.setState(state => ({\n    items: [...state.items, \"render\"]\n  }));\n  return fakeAPI().then(() => {\n    this.setState(state => ({\n      items: [...state.items, \"apple\"]\n    }));\n    this.setState(state => ({\n      items: [...state.items, \"mango\"]\n    }));\n    this.setState(state => ({\n      items: [...state.items, \"orange\"]\n    }));\n    this.setState(state => ({\n      items: [...state.items, \"pear\"]\n    }));\n  });\n};\n...\n```\n\n![setState outside React controlled methods](https://ik.imagekit.io/devtoolstech/understanding-react-setstate/5_4PvVAZpAF.jpg?ik-sdk-version=javascript-1.4.3&updatedAt=1642956382809)\n\nAs we can see the first two `setState` calls causes a single re-render. However, calls inside the promise lead to multiple intermediate re-renders.\n\nAs per the React team, there might be more uniform behaviour from React version 17 where batching of setState will happen regardless of the execution context.\n","languages":[],"editorConfig":{}},"stats":{"views":8634,"used":0,"likes":0},"description":"","published":true,"isActive":true,"tags":["reactjs","frontend","javascript","setstate","ui","code","devtools","react setstate"],"slug":"understanding-react-setstate---rid---eA1TtSO9ANI5xpBvb0nA","isPremium":false,"categories":[],"requires":[],"_id":"5f1dedb6cbec5f7ffc0c2fb2","title":"Understanding React setState","resourceId":"eA1TtSO9ANI5xpBvb0nA","createdAt":1595796918752,"modifiedAt":1643032087017},"currentUser":null,"isOwner":false,"recommendations":{"questions":[{"_id":"625983f11195627fe9f0bf77","content":{"languages":["javascript","typescript"],"difficulty":2},"tags":["javascript","lodash","memo","frontend","interview question","polyfill","problem solving","algorithm","frontend masters","egghead","codedamn","memoize","advanced javascript","frontend fundamentals"],"slug":"how-to-implement-memoize-function-or-javascript-interview-question-or-problem-solving---qid---RxWt8Q1Mr2iwCPJHrkkr","title":"How to implement memoize function | JavaScript Interview Question | Problem Solving","questionId":"RxWt8Q1Mr2iwCPJHrkkr"},{"_id":"61f39ebb1238c849f9e151ec","content":{"languages":["react","html"],"difficulty":2},"tags":["react","javascript","frontend interview question","js interview questions","machine coding round","browser api","dom","audio visualisation","backend","data sync"],"slug":"build-an-audio-recorder-from-scratch-or-javascript-interview-question-or-react---qid---K783XlxLzH7bMytThN2m","title":"Build An Audio Recorder From Scratch | JavaScript Interview Question | React","questionId":"K783XlxLzH7bMytThN2m"},{"_id":"6307a2a177f9961d5b7cbf53","content":{"languages":["javascript","typescript"],"difficulty":1},"tags":["","javascript","problem solving","oops","inhertiance","javascript prototype","methods","javascript interview questions","vanilla js","beginner frontend questions"],"slug":"how-to-implement-a-developer-builder-interface-or-frontend-problem-solving-or-javascript-interview-question---qid---CjH1hGv2r19ouztiDck2","title":"How to implement a Developer Builder Interface? | Frontend Problem Solving | JavaScript Interview Question ","questionId":"CjH1hGv2r19ouztiDck2"},{"_id":"63b2a0f522480f26b3cc1995","content":{"languages":["javascript","typescript"],"difficulty":2},"tags":["","javascript","frontend","array","coding","ui","ux","polyfills","problem solving","array coding questions","frontend problem solving","js","advanced js","codedamn","egghead","leetcode","alogrithms","data structures","javascript framework","devtools tech","frontend interview preparation","interview questions","interview resources","react","blogs","tutorials","youtube","HTML","CSS","programming content","api design","array fill"],"slug":"how-to-implement-array-prototype-fill-javascript-interview-question-or-problem-solving-or-javascript-polyfills---qid---5V39kYWrv68qsUw14khv","title":"How to implement Array.prototype.fill? JavaScript Interview Question | Problem Solving | JavaScript Polyfills","questionId":"5V39kYWrv68qsUw14khv"},{"_id":"63a97bea22480f26b3cbb6ad","content":{"languages":["javascript","typescript"],"difficulty":1},"tags":["javascript","problem solving","interview question","interview preparation","function","toggle functionality","vanilla js","basic js","facebook interview","netflix","google interview questions","frontend interview questions"],"slug":"how-to-create-a-toggle-function-in-javascript-or-frontend-problem-solving-or-javascript-interview-question---qid---gbucvY2jab4e1q6Fo6iV","title":"How to create a toggle function in JavaScript? | Frontend Problem Solving | JavaScript Interview Question","questionId":"gbucvY2jab4e1q6Fo6iV"}],"resources":[{"_id":"6924ac08bf1a48f85e0ddb2d","content":{"difficulty":4,"domain":1,"type":2,"isInternal":false,"languages":[]},"tags":["javascript","promises","frontend","ui","ux","devtools tech","coding","async await","async programming","coding"],"slug":"javascript-promises-complete-course---basics-to-advanced---rid---2lf744w157vmmYfDP14Q","title":"JavaScript Promises Complete Course – Basics to Advanced","resourceId":"2lf744w157vmmYfDP14Q"},{"_id":"61eeae76c596de5b12fea561","content":{"difficulty":4,"domain":2,"type":1,"isInternal":true},"tags":["remix","js framework","dev tooling","sass","css","styling","frontend"],"slug":"setting-up-sass-with-remix-run---rid---lXDyMjDSdDZDXxNcJ2ep","title":"Setting Up SASS With Remix Run","resourceId":"lXDyMjDSdDZDXxNcJ2ep"},{"_id":"62f3547677f9961d5b7c4bdf","content":{"difficulty":4,"domain":2,"type":2,"isInternal":false},"tags":["javascript","frontend coding challenges","reactjs","vanilla js","trello board","clone trello board","devtools tech","frontend masters","javascript interview question"],"slug":"clone-trello-board,-implement-dom-tree,-access-nested-properties-or-frontend-coding-challenges---rid---tNbr11YAsDyhSDHgQNiv","title":"Clone Trello Board, Implement DOM Tree, Access Nested Properties | Frontend Coding Challenges","resourceId":"tNbr11YAsDyhSDHgQNiv"},{"_id":"68ff7a273177c39e854e2efc","content":{"difficulty":1,"domain":2,"type":1,"isInternal":true,"languages":[]},"tags":[""],"slug":"atlassian-senior-frontend-interview-experience---rid---OC3cLlbmom5YGMkPVJmh","title":"Atlassian Senior Frontend Interview Experience","resourceId":"OC3cLlbmom5YGMkPVJmh"},{"_id":"631444c477f9961d5b7cfc27","content":{"difficulty":1,"domain":2,"type":2,"isInternal":false},"tags":["javascript","frontend","web performance"," devtools tech","advanced js","interview preparation","cls","tooling","web.dev","seo","optimise"],"slug":"how-to-improve-performance-of-your-website-or-cumulative-layout-shift-or-part-1---rid---iFdJmQ4rTsUUv72yhH59","title":"How to Improve Performance of Your Website!? | Cumulative Layout Shift | Part 1 ","resourceId":"iFdJmQ4rTsUUv72yhH59"}]}}