A common mistake I see people making while creating their React component is creating extra states and effects. That may cause unexpected bugs and extra renders.
Let's say that we have a simple app that generates a full name based on the value of two given inputs (first and last names) as shown below.
The approach that I mostly see developers using is creating an extra state for the full name, and in an useEffect set this state according to the new values in the inputs:
const [firstName, setFirstName] = useState<string>("");
const [lastName, setLastName] = useState<string>("");
const [fullName, setFullName] = useState<string>("");
useEffect(() => {
setFullName(`${firstName} ${lastName}`);
}, [firstName, lastName]);
That's not the right approach… But, why?
- It doesn't use a single source of truth: Developers in the future will be able to directly set the fullName state without respecting the fact that it should be based on the firstName and lastName states.
- It causes extra renders: basically, every time we have a setState, React re-renders stuff. In this case, because of the extra setState inside the useEffect, for every letter typed into any of the inputs we are gonna have one extra render.
Basically what happens is:
The right approach
When something derives from an existing prop or state we should always calculate it during render time. That avoids bugs that could be generated because of the extra states and increases performance because of the fewer renders.
const [firstName, setFirstName] = useState<string>("");
const [lastName, setLastName] = useState<string>("");
const fullName = `${firstName} ${lastName}`.trim();
With this new approach, our component lifecycle gets reduced to:
Comparing the two approaches
When comparing the two approaches with the name "James Robert" we see that the first approach does twice as much renders and has substantially more code than the second one.
First approach total renders: first render + 2 x number of letters in the name.
Second approach total renders: first render + number of letters in the name.
In this test case, since it is just a proof of concept, we will not see a big difference performance-wise, but in real-life features, we should always care about this kind of issue.
Code
If you want, you can take a look at the code used in the article: