如何优雅地防止 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>
使用 ?. operator
和 try{} 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 更简单。
缺点
错误边界不捕获错误,
- 事件处理程序
- 异步代码(例如 setTimeout 或 requestAnimationFrame 回调)
- 服务器端渲染
- 在错误边界本身抛出错误
此时您需要将容易出错的代码包装到 try-catch 块中,并从 catch 块中抛出 Exceprion
,这将由外部 HOC 进一步处理。在 official docs
阅读更多内容
如果你想制作完整的 crash less 应用程序,那么你应该在 react native 中实现两者
- 基于组件的错误
- 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)
我想在出现任何错误(语法、未定义、类型错误等)时优雅地显示一个空视图
这是我尝试过的方法,但它似乎并没有优雅地失败。整个应用程序仍然会因此实现而崩溃。
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>
使用 ?. operator
和 try{} 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 更简单。
缺点
错误边界不捕获错误,
- 事件处理程序
- 异步代码(例如 setTimeout 或 requestAnimationFrame 回调)
- 服务器端渲染
- 在错误边界本身抛出错误
此时您需要将容易出错的代码包装到 try-catch 块中,并从 catch 块中抛出 Exceprion
,这将由外部 HOC 进一步处理。在 official docs
如果你想制作完整的 crash less 应用程序,那么你应该在 react native 中实现两者
- 基于组件的错误
- 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)