Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS: How to display an child component error in parent component

I would like to display an error message on my parent react component if an error occurs on a child element.

In this case an error would be a catch of a apollo mutation call for example as you can see in the GrandChild component.

Of course I could create a function in the parent component which sets a state value for the error and pass the function down to every child, grandchild and so on. But as my structure is a bit complicated it would mean a lot of work. That's why I thought of using react error boundaries. But is this the correct use case?

As I'm using nextJS, every throw Error will display an error stacktrace in development mode, so it is impossible to display the error as a message

Parent.js

export class Parent extends Component {
  render () {
    return (
      { /* if there is an error in any child component, it should be displayed here */
        this.props.error &&
        <Message>{error}</Message>
      }
      <Child {...props} />
    )
  }
}

GrandChild.js

class GrandChild extends Component {
  doAnything () {
    return this.props.assumeToFail({
      variables: { id: '123' }
    }).catch(error => {
      console.error(error) // <-- this error should be given back to parent
      throw new Error('fail') // <-- should I throw the error or call a custom function?
    })
  }

  render () {
    return (
      <Button onClick={this.doAnything().bind(this)}>anything</Button>
    )
  }
}

export default graphql(exampleMutation, { name: 'assumeToFail' })(GrandChild)

To use the error boundaries in my nextJS application I just have to add

_app.js

class MyApp extends App {
  componentDidCatch (error, errorInfo) {
    console.log('CUSTOM ERROR HANDLING', error)
    // How do I get the error down to 'Component' in render()?
    super.componentDidCatch(error, errorInfo)
  }

  render () {
    const { Component, pageProps, apolloClient } = this.props
    return <Container>
      <ApolloProvider client={apolloClient}>
        <Component {...pageProps} />
      </ApolloProvider>
    </Container>
  }
}

to my _app.js file. But I'm not sure if this is the way to go... and I don't know how to get the error down to the Component.

like image 555
user3142695 Avatar asked Jan 05 '19 07:01

user3142695


1 Answers

  1. The best way to implement this is by using react state management like redux or fluxible. If you are using react state management, then you can call the action by dispatch the message from the child.js and connect to redux store in the parent.js to get the error message easily.

  2. If you decide to use function like what you have described, you can pass a function to the children and let the children call that function.

Parent.js

export class Parent extends Component {
  state = {
    error: null,
  }

  render () {
    return (
      { /* if there is an error in any child component, it should be displayed here */
        this.state.error &&
        <Message>{this.state.error}</Message>
      }
      <Child
        {...props}
        defineError={(errMsg) => setState({ error: errMsg })}
      />
    )
  }
}

GrandChild.js

import PropTypes from 'prop-types';

class GrandChild extends Component {
  static propTypes = {
    defineError: PropTypes.func,    
  }

  doAnything () {
    return this.props.assumeToFail({
      variables: { id: '123' }
    }).catch(error => {
      this.props.defineError(error);
      console.error(error) // <-- this error should be given back to parent
      throw new Error('fail') // <-- should I throw the error or call a custom function?
    })
  }

  render () {
    return (
      <Button onClick={this.doAnything().bind(this)}>anything</Button>
    )
  }
}

export default graphql(exampleMutation, { name: 'assumeToFail' })(GrandChild)
like image 142
Darryl RN Avatar answered Oct 02 '22 16:10

Darryl RN