DEV Community

Daniel Bayerlein
Daniel Bayerlein

Posted on • Updated on

Migrate react-apollo from v2 to v3 in conjunction with AWS AppSync

The implementation between Apollo and AWS AppSync is very good, but some time ago version 3 of react-apollo was released. Unfortunately this version is no longer compatible with the aws-appsync package.

The latest version of react-apollo provides new React Hooks and introduces a new monorepo structure.

You'll find an issue on GitHub that describes the incompatibility:

React-apollo 3.0 with aws-appsync-react #448

Xocix avatar
Xocix posted on

Do you want to request a feature or report a bug? Bug

What is the current behavior? Installing react-apollo 3.0 makes the Rehydrated component stop working. Going back to react-apollo 2.5.8 makes it work again

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Error message recieved: The context client is marked as required in Rehydrated, but its value is undefined.

What is the expected behavior? Rehydrated should have a client to be able to rehydrate

I didn't follow up on it anymore, because I thought there would be an update to fix the problem soon. But that's not what happened 🙃. The issue now contains 51 comments. Between all the comments with the question about "the current status" is hidden the solution.

Implementation with react-apollo version 2.x

In this example I use the aws-appsync, aws-appsync-react and react-apollo package. Your implementation should probably look like the following:

import React from 'react'
import ReactDOM from 'react-dom'
import Auth from '@aws-amplify/auth'
import AWSAppSyncClient from 'aws-appsync'
import { ApolloProvider } from 'react-apollo'
import { Rehydrated } from 'aws-appsync-react'

import App from './containers/App'
import AppSyncConfig from './aws-exports'

const appSyncConfig = {
  url: AppSyncConfig.graphqlEndpoint,
  region: AppSyncConfig.region,
  auth: {
    type: AppSyncConfig.authenticationType,
    jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()
  },
  disableOffline: true
}

const appSyncOptions = {
  defaultOptions: {
    watchQuery: {
      fetchPolicy: 'cache-and-network'
    }
  }
}

const client = new AWSAppSyncClient(appSyncConfig, appSyncOptions)

ReactDOM.render(
  <ApolloProvider client={client}>
    <Rehydrated>
      <App />
    </Rehydrated>
  </ApolloProvider>,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

Implementation with react-apollo version 3.x:

⚠ī¸ This solution does not include offline support. ⚠ī¸

With the latest version of react-apollo (3.x), the implementation also changes. For the new implementation you need the aws-appsync-auth-link, aws-appsync-subscription-link, apollo-link, apollo-client, apollo-cache-inmemory and @apollo/react-common package.

import React from 'react'
import ReactDOM from 'react-dom'
import { createAuthLink } from 'aws-appsync-auth-link'
import { createSubscriptionHandshakeLink } from 'aws-appsync-subscription-link'
import { ApolloProvider } from '@apollo/react-common'
import { ApolloLink } from 'apollo-link'
import ApolloClient from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import Auth from '@aws-amplify/auth'

import App from './containers/App'
import AppSyncConfig from './aws-exports'

const config = {
  url: AppSyncConfig.graphqlEndpoint,
  region: AppSyncConfig.region,
  auth: {
    type: AppSyncConfig.authenticationType,
    jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()
  }
}

const client = new ApolloClient({
  link: ApolloLink.from([
    createAuthLink(config),
    createSubscriptionHandshakeLink(config)
  ]),
  cache: new InMemoryCache(),
  defaultOptions: {
    watchQuery: {
      fetchPolicy: 'cache-and-network'
    }
  }
})

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

Ready for react-apollo 3.x

Now you can use the latest features of Apollo. đŸĻĻ

Discussion (3)

Collapse
danielbayerlein profile image
Daniel Bayerlein Author • Edited

ℹī¸ Meanwhile there is a new package from Apollo called @apollo/client.

  1. npm uninstall @apollo/react-common apollo-link apollo-client apollo-cache-inmemory
  2. npm install @apollo/client
  3. Replace the obsolete imports with the new ones:
import React from 'react'
import ReactDOM from 'react-dom'
import { createAuthLink } from 'aws-appsync-auth-link'
import { createSubscriptionHandshakeLink } from 'aws-appsync-subscription-link'
- import { ApolloProvider } from '@apollo/react-common'
- import { ApolloLink } from 'apollo-link'
- import ApolloClient from 'apollo-client'
- import { InMemoryCache } from 'apollo-cache-inmemory'
+ import { ApolloProvider, ApolloClient, ApolloLink, InMemoryCache } from '@apollo/client'
import Auth from '@aws-amplify/auth'
Enter fullscreen mode Exit fullscreen mode
Collapse
frivolta profile image
Filippo Rivolta • Edited

not working mate: Argument of type '{ url: string; region: string; auth: { type: string; jwtToken: () => Promise; }; }' is not assignable to parameter of type '{ url: string; region: string; auth: AuthOptions; }'...

Have a look here: github.com/awslabs/aws-mobile-apps...

Collapse
danielbayerlein profile image
Daniel Bayerlein Author

Just tested again and it works for me. Can you describe your problem a bit? Which versions do you use?