reactjsgoogle-analytics-apireact-hoc

React HOC to handel child component API failure


I am using a component from a library which accepts an accessToken as a props. Like <AnalyticsChart accesstoken={this.state.token} /> and based on the token, it makes an API call and renders an UI based on the result. Now, if the accesstoken has expired, it doesn't have a callback props to notify the the parent component (over which I have complete control).

SO, is there a way to build an Higher Order Component which could listen for API requests made by the child components, or just maybe watch for DOM changes to see if nothing is rendered for a long time?

Example-

export default MyComponent extends Component{
    render(){
        <AnalyticsComponent accesstoken={this.props.token} />
    }
}

Solution

  • You can have a withFetch HOC to inject your modified fetch function or a simple custom hook.

    1. HOC Implementation

    // UNTESTED
    function withFetch(Component) {
      return function(props) {
        const [error, setError] = React.useState(false);
    
        // modified fetch
        const doFetch = React.useCallback((url, options) => {
          try {
            fetch(url, options)
            // proceed if successful
          } catch(error) {
            setError(true);
            // TODO: add other states to store error message
          }
        }, [params])
    
        // run effect every time there's fetch error
        React.useEffect(() => {
          if (error) {
            // TODO: do something
          }
        }, [error]);
    
        return <Component fetch={doFetch} {...props} />
      }
    }
    
    const EnhancedComponent = withFetch(MyComponent)
    return <EnhancedComponent accessToken="some token" />
    

    2. Custom Hook

    function hasFetchError(url, options) {
      const [error, setError] = React.useState(false);
    
      React.useEffect(() => {
        async function doFetch() {
          try {
            await fetch(url, options)
            // do something with response
          } catch(error) {
            setError(true);
          }
        }
        doFetch();
      }, [url, options])
    
      return error;
    }
    
    // Usage:
    function MyComponent(props) {
      const error = hasFetchError(props.url, props.options);
      if (error) {
        // do something
      }
    }