Оригинальный адрес:GitHub.com/hu J IA oh J/ Первоначально…
Когда на странице React Native есть ошибка:
1. В режиме разработки появится страница с красным фоном, показывающая текущую информацию об ошибке кода.
2. В пакетном режиме появится белый экран или флешбэк
режим разработки
пакетный режим
В производственной среде все приложение представляет собой белый экран или мигает из-за ненормальной страницы RN, а взаимодействие с пользователем неудовлетворительное, поэтому аномалию следует зафиксировать и обработать, чтобы улучшить взаимодействие с пользователем.
Для захвата и обработки исключений страниц RN в основном используются два метода:
1. Границы ошибки реакции
2. Модуль React Native ErrorUtils
Границы ошибки реакции
Границы ошибок React (компоненты границ исключений) — это новая концепция, введенная в React 16. Чтобы избежать исключений пользовательского интерфейса в компонентах React, которые вызывают исключения для всего приложения.
Друзья, незнакомые с граничными компонентами исключений React, могут прочитать мою статью:Обработка исключений React из исходного кода
Вот краткое введение:
Границы ошибок — это компонент React, который фиксирует исключения js, сгенерированные всеми компонентами в его дереве подкомпонентов, и отображает указанный нижний пользовательский интерфейс для замены рассматриваемого компонента.
Он может перехватывать исключения в функциях жизненного цикла подкомпонентов, включая функции конструктора и рендеринга.
вместо того, чтобы поймать следующее исключение:
- Обработчики событий
- Асинхронный код (асинхронный код, такой как setTimeout, promise и т. д.)
- Рендеринг на стороне сервера
- Ошибки, возникающие в самой границе ошибки (а не в ее дочерних элементах)
Таким образом, все исключения в жизненном цикле компонента могут быть зафиксированы с помощью компонента границы исключения, а нижний пользовательский интерфейс может быть визуализирован, чтобы предотвратить появление белого экрана или флэшбэка в приложении и улучшить взаимодействие с пользователем. нижний пользовательский интерфейс для облегчения поиска и устранения неисправностей.
Перейдите непосредственно к коду:
with_error_boundary.js
...
function withErrorBoundary(
WrappedComponent: React.ComponentType <CatchCompProps> ,
errorCallback: Function,
allowedInDevMode: boolean,
opt: Object = {}) {
return class extends React.Component <CatchCompProps, CatchCompState> {
state = {
error: null,
errorInfo: false,
visible: false,
}
componentDidCatch(error: Error, errorInfo: any) {
this.setState({
error,
errorInfo,
visible: true,
})
errorCallback && errorCallback(error, errorInfo)
}
handleLeft = () => {
...
}
render() {
const { title = 'Unexpected error occurred', message = 'Unexpected error occurred' } = opt
return (
this.state.visible && (allowedInDevMode ? true : process.env.NODE_ENV !== 'development') ? (
<Modal
visible
transparent
animationType={'fade'}>
<View style={styles.container}>
<View style={styles.header}>
<NavBar
title={title}
leftIcon={'arrow-left'}
handleLeft={this.handleLeft}/>
</View>
<View style={styles.info}>
<Text>{message}</Text>
</View>
<ScrollView style={styles.content}>
<Text> { this.state.error && this.state.error.toString()} </Text>
<Text> { this.state.errorInfo && this.state.errorInfo.componentStack } </Text>
</ScrollView>
</View>
</Modal>
) : <WrappedComponent {...this.props} />
);
}
}
}
export default withErrorBoundary;
Вышеупомянутый компонент React более высокого порядка, и возвращаемый компонент определяетcomponentDidCatch
Функция жизненного цикла, когда в ее дочернем компоненте возникает исключение, это будет выполненоcomponentDidCatch
Функция жизненного цикла, отображающая нижний пользовательский интерфейс
использовать
...
import withErrorBoundary from 'rn_components/exception_handler/with_error_boundary.js';
...
class ExceptionHandlerExample extends React.Component {
state = {
visible: false,
}
catch = () => {
console.log('catch');
this.setState({
visible: true,
});
}
render () {
if (this.state.visible) {
const a = d
}
return (
<View style={styles.container}>
<Navbar
title={'Exception Handler'}
handleLeft={() => this.props.history.go(-1)}/>
<View style={styles.content}>
<TouchableOpacity onPress={this.catch}>
<View>
<Text>Click me</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
// 异常边界组件的使用
export default withErrorBoundary(ExceptionHandlerExample, (error, errorInfo) => {
console.log('errorCallback', error, errorInfo);
}, true);
Мы также сказали выше, что компоненты границы исключений могут захватывать исключения в функциях жизненного цикла подкомпонентов, включая конструкторы и функции рендеринга.
вместо того, чтобы поймать следующее исключение:
- Обработчики событий
- Асинхронный код (асинхронный код, такой как setTimeout, promise и т. д.)
- Рендеринг на стороне сервера
- Ошибки, возникающие в самой границе ошибки (а не в ее дочерних элементах)
Поэтому вам нужно использовать модуль React Native ErrorUtils для перехвата и обработки этих исключений.
Модуль React Native ErrorUtils
React Native ErrorUtils — это модуль, отвечающий за управление исключениями на страницах RN, аналогичный функции window.onerror на веб-страницах.
Во-первых, давайте посмотрим, как использовать React Native ErrorUtils для асинхронного захвата и обработки непосредственно в коде:
error_guard.js
const noop = () => {};
export const setJSExceptionHandler = (customHandler = noop, allowedInDevMode = false) => {
if (typeof allowedInDevMode !== "boolean" || typeof customHandler !== "function") {
return;
}
const allowed = allowedInDevMode ? true : !__DEV__;
if (allowed) {
// !!! 关键代码
// 设置错误处理函数
global.ErrorUtils.setGlobalHandler(customHandler);
// 改写 console.error,保证报错能被 ErrorUtils 捕获并调用错误处理函数处理
console.error = (message, error) => global.ErrorUtils.reportError(error);
}
};
export const getJSExceptionHandler = () => global.ErrorUtils.getGlobalHandler();
export default {
setJSExceptionHandler,
getJSExceptionHandler,
};
Приведенный выше код ключа состоит всего из двух строк, отмеченных в комментариях.
использовать
import { setJSExceptionHandler } from './error_guard';
import { Alert } from 'react-native';
setJSExceptionHandler((e, isFatal) => {
if (isFatal) {
Alert.alert(
'Unexpected error occurred',
`
${e && e.stack && e.stack.slice(0, 300)}...
`,
[{
text: 'OK',
onPress: () => {
console.log('ok');
}
}]
);
} else {
console.log(e);
}
}, true);
Это очень просто в использовании, давайте посмотримErrorUtils
исходный код модуля
Исходный код ErrorUtils
Исходный код этой статьи — это код основной ветки хранилища React Native, извлеченный 10 сентября 2018 г.
error_guard.js
Сначала посмотрите на определение ErrorUtils, расположение исходного кода:Libraries/polyfills/error_guard.js
let _inGuard = 0;
let _globalHandler = function onError(e) {
throw e;
};
const ErrorUtils = {
setGlobalHandler(fun) {
_globalHandler = fun;
},
getGlobalHandler() {
return _globalHandler;
},
reportError(error) {
_globalHandler && _globalHandler(error);
},
reportFatalError(error) {
_globalHandler && _globalHandler(error, true);
},
...
};
global.ErrorUtils = ErrorUtils;
Выше показан только метод, который мы использовали, мы можем видеть, что мы переписалиconsole.error
,Прямо сейчас(message, error) => global.ErrorUtils.reportError(error)
В конечном итоге казнен_globalHandler
Таким образом, вы можете захватить все используемыеconsole.error
исключение, давайте посмотрим, где в исходном коде React Native ErrorUtils используется для захвата и обработки исключений.
MessageQueue.js
приходитьMessageQueue
Исходный код, расположение:Libraries/BatchedBridge/MessageQueue.js
__guard(fn: () => void) {
if (this.__shouldPauseOnThrow()) {
fn();
} else {
try {
fn();
} catch (error) {
ErrorUtils.reportFatalError(error);
}
}
}
Мы можем видеть выше__guard
используемый методtry...catch...
Охраняйте выполнение функции, при возникновении исключения она будет вызванаErrorUtils.reportFatalError(error);
обрабатывать ошибки
использовал__guard
Места здесь не указаны, можем посмотретьMessageQueue
Где находится этот модуль в РН
Поскольку я не видел систематически исходный код RN, я нашел в Интернете картинку, которая представляет связь между Native и JS.MessageQueue
Связь между Native и JS — важный модуль
BatchedBridge.js
приходитьBatchedBridge
Исходный код, расположение:Libraries/BatchedBridge/BatchedBridge.js
'use strict';
const MessageQueue = require('MessageQueue');
const BatchedBridge = new MessageQueue();
Object.defineProperty(global, '__fbBatchedBridge', {
configurable: true,
value: BatchedBridge,
});
module.exports = BatchedBridge;
Студенты, знакомые с RN, должны знать, чтоBatchedBridge
Это ключевой модуль связи между Native и JS, Из приведенного выше исходного кода мы можем знать, чтоBatchedBridge
фактическиMessageQueue
пример
так вMessageQueue
Использование ErrorUtils в модуле может перехватывать все исключения в процессе связи и вызывать_globalHandler
иметь дело с
Все приведенные выше коды можно посмотреть в разработанном мной проекте библиотеки компонентов РН:rn_components ExceptionHandler, библиотека компонентов только начала создаваться и будет продолжать улучшаться в будущем.
напиши в конце
Вышеизложенное - это моя часть обработки исключений React Native, я надеюсь, что она может быть полезна тем, кто в ней нуждается~~~
Если вам понравилась моя статья, вы можете перейтимой личный блогнажмите звездочку ⭐️