Search code examples
reactjsgraphqlapollo

how to use multiple versions of Apollo client in single project


Im in the process on taking over an older React/Apollo/GraphQL project, which are currently not using hooks such as useQuery, useMutation etc.. So im trying to make an upgrade.

I've installed the package @apollo/react-hooks, and replaced ApolloProvider in my App.js

//import { ApolloProvider } from 'react-apollo'; //Old
import { ApolloProvider } from '@apollo/react-hooks'; //New

<ApolloProvider client={apolloClient}>......</ApolloProvider>

This however result in an error when running the application:

index.mjs?8baf:1 Uncaught ReferenceError: module is not defined at eval (index.mjs?8baf:1) at Module../node_modules/graphql/index.mjs (vendors.aa829d69df1a68216354.js:7568) at webpack_require (app.aa829d69df1a68216354.js:780) at fn (app.aa829d69df1a68216354.js:148) at eval (index.js:3) at Object../node_modules/@apollo/client/utilities/index.js

My package.json has the following packages related:

"react-apollo": "^2.0.1",
"react": "^16.14.0",
"apollo-cache-inmemory": "^1.1.12",
"apollo-client": "^2.6.10",
"@apollo/react-hooks": "^4.0.0",
"apollo-link": "^1.2.2",
"apollo-link-batch-http": "^1.2.2",
"apollo-link-context": "^1.0.8",
"apollo-link-error": "^1.0.9",
"apollo-link-http": "^1.5.4",
"apollo-link-ws": "^1.0.8",
"apollo-utilities": "^1.0.11"

If I try to use the ApolloProvider from 'react-apollo', I can run my application, but when adding :

import {useQuery} from '@apollo/react-hooks';

The application wont load.

I hope someone has experienced the same before who has a solution.. Thanks in advance


Solution

  • Maybe you need to go through the Apollo docs once again.

    Here is the link for Introduction to Apollo Client for React.

    Taken from Apollo Docs for React:

    import React from 'react';
    import { render } from 'react-dom';
    
    import { ApolloProvider } from '@apollo/client';
    
    function App() {
      return (
        <ApolloProvider client={client}>
          <div>
            <h2>My first Apollo app 🚀</h2>
          </div>
        </ApolloProvider>
      );
    }
    
    render(<App />, document.getElementById('root'));
    

    You need to import ApolloProvider from @apollo/client but not from @apollo/react-hooks.

    And also try to install version 4 of everything related to apollo react. Otherwise, you might encounter numerous errors like I did here


    Edit:

    If you want to combine both versions as you are gradually refactoring the code, try to provide the client created using Apollo v4 directly to the hooks. This is the approach we are currently using in our work.

    useQuery and useMutation has options object which can take client instance. So, try to create a new client instance using the new Apollo v4 package, and instead of passing this new client to ApolloProvider, import the client in every component and provide it to the hooks explicitly using the options object. Once you complete refactoring to the hooks, you can wrap your components in ApolloProvider and remove the client instance in the options object(Even if you don't remove it, it works fine until you keep using the same client(Apollo v4) instance in ApolloProvider and useQuery's and useMutation's options object).


    Edit: 2

    The thing is you are currently using Apollo Client v2.6. But the newer version is Apollo Client v3.x. And the new version of @apollo/react-hooks obviously expects you to use the latest Apollo Client v3.x.

    So, you need to maintain two apollo client files until you refactor your whole codebase to react hooks.

    1. Using apollo-client^2 - To use with your existing code (which you already have)
    2. Using @apollo/client^3 - To use with apollo hooks

    When you do,

    <ApolloProvider client={oldClientCreatedUsingv2}>
          <div>
            <h2>My first Apollo app 🚀</h2>
          </div>
    </ApolloProvider>
    

    The useQuery and useMutation hooks use the client provided in the ApolloProvider. But you can't use this for two ApolloProviders versions obviously. It will be conflicting.

    So, in the ApolloProvider provide your v2 apollo client instance so that your existing codebase is not disturbed. In fact, you don't even have to modify anything here. Let it be how it is now.

    And in the useQuery and useMutation, provide the v3 apollo client instance(i.e., create a client using @apollo/client like this). This is the only thing you have to do.

    Next, while making queries or mutations using hooks, provide the client created using v3 like this everywhere:

    const {loading, error, data } = useQuery(YOUR_QUERY, { client: newClientCreatedUsingv3 });
    

    ApolloProvider is only used to pass down the client so that we don't have to import it in every component and pass it to the hooks of useQuery and useMutation or HOC.

    If you explicitly provide a client while making a request, then it doesn't use the client provided in ApolloProvider.

    Once you completely refactor your code into using react hooks, then you can change the ApolloProvider like this:

    <ApolloProvider client={newClientCreatedUsingv3}>
          <div>
            <h2>My first Apollo app 🚀</h2>
          </div>
    </ApolloProvider>
    

    Now, you can remove the client option from every useQuery and useMutation to further clean up the code as from now onwards useQuery and useMuation will start using the newClientCreatedUsingv3 instance provided in the ApolloProvider.

    Hope this clarifies.