The "React + Relay + GraphQL" combo is the most advanced and handiest frameworks suite to build any browser app now. Among these 3, Relay is relativley harder to learn, due to it's evolving API: Container → Hooks.

In this note, based on my 1st hand experience at Facebook, I am going to share why the new RelayHooks is better than RelayContainers.

Definitions

RelayContainer is a React Component which is usually the root of a Relay component tree, like QueryRenderer, FragmentContainer, PaginationContainer, etc.

QueryRenderer handles fetching your query and uses the render prop to render the resulting data.

FragmentContainer won't directly fetch the data; instead, the data will be fetched by a QueryRenderer ancestor at the root, which will aggregate all of the data needed for a tree of Relay components, and fetch it in a single round trip.

None
RelayContainer Example

RelayHooks is an API similar to ReactHooks, includes API like useFragment, useLazyLoadQuery. It separates the data loading logic and React component rendering code.

None
RelayHooks Example

Note: Relay components will interop correctly regardless of whether they were written as Relay Hooks or as Relay containers.

Benefits

Simple

Hooks are functions that have specific inputs and outputs. It's clearer than the "magic" that happens in Higher Order Components, where the prop you pass from above is not the same as the prop you receive inside the component.

It also allows us to not pollute the React tree with multiple nested layers of Higher-Order Components that wrap your actual components like the refetch and pagination containers.

Typesafe

Hooks are also a lot simpler to Flow type, and with Relay Hooks we were able to guarantee better type safety than we could with our HOC / Renderer APIs.

They are easier to reason about and require less indirection, and are substantially easier to debug.

Concurrent-Safe

Hooks have more capabilities compared to their container counterparts, for example by being integrated with Suspense for loading states, and providing new capabilities such as directly rendering data that is cached in the Relay store, which were previously not available.

It also allows you to use the newer usePreloadedQuery APIs, which cut down on null renders, unexpected suspense, and accidental over fetching.