bordeltabernacle
bordeltabernacle

Reputation: 1653

Showing error toast with apollo-link-error

I'm trying to show a toast/snackbar with apollo-link-error, but when I do the error toast shows up repeatedly without stopping, and the loader that shows on loading spins in the background.

multiple error messages in ui

My apollo client contains this code...

const errorLink = onError(handleErrors)

const httpLink: ApolloLink = createHttpLink({
  uri: graphqlUri,
})

const link = ApolloLink.from([errorLink, authLink, httpLink])

where the handleErrors function is passed in in my App.tsx...

const { addToast } = useToasts()

const handleErrors: ErrorHandler = ({ graphQLErrors, networkError }) => {
    if (graphQLErrors) {
      const errors = graphQLErrors.map(({ message }) => message)
      addToast(errors.join(`, `))
    }

    if (networkError) console.log(`[Network error]: ${networkError}`)
  }

  const client = apolloClient(
    token,
    GRAPHQL_URI,
    handleErrors
  )

and then passed into the ApolloProvider. The useToasts hook comes from react-toast-notifications.

I was previously handling the errors in the component...

const { loading, data, error } = useQuery(Query)

if (error) return <div>{error.message}</div>

but have switched from using graphql-yoga to apollo-server on the backend and so am having to handle errors differently.

If I remove the toast notification, and just print to the console instead, it works fine. Why are my toasts being created repeatedly and how can I just show one on error?

Thanks.

Upvotes: 1

Views: 2538

Answers (2)

Kaslie
Kaslie

Reputation: 543

You might have find the solution, but this sample answer might be useful for other people.

NOTE: This answer not using react-toast-notification

import React, { useState, useContext } from 'react'
import ApolloClient from 'apollo-boost'

const ErrorContext = React.createContext([])

const ErrorProvider = () => {
  const [errors, setError] = useState([])
  const handleUpdateError = error => {
    setError([...errors, error])
  }
  const ctx = { handleUpdateError }
  return (
    <ErrorContext.Provider value={ctx}>
      {errors.map(errorMessage => <Toast>{errorMessage}</Toast>)}
      {children}
    </ErrorContext.Provider>
  )
}

class ApolloCustomProviderWithContext extends React.Component {
  construtor(props) {
    super(props)
    
    const { handleUpdateError } = props

    const errorLink = onError(({ graphQLErrors, networkError }) => {
      if (graphQLErrors) {
        const errors = graphQLErrors.map(({ message }) => message)

        handleUpdateError(errors.join(','))
      }
    })
    
    const httpLink = createHttpLink({ uri: "/graphql" });
    
    this._client = new ApolloClient({
      link: errorLink.concat(httpLink),
      cache: new InMemoryCache(),
      
    })
  }
  
  render () {
    return <ApolloProvider client={this._client}>{this.props.children}</ApolloProvider>
  }
}

const ApolloCustomProvider = props => {
  const { handleUpdateError } = useContext(ErrorContext)
  
  return (
    <ApolloCustomProviderWithContext handleUpdateError={handleUpdateError}>
      {props.children()}
    </ApolloCustomProviderWithContext>
  )
}

const Application = () => {
  return (
    <ErrorProvider>
      <ApolloCustomProvider>
        {children}
      </ApolloCustomProvider>
      // Your Application Code
    </ErrorProvider>
  )
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Upvotes: 1

Alan Fitzpatrick
Alan Fitzpatrick

Reputation: 181

Hard to tell without seeing the code as a whole but it seems to be adding a new Toast per render of your component,

You should check how and where this is being called, my guess this is nothing to do with apollo and something to do with rerendering of the component

Also toasts are generally a list that gets added to so it will just grow and grow instead of replacing

Upvotes: 0

Related Questions