DEV Community

Andrey Smolko
Andrey Smolko

Posted on

Strive for a minimum required state in a React component

Keep a component state as minimal as possible and avoid unnecessary state synchronization .

🚫 Before refactoring - b is a redundant state which should be sync:

export default function App() {
  const [a, setA] = useState(1);
  const [b, setB] = useState(1);

  function updateA(x) {
    setA(x);
  };

  function updateB() {
    setB(1 + a);
  };

  useEffect(() => {
    updateB()
  },[a])


  return (
    <div>
      <button onClick={() => updateA(a+1)}>Click</button>
        <p>a: {a}</p>
        <p>b: {b}</p>
    </div>
)
};
Enter fullscreen mode Exit fullscreen mode

✅ After refactoring - a is a minimum sufficient state and just derive b from it:

export default function App() {
  const [a, setA] = useState(1);

  function updateA(x) {
    setA(x);
  };

  function updateB() {
    return a+1
  };

  return (
    <div>
      <button onClick={() => updateA(a+1)}>Click</button>
      <p>a: {a}</p>
      <p>b: {updateB()}</p>
    </div>
  )
};
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
erik_slagter profile image
Erik Slagter

Both examples are anti patterns, I would suggest looking into useMemo for derived/calculated properties

Collapse
 
smlka profile image
Andrey Smolko • Edited

May you clarify what is a problem with a second? If it is just about wrap in useMemo then I say "Measure first".

Collapse
 
erik_slagter profile image
Erik Slagter • Edited

I would say calling a function inside the template is not great for visibility and debug-ability. Define const b = useMemo(() => ..., [a]) on top, so you have a clear view of all variables inside your functional component.

Defining state variables doesn't cost anything, replacing them with an uncached function call, is not great.

In your example you are doing some very basic calculation on a + 1, but in real life you want to keep your derived variables in useMemo. Keeping strict to good habits will help you preventing performance bugs. It might not look/feel slow, but it adds a little computation to every render.

Thread Thread
 
smlka profile image
Andrey Smolko • Edited

Regarding first part I agree, it is better for readability to define a separate variable b instead of just a function call.

I would argue that wrap all derived variables in useMemo by default is a good habit. Most of real life function calls which returns derived values are extremely fast. I think you know the phrase about premature optimization and evil=)