Principles for structuring state Flashcards
Principles for structuring state
- Group related state. If you always update two or more state variables at the same time, consider merging them into a single state variable.
- Avoid contradictions in state. When the state is structured in a way that several pieces of state may contradict and “disagree” with each other, you leave room for mistakes. Try to avoid this.
- Avoid redundant state. If you can calculate some information from the component’s props or its existing state variables during rendering, you should not put that information into that component’s state.
- Avoid duplication in state. When the same data is duplicated between multiple state variables, or within nested objects, it is difficult to keep them in sync. Reduce duplication when you can.
- Avoid deeply nested state. Deeply hierarchical state is not very convenient to update. When possible, prefer to structure state in a flat way.
The goal behind these principles is to make state easy to update without introducing mistakes. Removing redundant and duplicate data from state helps ensure that all its pieces stay in sync.
Group related state
if some two state variables always change together, it might be a good idea to unify them into a single state variable. Then you won’t forget to always keep them in sync,
Another case where you’ll group data into an object or an array is when you don’t know how many different pieces of state you’ll need. For example, it’s helpful when you have a form where the user can add custom fields.
If your state variable is an object, remember that you can’t update only one field in it without explicitly copying the other fields.
Avoid contradictions in state
Since isSending and isSent should never be true at the same time, it is better to replace them with one status state variable that may take one of three valid states: ‘typing’ (initial), ‘sending’, and ‘sent’.
You can still declare some constants for readability:
const isSending = status === 'sending'; const isSent = status === 'sent';
But they’re not state variables, so you don’t need to worry about them getting out of sync with each other.
Avoid redundant state
If you can calculate some information from the component’s props or its existing state variables during rendering, you should not put that information into that component’s state.
This form has three state variables: firstName, lastName, and fullName. However, fullName is redundant. You can always calculate fullName from firstName and lastName during render, so remove it from state.
Here, fullName is not a state variable. Instead, it’s calculated during render:
const fullName = firstName + ‘ ‘ + lastName;
As a result, the change handlers don’t need to do anything special to update it. When you call setFirstName or setLastName, you trigger a re-render, and then the next fullName will be calculated from the fresh data.
Don’t mirror props in state
A common example of redundant state is code like this:
function Message({ messageColor }) { const [color, setColor] = useState(messageColor);
Here, a color state variable is initialized to the messageColor prop. The problem is that if the parent component passes a different value of messageColor later (for example, ‘red’ instead of ‘blue’), the color state variable would not be updated! The state is only initialized during the first render.
This is why “mirroring” some prop in a state variable can lead to confusion. Instead, use the messageColor prop directly in your code. If you want to give it a shorter name, use a constant
This way it won’t get out of sync with the prop passed from the parent component.