State Management in a React App in 2021

Presentational Components

The separation of the presentational and container components was a decision inspired by Dan Abramov’s blog post.

  1. Only responsible for the DOM markup.
  2. They get data via props and communicate back only via callbacks we passed on as props.
  3. They might have a state, but most of the time, the state is lifted up to a container component and passed to the presentational component via props.
  4. Since presentational components are loosely coupled it’s really easy to reuse them.

Container Components

This is where most of the business logic happens. Container components “contain” presentational components. Container components are responsible for…

  1. Fetching data from backend APIs and forward them as props for presentational components.
  2. Composing dispatchable actions as callbacks for presentational components.
  3. Passing data from global store to presentational components.
  4. Storing local state/callbacks to trigger actions lifted from presentational components.


Previously I used to fetch data from APIs via redux but I would discourage that now because,

  1. Lots of boilerplate code to fetch data from an API. It’s a boring repetitive task.
  2. Pollutes the global state.
  3. Having to make redux state async adds additional complexity to the code base.
  4. API calls are duplicated if we want the same data in several components. So it impacts application performance. Of course, you can dedupe them with prop drilling but again it’s additional complexity.
  5. Duplicated API calls also mean additional renderings. Again it impacts application performance.

Alternative Approach to Data fetching — Custom Hooks

Custom Hooks allow us to extract component logic into reusable functions. It’s not something specific for data fetching but let’s focus on our use case for now. Instead of building our own hooks from the scratch, I opt to use the SWR library which addresses the problems above plus a bit more. There are alternatives like React Query too.

  1. A builtin cache for request deduplication
  2. Builtin optimistic rendering — first return the muted data from cache (stale), then send the fetch request (revalidate), and finally, come with the up-to-date data.
  3. Automatic retry on error.
  4. Polling on interval.
  5. Data revalidation on focus (If the user switch browser tabs or returned after locked ).

Redux Store

Since we use custom hooks for data we only have few use cases to use the redux store. as I said earlier we might be better off without redux.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store