Here's Why You Need To Avoid Derived States in ReactJS

Here's Why You Need To Avoid Derived States in ReactJS

Learn how Derived States can cause performance issues and re-renders

·

3 min read

Introduction

ReactJS, a popular JavaScript library for building user interfaces, emphasizes the importance of state management in creating interactive UIs. However, when managing state, one of the common pitfalls developers fall into is using derived state.

What exactly is a Derived State?

As the name suggests, the derived states are the states which are derived from props. In other words, when a state uses props in the form of its default value, then, the state is called a derived state.

image.png

What are the issues with Derived States?

As one can observe, using the Derived States lead to Two Sources of Truth inside a single component. Originally, the props acted as a single Source of Truth for the component. When a derived state is created, it gets diverged from the props and becomes out of sync. It can lead to issues such as -

  1. Unwanted re-renders

  2. Accidental props mutation

  3. Performance concerns

  4. Multiple Sources of Truth and many other anti-patterns

  5. Increased Complexity

Solutions

1. Compute Values Inline

Instead of storing derived values in the state, compute them directly inside the render or return statements. For instance, in the MyComponent example, you can simply use items.length without storing it in state:

function MyComponent({ items }) {
  return <div>Total items: {items.length}</div>;
}

This keeps your component’s state minimal, avoids unnecessary renders, and ensures the UI is always in sync with the data.

2. Use Memoization for Expensive Calculations

If the derived value is expensive to compute (e.g., running a filter or sort operation on a large array), you can use the useMemo hook to cache the result and avoid recomputing it unnecessarily.

function MyComponent({ items }) {
  const itemCount = useMemo(() => items.length, [items]);

  return <div>Total items: {itemCount}</div>;
}

Here, useMemo ensures that the items.length is only recalculated when the items prop changes, preventing unnecessary calculations on each render.

3. Lift State Up

If you find yourself needing to sync derived state with multiple components, consider lifting the state up. Move the source of truth higher up the component tree and pass it down via props to the components that need it. This ensures that all components share a single, consistent state.

4. Use Custom Hooks for Shared Logic

For complex derived state logic that’s needed across multiple components, you can encapsulate the logic into custom hooks. This allows you to reuse the logic without duplicating state management or cluttering your components.

function useItemCount(items) {
  return useMemo(() => items.length, [items]);
}

function MyComponent({ items }) {
  const itemCount = useItemCount(items);

  return <div>Total items: {itemCount}</div>;
}

By using custom hooks, the derived logic is abstracted, making your components simpler and more focused on their main responsibilities.

Conclusion

Derived state in React often introduces more problems than it solves. It can lead to inconsistencies, unnecessary re-renders, and increased complexity in your code. Instead, favor direct computations, memoization, lifting state up, or using custom hooks to avoid these issues. By adhering to React’s core principle of a single source of truth and keeping your state management lean, you can ensure that your applications remain efficient, maintainable, and bug-free.

Avoiding derived state is a best practice that will help you build more predictable and performant React applications!

Did you find this article valuable?

Support Utkarsh by becoming a sponsor. Any amount is appreciated!