React-instantsearch: Question: how to detect and handle errors? (especially apiKey)

Created on 5 Apr 2018  ยท  6Comments  ยท  Source: algolia/react-instantsearch

We are building an SPA which uses Algolia for search-related features. While we periodically renew users apiKey, cases might happen where the key is expired (user reopens his laptop and starts searching right away before any renewal can be made).

I've searched through the documentation but could not find a way to hook an onError callback or even detect when there are similar issues.

Does anyone have pointers?

โ” Question

Most helpful comment

@ArnaudRinquin Thanks for sharing your solution. At the end you don't even need to re-throw the error. You can call a function that will renew the apiKey directly from willReceiveProps.

All 6 comments

A regular error should be thrown when API key is incorrect. In that case you can use an Error boundary around the <InstantSearch />

see https://reactjs.org/docs/error-boundaries.html

You can also use the connector connectStateResults to access the error.

@Haroenv I tried using React error boundaries with success:

class SearchContainer extends React.Component {
  componentDidCatch(error) {
    debugger
    // renew searchToken
  }
  render() {
    const { searchToken, searchState, searchApplicationId } = this.props
    if (!searchToken) {
      return false
    }

    const query = cleanSearchQuery(searchState.get('query'))
    return (
      <InstantSearch
        appId={searchApplicationId}
        apiKey="obviously-invalid" //{searchToken}
        indexName="notes"
        root={{
          Root: 'div',
          props: {
            className: 'flexbox flexbox-no-grow flexbox-no-shrink',
            style: { width: 300 },
          },
        }}
        searchState={{ query, hitsPerPage: HITS_PER_PAGE }}
      >
        <SearchPanel />
      </InstantSearch>
    )
  }
}

I can see the 403s in the debug tools but the debugger isn't stopping and no logs show in my console. This isn't so surprising as I guess these network errors are asynchronous and can't be caught by React (unless InstantSearch specifically rethrows them in a way React can catch).

I coupled it with @samouss solution and it worked but it feels clumsy:

class SearchContainer extends Component {
  componentDidCatch(error, info) {
     debugger
     // renew searchToken
  }

  render() {
    const { searchToken, searchState, searchApplicationId } = this.props
    if (!searchToken) {
      return false
    }

    const query = cleanSearchQuery(searchState.get('query'))
    return (
      <InstantSearch
        appId={searchApplicationId}
        apiKey="obviously-invalid" //{searchToken}
        indexName="notes"
        root={{
          Root: 'div',
          props: {
            className: 'flexbox flexbox-no-grow flexbox-no-shrink',
            style: { width: 300 },
          },
        }}
        searchState={{ query, hitsPerPage: HITS_PER_PAGE }}
      >
        <SearchErrorCatcher />
        <SearchPanel />
      </InstantSearch>
    )
  }
}

const SearchErrorCatcher = connectStateResults(
  class SearchErrorCatcher extends Component {
    error = null

    componentWillReceiveProps(nextProps) {
      if (this.error && !nextProps.error) {
        this.error = null
      }
      if (!this.error && nextProps.error) {
        // only throw on new errors
        throw nextProps.error
      }
    }
    render() {
      return null
    }
  }
)

@ArnaudRinquin Thanks for sharing your solution. At the end you don't even need to re-throw the error. You can call a function that will renew the apiKey directly from willReceiveProps.

Oh I know I don't have to, but it feels cleaner.

Anyway, It'd be nice to have a proper Error handling as this solution seems clunky. @Haroenv don't you think the Error Boundary not working is a bug and should be addressed? An onError prop on the InstantSearch could work as well.

The error boundaries are used to catch error related to the rendering. This one is not related to the rendering, you can recover it independently from React (see Error Boundaries).

You are right a prop onError could also work, I like the approach with the declarative SearchErrorCatcher. It act a bit like an error boundaries at the end, it catch the network error of InstantSearch. We could provide a widget out of the box it will feels a bit more natural.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

afgoulart picture afgoulart  ยท  4Comments

oznekenzo picture oznekenzo  ยท  3Comments

flouc001 picture flouc001  ยท  5Comments

noclat picture noclat  ยท  3Comments

denkristoffer picture denkristoffer  ยท  4Comments