{"title":"Managing State in React","url":"https://seanbehan.ca/posts/react-state","description":"useState, what triggers a re-render, and where React state should actually live.","author":"Sean Behan","published":"2021-09-04T20:31:25.000Z","updated":null,"draft":false,"tags":["javascript","programming","react"],"readingMinutes":2,"image":null,"sections":[{"id":"introduction-to-usestate","text":"Introduction to useState","level":2},{"id":"incrementing-a-counter","text":"Incrementing a Counter","level":2},{"id":"managing-list-state","text":"Managing List State","level":2},{"id":"handling-form-input","text":"Handling Form Input","level":2}],"content_format":"text/markdown","content_url":"https://seanbehan.ca/posts/react-state.md","content":"### Introduction to useState\n\nIn React when we want to manage individual state there is a function we can\n\nimport called `useState` that gives us a getter and setter letting React know\n\nwhen it needs to re-render.\n\n```typescript\nimport React, { useState } from 'react';\n\nconst myComponent = () => {\n  const [count, setCount] = 0;\n  ...\n}\n```\n\nThis initializes count as a state variable that can be accessed with `count`\n\nand set with `setCount`.\n\n### Incrementing a Counter\n\nIf we wanted to write a function that incremented count, we could add a button.\n\n```typescript\n...\nreturn (\n    <>\n      <p>Count is: {count}</p>\n      <button onClick={() => setCount(count + 1)}>+1</button>\n    </>\n);\n```\n\nHere we wrapped our text and button in a [React\n\nFragment](https://react.dev/reference/react/Fragment). Since components can only\n\nreturn one DOM parent element, Fragments allow us to return more than one\n\nwithout creating more divs in our markup.\n\nThen I set the `onClick` for button to an inline function that increases count\n\nby 1 using `setCount`. If we were to do this without a state variable, i.e.\n\n`const count = 0` React wouldn't know when to re-render our data.\n\n### Managing List State\n\nThis can be used to hold any state or object however, not just numbers and\n\nstrings. If we wanted to instead append to a list we might write a function\n\nthat gets passed to the `onSubmit` of a form.\n\n```typescript\n...\n[list, setList] = useState([]);\n...\n\nconst onFormSubmit(event) {\n  event.preventDefault();\n  list.push(form.name);\n  setList(list);\n}\n```\n\n### Handling Form Input\n\nChanging all our input `onChange` methods as well to update the state of `form`\n\nwhen the data changes.\n\n```typescript\n...\n<label>\n  <p className={\"text-label\"}>Name:</p>\n  <input\n    onChange={handleSetForm}\n    type=\"text\"\n    name=\"name\"\n  />\n</label>\n...\n```\n\n```typescript\n...\n[form, setForm] = useState({ name: '' });\n...\n\nconst handleSetForm = ({ target: { name, value } }: any) => {\n  setForm((form) => ({ ...form, [name]: value }));\n};\n```\n\nThis updates our form state whenever the data changes. Allowing us to use\n\n`form` to append to our list above whenever the submit button is clicked.\n"}