如何优雅地防止 React Native 崩溃?

How do I gracefully prevent crashes in react native?

我想在出现任何错误(语法、未定义、类型错误等)时优雅地显示一个空视图

这是我尝试过的方法,但它似乎并没有优雅地失败。整个应用程序仍然会因此实现而崩溃。

const Parent = (props) => {
    try{
        return (<Child/>) //if Child logic crashes for any reason,  return a blank view.
    }catch(err){
        return <View/>
    }
}

您可以使用 ErrorBoundary https://reactjs.org/docs/error-boundaries.html

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also log the error to an error reporting service
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

在根项目中使用(示例App.js

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

使用 ?. operatortry{} catch(error){} 它将防止您的应用程序崩溃。这是您可以在函数式编程中尝试的示例。

import React, {useEffect, useState } from 'react';
import {Text, TouchableOpacity , View} from 'react-native'

// in order to prevent app from crash use this method

function ShowErrorMessageCompnent () {
    const [error, setError] = useState(false)
    const [item, setItem] = useState({
        id:"1",
        name:"ab"
    })
    const [showerrormessage , setShowErrorMessage] = useState("")
    // if you have an object but unsure of the attibute sof that use this 

    useEffect(() => {
       try{
          let fathername = item?.fathername?.a   // this will thro no Errror
           //let fname = item.fathername.a   // this will throw Error
            //setUnknowfunction("Erro")  // as i dont have this function so it will thorw error
       }catch(err){
        console.log(err)
        setShowErrorMessage(err.message)
        setError(true)
       }
    },[])
   

    if(error){
        return(
            <TouchableOpacity style={{flex:1,justifyContent:"center", alignItems:"center",}}>
                <Text style={{color:"#000"}}>{showerrormessage}</Text>
            </TouchableOpacity>
        )
        }

    return (
            <View style={{flex:1, justifyContent:"center", alignItems:"center",}}>
                <Text style={{color:"#000", fontWeight:"bold"}}>No error</Text>
            </View>
    )
  
  }

  export default ShowErrorMessageCompnent;

你只需要ErrorBoundary,首选的方式是设置一个HOC(Higher-order component)可以处理错误并防止应用程序崩溃。您还可以创建 ErrorBoundary 组件。这是一个 HOC 示例,可能会对您有所帮助。

import React, { Component } from 'react';

export const withErrorBoundary = WrappedComponent => (
  class extends Component {
    constructor(props) {
      super(props);
      this.state = { error: null, errorInfo: null };
    }

    componentDidCatch = (error, errorInfo) => catchFunc(error, errorInfo, this)

    render() {
      if (this.state.errorInfo) {
        return handleError(this)
      }
      // Normal, just render children
      return <WrappedComponent {...this.props} />;
    }
  }
);

const catchFunc = (error, errorInfo, ctx) => {
  // catch errors in any components below and re-render with error message
  ctx.setState({
    error: error,
    errorInfo: errorInfo
  })
  // log error messages, etc.
}

const handleError = (ctx) => (
  // Error path
  <div style={ctx.props.style || styles.error}>
    <h2>Something went wrong.</h2>
    <details style={{ whiteSpace: 'pre-wrap' }}>
      {ctx.state.error && ctx.state.error.toString()}
      <br />
      {ctx.state.errorInfo.componentStack}
    </details>
  </div>
);

const styles = {
  error: {
    backgroundColor: '#f98e7e',
    borderTop: '1px solid #777',
    borderBottom: '1px solid #777',
    padding: '12px',
  }
}

export default withErrorBoundary;

这里,withErrorBoundry是一个高阶组件,负责通过componentDidCatch捕获包装组件中的任何错误。您需要做的只是导出带有错误边界 HOC 的组件,它会处理底层错误。这是示例用法。

import React from 'react';
import { Text } from 'react-native';
import withErrorBoundary from './withErrorBoundary';

const ExampleComponent = (props) => (
    <Text>{ props.user.name }</Text>
);

export default withErrorBoundary(ExampleComponent);

或者,您也可以创建一个 ErrorBoundary 组件,但与 ErrorBoundary 组件相比,使用 HOC 更简单。

缺点

错误边界不捕获错误,

  1. 事件处理程序
  2. 异步代码(例如 setTimeout 或 requestAnimationFrame 回调)
  3. 服务器端渲染
  4. 在错误边界本身抛出错误

此时您需要将容易出错的代码包装到 try-catch 块中,并从 catch 块中抛出 Exceprion,这将由外部 HOC 进一步处理。在 official docs

阅读更多内容

如果你想制作完整的 crash less 应用程序,那么你应该在 react native 中实现两者

  1. 基于组件的错误
  2. Javascript 基于错误

基于组件的错误处理

最常见的方法是使用 错误边界,您可以使用此库 https://www.npmjs.com/package/react-native-error-boundary

来实现

Javascript 基于错误处理

https://www.npmjs.com/package/react-native-exception-handler

安装

只需安装

yarn add react-native-error-boundary

HOC

像这样HOC

const CustomFallbackComponent = (props: { error: Error, resetError: Function }) => (
  <View>
    <Text>Something happened!</Text>
    <Text>{props.error.toString()}</Text>
    <Button onPress={props.resetError} title={'Try again'} />
  </View>
)

const withErrorBoundries = (props) => (
  <ErrorBoundary FallbackComponent={CustomFallbackComponent}>
    {props.children}
  </ErrorBoundary>
)

用法

像这样包装每个可以抛出异常的组件

export default withErrorBoundries(ComponentA);

or
export const ComponentC=withErrorBoundries(ComponentB)