ReactJS:如何在父组件中显示子组件的错误

7
我希望在我的父级 react 组件中显示一个错误消息,如果子元素发生错误。
在这种情况下,例如在 GrandChild 组件中,错误会被捕获为 Apollo mutation 调用。
当然,我可以在父组件中创建一个函数来设置错误的状态值,并将该函数传递给每个子元素、孙子元素等。但是,由于我的结构有点复杂,这意味着需要做很多工作。这就是为什么我考虑使用 react 错误边界。但这是正确的用例吗?
由于我正在使用 nextJS,每个 throw Error 都会在开发模式下显示一个错误堆栈跟踪,因此不可能将错误显示为消息。
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)

为了在我的NextJS应用程序中使用错误边界,我只需要添加_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>
  }
}

我想把它加到_app.js文件中。但我不确定这是否是正确的方法……而且我不知道如何将错误缩小到Component


1
请查看 componentDidCatch https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html - quirimmo
@quirimmo请看一下更新后的帖子:我在我的NextJS应用程序中使用componentDidCatch,但这会导致在开发模式下始终显示堆栈跟踪,因此我无法在组件中显示错误。 - user3142695
阅读我分享的链接。他们也谈到了这个问题。 - quirimmo
在NextJS中,堆栈跟踪不仅会传递到控制台,还会显示在屏幕上。因此,在出现错误时,应用程序将不再可见(在开发模式下)。 - user3142695
componentDidCatch 只是其中的一部分,您还需要创建一个实现 componentDidCatch 的错误边界组件,以便它可以返回一些错误状态,并基于该状态返回一个回退组件。请参见 https://reactjs.org/docs/error-boundaries.html 。请注意,它会转储全屏堆栈跟踪 "模态",右上角有一个 "X" 用于关闭它并返回到您的应用程序。 - Drew Reese
1个回答

1
  1. 最佳实践是使用React状态管理,例如reduxfluxible。 如果您正在使用React状态管理,则可以通过从child.js分派消息并在parent.js中连接到Redux存储来轻松获取错误消息。

  2. 如果您决定使用像您所描述的函数,您可以将函数传递给子元素,让子元素调用该函数。

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)


1
React 通过错误边界提供了一种默认的方式来处理从任何渲染后代(不仅仅是直接子组件)传递上来的错误。这还通过生命周期函数给你机会去更新任何需要使用的 redux 或应用程序状态。不必重复发明轮子。React 的错误边界的工作原理类似于 try/catch 块,最近的边界(catch)会处理错误。 - Drew Reese

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接