给react加try-catch

最近在一个使用fis构建的react.js项目里遇到个问题,render函数里如果发生了运行时错误,比如说某个对象没有判断就直接去访问其属性,那我所知道的就是,页面不正常了,特别是有嵌套子组件的时候,我可得一个个一层层去排查判断,去加try-catch。。。

好像react的开发体验不应该是这样子的。

通常来说,使用react的时候都配合以webpack构建,再加个webpack-dev-client,不仅有js live reload还能hot module reload,不离开编辑器的情况下就能一直调试下去。而且当出现运行时错误时,会有明确的error stack打印在页面上。为什么使用fis构建的就不行呢?

先就自己遇到的这个问题来说,我通过多次手动try-catch的方式,找到了render失败的原因,那么这个“手动”的方式是不是可以自动?通常就是monkeypatch,在当前类定义之后,借助于js这种动态修改类定义的特性,可以这样子:

var unsafeCreateClass = React.createClass;
React.createClass = function(spec) {
    var unsafeRender = spec['render'];
    spec['render'] = function() {
        try {
            return unsafeRender.apply(this, arguments);
        } catch(e) {
            console.log(e);
        }
    }

    return unsafeCreateClass.apply(this, arguments);
}

社区的一个详细实现:https://github.com/skiano/react-safe-render/blob/feature/safe-methods/index.js 当然,这种传统方式在使用ES6的组件上是无效的,所以针对另一种写法可以这样子:

class MyComponent extends React.Component {
    render() {
        return <div>render something here</div>;
    }
}
function wrapTryCatch(Component) {
    let oldRender = Component.prototype.render;
    Component.render = function() {
        try {
            oldRender.apply(this, arguments);
        } catch(e) {
            console.log(e);
        }
    }

    return Component;
}

exports default wrapTryCatch(MyComponent);

看起来大同小异,不过需要在每个Component的实现之后再wrap一下,包装出一个新的组件出来。而这种wrapper,借助于es7的新语法,decorator,(引入babel-plugin-transform-decorators)又可以这么写:

@wrapTryCatch
class MyComponent extends React.Component {
    render() {
        return <div>render something here</div>;
    }
}

社区实现:https://www.npmjs.com/package/react-try-catch-render

然而,这还是不能让人满意的,毕竟遗留代码那么多,难道我要一个个去添加这种wrapper? 想想看,现在连decorator这种新语法都能通过babel插件来支持了,为什么不能再通过类似方法来把decorator都自动加进去呢?

事实上,react-try-catch-render(也就是上个例子)这个文档是指出其由react-transform-catch-errors得到的启发,顺着这一点,最后是找到了babel-plugin-react-transform这个插件,刚好就能满足这个需求。而且,它本身已经内置在webpack-dev-client中,所以webpack构建的开发方式才会如此方便看到错误。

按照给出的步骤,自行安装完依赖之后,在fis中对应的babel plugins配置部分添加:

"plugins": [
        ["react-transform", {
          "transforms": [{
            "transform": "react-transform-catch-errors",
            "imports": ["react", "redbox-react"]
          }]
        }]
      ]

配置选项中的imports传入了两个参数,这两个参数是react-transform会传给transform插件使用的,其中redbox-react 是一个自定义的错误处理组件,之前在webpack构建方式下的开发经常看到的红色框框原来就是它了!在实际使用中,可以按需替换,比如说实现badjs上报等。最后试了一下,在fis的构建方式下,也成功看到了红色框框,以后开发过程出现运行错误就页面不会安安静静地失败了。

当然,到这里为止都只是在关心render函数的报错,其它阶段的回调,其实都是类似的实现。

最后一种方式给了很大的启发和想象空间,现在借助于babel的帮助,我们可以在语法层面对js进行增强,在构建阶段就完成对功能的补充,这种方法现在看来,work like a charm!

惹不住还是看了下babel transform插件是如何开发实现的,文档在此。babel作为一个源码转换编译器,是一个源码->ast->源码的过程,而transform插件所做的事就是在ast->源码的阶段。在对AST遍历的过程,按插件接口形式提供visitor,可以细致到对每个AST 节点进行修改(添加,删除,替换等)。所谓的visitor其实就是访问节点时候的钩子/回调。给visitor传入的参数path,给我一种一沙一宇宙的感觉,path提供的属性和操作就可以勾画出整个AST。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏较真的前端

Headless Testing入坑指南

1765
来自专栏前端架构

10款Web程序员必备的CSS工具

对于web开发来说,CSS是最有效的美化页面、设置页面布局的技术。但问题是,CSS是一种标记性语言,语法结构非常的松散、不严谨。WEB程序员会经常发现自己的或别...

892
来自专栏企鹅号快讯

8.实战篇_关于前端路由

写在前面的话:有的读者提意见“文字太多,图片太少,不活泼可爱”,我已经尽力了。 1.一张图理解“页面路由” 这就是页面路由,很古老的J2EE开发,一般一个页面路...

1997
来自专栏编程

前端SEO—详细讲解

一、搜索引擎工作原理 当我们在输入框中输入关键词,点击搜索或查询时,然后得到结果。深究其背后的故事,搜索引擎做了很多事情。 在搜索引擎网站,比如百度,在其后台有...

1818
来自专栏phodal

\b这样去设计 URL,可以提高网站的访问量

今天,很多网站的 URL 的设计都是“有问题”的。它们看起来一塌糊涂,仿佛是被人洗掉的脏数据一样,没有经过设计,没有经过思考。他们一点都不适合阅读,也不利于搜索...

1748
来自专栏13blog.site

Spring+SpringMVC+MyBatis+easyUI整合进阶篇(一)设计一套好的RESTful API

写在前面的话 看了一下博客目录,距离上次更新这个系列的博文已经有两个多月,并不是因为不想继续写博客,由于中间这段时间更新了几篇其他系列的文章就暂时停止了,如今已...

2745
来自专栏开源项目

代码生成器:提升程序员的生产力 | 码云周刊第 27 期

代码生成器:提升程序员的生产力 码云项目推荐 1 基于代码生成器的 J2EE 快速开发平台 jeecg ? 项目简介:JEECG(J2EE Code Gener...

3479
来自专栏Coco的专栏

《HTML重构》读书笔记&思维导图

954
来自专栏开源项目

码云推荐 | tabris.js + restify + 码云打造个人 APP

前言: 从9月初开始到现在,我一直在寻找一个适合自己的,可以跨平台的开发APP的js框架。 虽然之前自己也有陆续接触过Weex,React Native,F...

4228
来自专栏Crossin的编程教室

【我问Crossin】Python web 该如何入门?

1 如何在 Python 中判断字符编码类型? 使用 chardet 库可以检测 >>>import chardet >>>l = b'\xc3\x83\xc3...

2759

扫码关注云+社区