醉临武-临武县第一中学官网

关于React框架16版中的错误演示

React框架16版已经出了,许多变化令人兴奋。其中有一个功能让我感到兴奋,那就是改良过的错误处理方法。之前的版本在渲染网页过程中,如果发生了运行时错误,那整个React框架就会处于一种被破坏的状态。

现在在React 16中,大家就能使用错误边界功能,而不用一发生错误就解除整个程序挂载了。把错误边界看成是一种类似于编程中try-catch语句的机制,只不过是由React组件来实现的。

错误边界是一种React组件。它及其子组件形成一个树型结构,能捕获JavaScript中所有位置的错误,记录下错误,并且还能显示一个后备界面,避免让用户直接看到组件树的崩溃信息。


这里涉及到一种新的生命周期函数叫componentDidCatch(error, info)。无论什么样的类组件,只要定义了这个函数,就成为了一个错误边界。

有了错误边界,即使某个组件的结果有错误,整个React程序挂载也不会被解除。只有出错的那个组件会显示一个后备界面,而整个程序仍然完全正常运行。

现在要演示下如何在React程序中使用错误边界。我们要举一个电子商务网站的例子,这个网站有一个产品清单网页,显示了正在销售的所有产品。

最终形成的网页应该看上去是这样的:


注意最后一个产品卡,那里的模板可以看到有个什么错误。靠React 16的错误边界功能,我们能够将一个后备界面模板插入到那个特定的组件中去,然后整个程序仍然能正常渲染。

错误边界类组件可以用以下方法创建:

import React, { Component } from 'react';
import { Card, CardMedia, CardTitle, CardText } from 'react-toolbox/lib/card';

const style = {
  width: '350px',
  marginLeft: '20px',
  marginTop: '20px',
  display: 'inline-block'
};

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hasError: false
    };
  }
  componentDidCatch(error, info) {
    this.setState({
      hasError: true
    });
  }
  render() {
    if(this.state.hasError) {
      return (
        <Card style={style}>
          <CardMedia
            aspectRatio="wide"
            image="https://cdn.dribbble.com/users/1078347/screenshots/2799566/oops.png"
          />
          <CardTitle
            title="Sorry Something went wrong!!!"
            subtitle="Error catched by error boundary of react 16"
          />
        </Card>
      );
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

然后我们可以将任意一个组件包在错误边界组件内部来捕获错误并显示后备界面。

比如:

<ErrorBoundary>
  <ProductCard />
</ErrorBoundary>

这里的componentDidCatch()函数使用方法和JavaScript中的catch {}代码块差不多,但只能用于组件。只有类组件才可以成为错误边界。

componentDidCatch()函数内部我们把hasError状态设置为true。然后在渲染方法中检查那个状态。如果出错状态是真,就渲染后备界面;如果是false就把想渲染的React组件界面当作子组件界面渲染出来。


这个程序里主要有三部分:

  • ProductList Component 产品表组件( 智能组件Smart Component)

  • Product Component 产品组件 (展示组件Presentational Component)

  • Header Component 标题组件(展示组件Presentational Component)

网页样式我用的是React工具箱 Toolbox

ProductList组件代码如下:

import React, { Component } from 'react';
import ErrorBoundary from './ErrorBoundary';
import Product from './Product';

export default class ProductList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [{
        name: 'iPhone 7',
        price: 'Price: 650$',
        imageUrl: 'https://i.ytimg.com/vi/7Jd7P42qaFM/maxresdefault.jpg'
      }, {
        name: 'Tesla',
        price: 'Price: 950$',
        imageUrl: 'https://www.tesla.com/tesla_theme/assets/img/models/v1.0/slideshow/Red_Bay-1440.jpg?20171005'
      }, {
        name: 'Iron',
        price: 'Price: 50$',
        imageUrl: 'https://images-na.ssl-images-amazon.com/images/I/41BW0yDhVeL._SX355_.jpg'
      }, {
        name: 'The Kite Runner',
        price: 'Price: 30$',
        imageUrl: 'https://images.gr-assets.com/books/1484565687l/77203.jpg'
      }, {
        price: 'Price: 950$',
        imageUrl: 'https://www.tesla.com/tesla_theme/assets/img/models/v1.0/slideshow/Red_Bay-1440.jpg?20171005'
      }]
    };
  }

  renderProducts() {
    return this.state.products && this.state.products.map((product) => {
      return (
        <ErrorBoundary key={product.name}>
          <Product product={product} />
        </ErrorBoundary>
      );
    });
  }

  render() {
    return (
      <div className="productList" style={{ marginTop: '40px' }}>
        { this.renderProducts() }
      </div>
    );
  }
}

可以看到产品组件是包裹在错误边界内部的。

Product组件的代码是:

import React from 'react';
import { Card, CardMedia, CardTitle, CardText } from 'react-toolbox/lib/card';

const style = {
  width: '350px',
  marginLeft: '20px',
  marginTop: '20px',
  display: 'inline-block'
};
const Product = (props) => (
  <Card style={style}>
    <CardMedia
      aspectRatio="wide"
      image={props.product.imageUrl}
    />
    <CardTitle
      title={props.product.name.toUpperCase()}
      subtitle="Subtitle here"
    />
    <CardText>{props.product.price}</CardText>
  </Card>
);

export default Product;

在上面Product.js的代码中,我们调用了props.product.name.toUpperCase()函数。

所以无论什么时候,只要一个产品没有名字,就会产生值为未定义undefined的对象调用toUpperCase函数的情况。这种错误发生在以前,最终就会导致整个react程序解除挂载

但现在有了错误边界,我们可以捕获这些错误,并渲染一个后备界面。比如下面这个界面:

希望我演示的这个例子能帮助理解React 16的错误边界。

React 16还有带有很多非常棒的功能,我想在下一篇文章里再讨论一些其它的。

以上演示程序的整个代码可以在我的github网页上找到,链接是:

vivek12345/React-16---Error-Boundaries _React-16---Error-Boundaries - Repo to demonstrate the usage of Error Boundaries in React 16_github.com