What do you do when you have dynamic data in React? Use state!
A component's state, unlike its props, can change during the component's life. For a prop to change, its parent would need to send down new props which the component would use to remake itself, taking the new props into consideration. The React Hook, useState gives us a way to maintain and update information in a component without needing the parents to continuously send the dynamic information down to the child components as props.
With React Hooks we can write React applications with only function components.
useState is a function that is imported from React, it's a React Hook, which lets us "hook" into React's internal state inside of our function component. Once imported you can call a hook inside of the component.
Once imported into your component's file, you can call it inside of the function component.
When it is called inside of the function component this now creates a new dynamic state variable that the function has access to. This state variable has an initial value of whatever is passed into useState() when it is called. This can be any primitive value: string, integer, boolean, null, etc. useState also returns an array that contains two things. The first is the current value for the state variable. The second thing that the array contains is a setter function to update the state variable.
The state variable is pretty straightforward, it is what the state is. This variable can change, their value can be updated, due to the setter function. The setter function just sets or updates the state. To do this, to update the state, you call the setter function. This function also re-renders the component. When it does, it tells React to call that function again and figure out what changed and what to return based on the new state.
useState Step-By-Step Recap:
- Import the useState hook:
- Set up the initial state, use the same naming convention for variable and setter function.
- ex: [state, setState] or [banana, setBanana] or [fooBar, setFooBar], etc you get the idea.
- Use the state variable in the component.
- Call the setter function to update the state.
Here, when the button element is clicked, it runs the increment function. This calls on the setCount function to update the count variable by one and re-render the component.
When a site is loaded, the initial render is the ReactDOM.render(), which builds all of the initial JSX by calling all components once. Then when the state is updated in a component somewhere in the application, the setState function of useState re-renders that component and any of its child components with the new state. And then each and every time that state is modified React automatically re-renders the component and its child components and updates the DOM based on these new values.
State is only for the values that are expected to change, the dynamic values, during the component's life. So only use it where needed. The more state you have, the more difficult it can be to keep track of all of the changes happening.
So, when to use state?
Three Key Questions to determine state:
- Is it passed from a parent via props?
- If so, it's not state!
- Can you compute it based on any other state or props in the component?
- Yes? Not state!
- Does it remain unchanged over time?
- If so, it is not state!!!
Often, several components need to reflect the same dynamic data so the state needs to be lifted to their closest common parent and then passed down to the children as a prop.
When working with arrays and updating state never mutate the array! It's best to make copies of them because React will only re-render the component when we set state with a new value. This means that a copy needs to be made of the original array to pass the setter function instead of mutating the original array directly and passing a reference to the original array. Also, be sure to never mutate state directly.
Need to add to an array? Use the spread operator! You will get a copy of the array with the new value added in.
Do you need to remove something from an array? Use filter! Filter will return a new array based on which elements match the criteria in the callback function.
Do you need to update the array? Map it out! Map will return a new array without mutating the original array!