React中如何优雅的捕捉事件错误

React中如何优雅的捕捉事件错误 前话

人无完人,所以代码总会出错,出错并不可怕,关键是怎么处理。
我就想问问大家react的错误怎么捕捉呢? 这个时候:

小白:怎么处理?

小白+: ErrorBoundary

小白++: ErrorBoundary, try catch

小白#: ErrorBoundary, try catch, window.onerror

小白##: 这个是个严肃的问题,我知道*种处理方式,你有什么好的方案?

正题

小白#回答的基本就是解决思路。我们来一个一个简单说说。

1. EerrorBoundary

EerrorBoundary是16版本出来的,有人问那我的15版本呢,我不听我不听,反正我用16,当然15有unstable_handleError。
关于EerrorBoundary官网介绍比较详细,这个不是重点,重点是他能捕捉哪些异常。

Error boundaries在rendering,lifeCyclemethod或处于他们树层级之下的构造函数中捕获错误
哦,原来如此。 怎么用

class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // You can also log the error to an error reporting service logErrorToMyService(error, info); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <h1>Something went wrong.</h1>; } return this.props.children; } } <ErrorBoundary> <MyWidget /> </ErrorBoundary>

重点:error boundaries并不会捕捉这些错误:

事件处理器

异步代码

服务端的渲染代码

在error boundaries区域内的错误

2. try catch

简单有效的捕捉

handleClick = () => { try { // Do something that could throw } catch (error) { this.setState({ error }); } } 3. window.onerror

超级奥特曼,只是错误信息比较不好分析。

4.其他

http请求
封装后,专门处理

状态管理redux,mobx等
封装拦截 ,我们在项目的应用mobx-state-tree基本都是在model里面拦截的

其他
自己看着办啊,都找我,我很忙的。

问题

啊?这么多事件处理和方法都要加try catch啊。 你笨啊window.onerror啊。
onerror是非常好,但是有个问题,错误细节不好分析,有大神说,正则解析。
我不扶墙扶你。

解决

decorator特性,装饰器。 create-react-app创建的app默认是不知此的装饰器的。
不要和我争,github地址上人家写着呢

那问题又来了,如何支持装饰器。

场景一:自己构建的项目
那还不简单的飞起

场景二: create-react-app脚手架创建的项目


react-app-rewired

const {injectBabelPlugin} = require('react-app-rewired'); /* config-overrides.js */ module.exports = { webpack: function override(config, env) { // babel 7 config = injectBabelPlugin('transform-decorators-legacy',config) // babel 6 config = injectBabelPlugin('transform-decorators',config) return config; } }

关于装饰器这里不做过多的说明,修改类的行为。
这里又有几个点

装饰方法 装饰类 装饰getter, setter都可以,我们选在装饰方法和类

装饰类,如何排除系统内置方法和继承的方法

装饰的时候有参和无参数怎么处理

我们先写一个来检查内置方法的方法, 不够自己补全

const PREFIX = ['component', 'unsafe_'] const BUILTIN_METHODS = [ 'constructor', 'render', 'replaceState', 'setState', 'isMounted', 'replaceState' ] // 检查是不是内置方法 function isBuiltinMethods(name) { if (typeof name !== 'string' || name.trim() === '') { return false } // 以component或者unsafe_开头 if (PREFIX.some(prefix => name.startsWith(prefix)))) { return true } // 其他内置方法 if (BUILTIN_METHODS.includes(name)) { return true } return false }

再弄一个装饰方法的方法, 这个方法参考了autobind.js
handleError是自己的错误处理函数,这里没有写出来

// 监听方法 function createDefaultSetter(key) { return function set(newValue) { Object.defineProperty(this, key, { configurable: true, writable: true, // IS enumerable when reassigned by the outside word enumerable: true, value: newValue }); return newValue; }; } function observerHandler(fn, callback) { return (...args) => { try { fn(...args) } catch (err) { callback(err) } } } //方法的装饰器, params是额外的参数 function catchMethod(target, key, descriptor, ...params) { if (typeof descriptor.value !== 'function') { return descriptor } const { configurable, enumerable, value: fn } = descriptor return { configurable, enumerable, get() { // Class.prototype.key lookup // Someone accesses the property directly on the prototype on which it is // actually defined on, i.e. Class.prototype.hasOwnProperty(key) if (this === target) { return fn; } // Class.prototype.key lookup // Someone accesses the property directly on a prototype but it was found // up the chain, not defined directly on it // i.e. Class.prototype.hasOwnProperty(key) == false && key in Class.prototype if (this.constructor !== constructor && getPrototypeOf(this).constructor === constructor) { return fn; } const boundFn = observerHandler(fn.bind(this), err => { handleError(err, target, key, ...params) }) defineProperty(this, key, { configurable: true, writable: true, // NOT enumerable when it's a bound method enumerable: false, value: boundFn }); boundFn.bound = true return boundFn; }, set: createDefaultSetter(key) }; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpswdz.html