React Apollo
React bindings for Apollo Client — hooks, render-prop components, and a graphql() HOC for querying, mutating, and subscribing to GraphQL data.
Repository Health
Technical Analysis
React Apollo is the original set of React integrations for Apollo Client, published as a single package that re-exports the @apollo/react-common, @apollo/react-components, @apollo/react-hoc, @apollo/react-hooks, and @apollo/react-ssr sub-packages. It gives React applications three different ways to talk to a GraphQL endpoint through Apollo Client: the useQuery/useMutation/useSubscription/useLazyQuery/useApolloClient hooks, the Query/Mutation/Subscription render-prop components, and the graphql() higher-order component for wrapping class or function components with GraphQL data props. It also ships getDataFromTree/renderToStringWithData helpers for server-side rendering GraphQL-backed pages before they reach the client.
The project was the standard way to connect React to Apollo Client from 2016 through Apollo Client 2, and its final 4.0.0 release folded all of its sub-packages into thin re-export shims pointing at @apollo/client (>= 3), which now ships its own React bindings directly. react-apollo itself is frozen at 3.1.5 and formally deprecated, but it remains a distinct, separately versioned and downloaded npm package — still pulled in by a large number of pre-Apollo-Client-3 codebases — and is catalogued here as its own entry rather than folded into @apollo/client.
What You Get
- Three integration styles -
useQuery/useMutation/useSubscription/useLazyQuery/useApolloClienthooks,Query/Mutation/Subscriptionrender-prop components, and agraphql()higher-order component, all built on the same underlyingapollo-clientinstance. - Server-side rendering helpers -
getDataFromTreeandrenderToStringWithDatawalk a React tree, execute every GraphQL query it contains, and return fully-resolved markup for SSR. - Shared context provider -
ApolloProvider/ApolloConsumerfrom@apollo/react-commonexpose the Apollo Client instance to every hook, component, and HOC in the tree via React context. - TypeScript-first types - full generic typings for query/mutation results, variables, and component props across all three integration styles.
Common Use Cases
- Migrating from the HOC pattern to hooks - teams on class components using
graphql()gradually adoptinguseQuery/useMutationin new function components without switching Apollo Client versions. - Server-rendered GraphQL pages - Next.js/Express apps calling
getDataFromTreeto pre-fetch every query in a page before sending HTML to the client. - Testing GraphQL components - using
@apollo/react-testing’sMockedProviderto mock network responses in Jest/Testing Library suites. - Legacy Apollo Client 2.x codebases - projects still on
apollo-client^2.6 that need React bindings compatible with that major version, prior to migrating to@apollo/client3.
Under The Hood
Architecture
The package is organized as a Lerna monorepo with clear separation of concerns: @apollo/react-common (packages/common/src/index.ts) hosts the shared ApolloContext/ApolloProvider and document-type parsing used by every other package; @apollo/react-hooks implements useQuery/useMutation/useSubscription/useLazyQuery/useApolloClient as thin functions (packages/hooks/src/useQuery.ts) delegating to useBaseQuery (packages/hooks/src/utils/useBaseQuery.ts), which owns a per-component QueryData instance (packages/hooks/src/data/QueryData.ts) extending an abstract OperationData base class (packages/hooks/src/data/OperationData.ts) that centralizes client resolution, options diffing, and subscription lifecycle across queries, mutations, and subscriptions; @apollo/react-components and @apollo/react-hoc (packages/hoc/src/graphql.tsx, query-hoc.tsx, mutation-hoc.tsx, subscription-hoc.tsx) both wrap those same data classes to expose render-prop and HOC APIs respectively, so all three integration styles share one execution core rather than three independent implementations; @apollo/react-ssr layers getDataFromTree/renderToStringWithData on top by walking the React tree and calling each component’s fetchData(); the outward-facing react-apollo package (packages/all/src/index.ts) is a pure barrel re-export of the other sub-packages with no logic of its own. Changing the shared OperationData/QueryData/MutationData/SubscriptionData hierarchy would ripple through hooks, components, and the HOC uniformly — exactly the intended blast radius for a shared core.
Tech Stack
Written in TypeScript 3.8, compiled per-package via tsc (each package’s config/tsconfig.json extending a shared base config) and bundled to CJS/ESM with Rollup (rollup-plugin-typescript2, rollup-plugin-terser); each sub-package depends on apollo-client ^2.6.4 and graphql ^14.3.1 as peer dependencies, plus @wry/equality for deep-equal checks and ts-invariant for runtime assertions. The monorepo is orchestrated with Lerna 3.x (independent versioning), tests run on Jest 24 with ts-jest across three separate configs (ESM, built-CJS, built-UMD) driven by CircleCI, and bundle size is enforced via bundlesize with per-package byte budgets. React is a peer dependency (^16.8.0, the first hooks-capable release), and @testing-library/react backs the test suite.
Code Quality
37 test files span the sub-packages, covering unit tests per hook (useQuery, useMutation, useSubscription, useLazyQuery, useApolloClient), scenario-based suites under the HOC package (lifecycle, polling, skip, errors, updateQuery for both queries and mutations), and dedicated SSR tests for getDataFromTree — run three ways in CI (ESM, built-CJS, built-UMD) to catch bundling regressions. Error handling is explicit and typed: OperationData.refreshClient() throws via ts-invariant with a descriptive message when no Apollo Client is found in context, and option changes are diffed with @wry/equality rather than swallowed. Naming is consistent (use* for hooks, with* for HOC factories, *Data for internal execution classes), the codebase is fully typed in strict TypeScript with generated .d.ts typings shipped per package, and CI enforces Prettier formatting and TypeScript compilation, though there’s no dedicated linter step beyond tsc.
API Design
The library’s central design bet is letting three different React idioms — hooks, render-prop components, and a class-oriented HOC — share one execution core (OperationData/QueryData/MutationData/SubscriptionData), so a codebase built on graphql() HOCs can adopt useQuery in new components incrementally without duplicating subscription or refetch logic, and both styles read the same ApolloProvider context. Boilerplate to get started is low: a single ApolloProvider at the root, then useQuery(QUERY) or <Query query={QUERY}>{...}</Query> at the call site. getDataFromTree’s recursive walk-and-await-every-query approach for SSR was comparatively rare among GraphQL client bindings of that era, though the underlying ObservableQuery-per-operation model was standard Apollo Client 2.x design rather than something original to this package — and the project was ultimately deprecated in favor of folding this exact functionality directly into @apollo/client.