Skip to content

Instantly share code, notes, and snippets.

@samsch
Created June 4, 2022 00:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samsch/26a57cb1cca7ee76f73d4a80cd853d22 to your computer and use it in GitHub Desktop.
Save samsch/26a57cb1cca7ee76f73d4a80cd853d22 to your computer and use it in GitHub Desktop.
Why React Data Fetching is Hard (right now)

Why React Data Fetching is Hard (right now)

Context

Recently Dan Abramov has been linking drafts of a new documentation page for useEffect, which has kicked off discussion about where you are "supposed" to do data fetching in a "React app". Some of that conversation is happening on Twitter such as here: https://twitter.com/dan_abramov/status/1532540685710147589

Within the draft and repeated on Twitter, there is a recommendation that for data fetching you should use third party libraries as either tools like React Query or useSWR or via frameworks such as Next and Remix which include integrated data fetching solutions. Writing your own data fetching using useEffect is suggested to be only a fallback in case you can't do those things, and not really a preferred recommendation.

This idea is hitting backlash, with a basic detracting idea that boils down to: React is a client side framework, how can it not include as a feature an important and common requirement like data loading.

What is React?

A long running "debate" in the React community is whether React is a "framework" or "just a library". If React is "just" a library, then why does React seem to inform nearly all decisions made for the front end, and not just exist as a tool used in our codebase? If React is a framework, then why doesn't it include data loading, routing, and some other commonly needed features?

My Opinion

React is a framework, but it also doesn't have to be. The vast majority of React users build "React apps" which are structured and organized based on how React works. React can also be used as a "plain" templating engine which can do high performance view updates, but this is very rare.

The React team has made mistakes in the management of React. There are various probable reasons, but not really relevant here. Some of these mistakes are:

  • One big library. Technically react and react-dom are separate, and React Native is a thing, but practically speaking, all of the features of React are centralized into the blob that is those two packages.
  • Outdated documentation. React hooks released in 2019, and in 2022 we're seeing drafts of docs which reflect them properly.
  • Documentation doesn't encourage good overall application structure.

That third point is the crux of the current issue. It comes in a couple pieces, but perhaps the largest is that the docs treat your React code as a standalone application. A major symptom of this is the recommendation of Create React App, which strongly designed around a singular React SPA structure. Another symptom is that the docs skip any examples which would re-render the app from the root with new props.

React itself is largely built with a design that suggests using it as a library more than a framework.

Data Loading

So what does any of this have to do with data loading? Data loading is generally part of the primary task that a client side rendering app needs to do. Within the structure of a singular SPA, it would usually make sense that the general framework for building that SPA should handle data loading. With the result of the above mistake and wide popularity of React as a "framework", it would make sense for React to provide data loading, and people will frequently assume that it does, regardless of what docs literally say. Making that assumption, people land on useEffect, as the only feature in React that really makes sense to use for data loading.

The problem with that is useEffect can't do data loading at all on its own, and setting up data loading using it is a non-trivial task with several nasty pitfalls.

People do it anyway, and regularly get it to just barely work with numerous hidden bugs and gotchas.

So, the answer to why data fetching with React is hard, is that it's more or less intentional. You aren't supposed to do data loading with React directly as currently designed. Data fetching is a non-trivial task that React expects to be handled outside of its own code.

The React Team's Solution

The React team is currently working on Server Components, which can eventually function as a data loading tool. They are also writing recommendations to use third party data loading libraries or frameworks built around React. They do not intend to build a data loading tool for React as a client side framework. (Per my understanding of public indications, primarily from Dan Abramov.)

My Solution

For the problem at hand, the React team needs accelerate the recommendations for using third party data loading libraries. They should even more strongly emphasize that you shouldn't try to build data loading with useEffect directly (either use a third party lib, or at least build a data loading wrapper yourself). They should reframe the documentation to discourage React as a standalone SPA framework tool (such as adding top-down re-rendering examples, and integration examples with common frameworks).

I don't think they should continue developing Server Components to be fitted into React as it currently exists. The React library needs to be modularized. The rendering and component core should be separated from nearly every other feature, with most of the current hooks being separate packages, and ideally even aspects like context being externalized. These user-facing tools should rely on a public low-level API on the core, which is thoroughly documented and also discouraged from being directly used by apps. This way third party frameworks and libraries would be able to extend React functionality much better, and React itself could potentially reach a "done" state, where the library itself would no longer need to be updated regularly (all desirable new features could be reasonably built on top). I don't really expect the React team would be willing to do this, for reasons related to why they made the previously noted mistakes.

What You Should Do

If you need to load data inside "plain" React, use a third party data loading library (*note on this below). Besides React Query and similar, there are also simpler tools like the react-use useAsync and useAsyncFn hooks.

Use React-based frameworks if you are so inclined.

But really, strongly consider if you need to build an SPA structure at all. Render your pages on the server, and only replace parts of the html with smaller independent React trees. Load the data in plain JS code and call React's render when you're done (the server can render a loading spinner for you).

Building "plain React apps" is part of what caused all this trouble. The blame isn't just on the React team, nor just on the community.

Footnote

*Note about using third party libraries

I have seen some arguments that suggest someone "can't" add third party libraries as reason they need React to handle data loading. Considering React itself is a third party library, I find this argument highly suspect. The only defensible reason I've seen basically is "my boss says so". Usually the response to that would be "get a better boss or fix the one you have", but since that's more politics than technical and may not be possible, you might thoroughly reference a third party open source lib and write your own data loading wrapper. Just be careful, it's easy to mess up and hard to be feature-complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment