• 【后台管理系统】—— Ant Design Pro入门学习&项目实践笔记(三)


    前言:前一篇记录了【后台管理系统】目前进展开发中遇到的一些应用点,这一篇会梳理一些自己学习Ant Design Pro源码的功能点。附:Ant Design Pro 在线预览地址。 


    Dashboard指示板

    pages/Dashboard 目录下:Analysis.js分析页、Monitor.js指控页、WorkPlace.js工作台

    用到的一些技术点:react v16.6 动态 import,React.lazy()、Suspense、Error boundaries (来源:Postbird博客

     

    Ⅰ、动态 import

    在 Code-Splitting 部分,提出拆分组件的最佳方式(best way) 是使用动态的 import 方式。

    比如下面两种使用方式的对比:

    之前:

    import { add } from './math';
    
    console.log(add(16, 26));
    

    之后:  

    import("./math").then(math => {
      console.log(math.add(16, 26));
    });
    

    可以发现动态 import 提供了 Promise 规范的 API,比如 .then(),关于 ES 动态 import,可以查看下面链接:  

    同样,下面这篇文章上也可以参考:

    目前动态 import 仍旧是 ECMAScript 的提案,并没有纳入规范,不过既然 react 能够大力的推进,应该下个标准会被写入。可以查看 TC39-https://github.com/tc39/proposal-dynamic-import

    动态 import 主要用于延迟请求,对于组件我觉得没什么太大的用处,但是对于延迟加载方法或者bundle非常有用,比如下面的代码:

    可以发现,当触发点击事件的时候,才会去引入需要的方法或者是对象,并且由于 Promise API 的特性,可以使用 Promise.all Promise.race 这种 API,进行并行加载,然后在 then() 回调中调用方法,非常方便

    class App extends Component {
      clickHandle = (e) => {
        Promise.all([
          import('./mods/Lazy2')
        ]).then(([a]) => {
          console.log(a);
            a(e);
        });
      }
      render() {
        return (
          <div className="App">
            <header className="App-header">
              <button onClick={this.clickHandle}>click</button>
            </header>
          </div>
        );
      }
    }
    

    webpack 已经支持动态 import,在 create-react-app 和 next.js 中都已经可以使用。如果是自己的 webpack 脚手架,需要在 webpack 中进行配置,具体的可以参考下面的方式https://webpack.js.org/guides/code-splitting/,最终配置完的样式类似于:https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269(这个链接是react文档给出的额,但是我的网络无法访问)

    同样的,如果使用 babel,需要使用babel-plugin-syntax-dynamic-import这个组件来保证Babel不对动态导入进行转换。

     

    Ⅱ、React.lazy() 和 Suspense

    1、React.lazy()

    动态 import 主要应用场景是延迟加载方法,对于组件来说,并不是很适用,但是 React.lazy 对于组件的加载则是有比较大的帮助。  

    • 目前明确指出,React.lazy 和 suspense 并不适用于服务端渲染 

    先看一下前后的区别,

    之前代码: 

    import OtherComponent from './OtherComponent';
    
    function MyComponent() {
      return (
        <div>
          <OtherComponent />
        </div>
      );
    }
    

    之后:  

    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    function MyComponent() {
      return (
        <div>
          <OtherComponent />
        </div>
      );
    }
    

    关键点是 const OtherComponent = React.lazy(() => import('./OtherComponent')); 这个语句,摒弃了之前的 import X from 'x' 的静态引入方式。  

    同样的,这个变动会使得在组件渲染的时候,再去加载包含引入路径的组件。 

    React.lazy(()=>{}) 这个方法的回调中其实就是包含了一个动态 import, 以下面方式举例: 

    const Lazy2 = React.lazy(() =>import('./mods/Lazy2').then((e) => {
      console.log(e);
    }));
    

    箭头句柄后面就是一个动态 import 的使用, 打印出来的 e,也就是引入的内容,而前面引入的是个组件,因此会打印出如下信息:  

    2、Suspense

    要使用 Suspense,需要从 react 中 import:

    import React, { Component, Suspense } from 'react';
    

    既然是延迟加载,就会有一个加载过程,之前在渲染的时候,我们基本都是自顶一个一个 <Loading> 组件,然后通过变量控制进行操作,如果加载完成,则取消掉 <Loading> 组件。  

    如果直接使用 React.lazy,会报错误:需要一个 placeholder ui 

    既然是延迟加载,就一定会有一个loading的过程,而 Suspense 正是完成这个过程。

    如同上面的效果会有一个动态的过程,代码如下:

    render() {
      return (
        <div className="App">
          <header className="App-header">
          <Suspense fallback={<div>Loading...</div>}>
            {this.renderList()}
          </Suspense>
          </header>
        </div>
      );
    }
    

    Suspense 使用的时候,fallback 一定是存在且有内容的, 否则会报错。  

    针对网络请求的 loading,我并没觉的这种 fallback 有什么帮助,因为他是组件加载的 loading,如果组件加载完了,那么再去 fallback 就没意义,也没效果了。

    Ⅲ、Error boundaries

    上面 Suspense 是对 loading 的一个打底,而错误边界可以在任何一个组件中进行错误的捕获。 

    这里只对错误边界进行一个简要的使用,具体的文档见下: 

    这里的错误边界用在这个位置是为了当组件懒加载失败的时候,进行错误的捕获和保护 

    1、创建错误边界组件

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
      // 从error中接收错误并设置 state
      static getDerivedStateFromError(error) {
        // Update state so the next render will show the fallback UI.
        return { hasError: true };
      }
    
      componentDidCatch(error, info) {
        // 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; 
      }
    }
    

    2、在组件中使用错误边界

    将创建的错误边界挂到组件中,不适用 React.lazy,因为已经没有更上一层次的错误组件了,万一错误边界组件也懒加载出错,会导致无法捕获。

    错误边界组件中,通过 componentDidCatch 捕获错误,可以设置信息或发错误日志。

    错误边界的使用示例可以参考下面的示例:

    按照上面的例子,在使用的时候,组件中报错,触发错误边界:

    Lazy2.jsx:  

    render() {
        throw new Error('I crashed!');
        return (
          <div>
            <p>{this.state.title}</p>
          </div>
        );
    }
    

    App.jsx:  

    <Error>
        {this.renderList()}
    </Error>
    

    Error.jsx:  

    import React, {Component} from 'react';
    
    class Error extends Component {
      constructor(props) {
        super(props);
        this.state = { error: null, errorInfo: null };
      }
      
      componentDidCatch(error, errorInfo) {
        // Catch errors in any components below and re-render with error message
        this.setState({
          error: error,
          errorInfo: errorInfo
        })
        // You can also log error messages to an error reporting service here
      }
      
      render() {
        if (this.state.errorInfo) {
          // Error path
          return (
            <div>
              <h2>Something went wrong.</h2>
              <details style={{ whiteSpace: 'pre-wrap' }}>
                {this.state.error && this.state.error.toString()}
                <br />
                {this.state.errorInfo.componentStack}
              </details>
            </div>
          );
        }
        // Normally, just render children
        return this.props.children;
      }  
    }
    
    export default Error;
    

    最终结果:  

    Dashboard模块除了上面的新技术点,在AntD组件和布局上也有一些常用的知识点:GridContent网格内容布局、Charts图表、Tabs标签页

    Ⅰ、GridContent网格内容布局

     

    使用GridContent组件,需要从components/PageHeaderWrapper目录下引用,源码如下↓

    import React, { PureComponent } from 'react';
    import { connect } from 'dva';
    import styles from './GridContent.less';
    
    class GridContent extends PureComponent {
      render() {
        const { contentWidth, children } = this.props;
        let className = `${styles.main}`;
        if (contentWidth === 'Fixed') {
          className = `${styles.main} ${styles.wide}`;
        }
        return <div className={className}>{children}</div>;
      }
    }
    
    export default connect(({ setting }) => ({
      contentWidth: setting.contentWidth,
    }))(GridContent);

    1、组件继承自PureComponent

    PureComponent 纯组件是React新加的一个类,是优化 React 应用程序最重要的方法之一,易于实施。

    只要把继承类从 Component 换成 PureComponent 即可,可以减少不必要的 render 操作的次数,从而提高性能,而且可以少写 shouldComponentUpdate 函数,节省了点代码。  

    具体使用及原理可参看下面的链接:

    2、设置多个PageHeader网格式分布样式

    .main {
       100%;
      height: 100%;
      min-height: 100%;
      transition: 0.3s;
      &.wide {
        max- 1200px;
        margin: 0 auto;
      }
    }
    

    Ⅱ、Charts图表  

     利用 Ant Design Pro 提供的图表套件,可以灵活组合符合设计规范的图表来满足复杂的业务需求。

    迷你区域图MiniArea 迷你进度条MiniProgress
    迷你柱状图MiniBar 柱状图Bar
    饼状图Pie, yuan 迷你饼状图Pie
  • 相关阅读:
    HDU 6430 Problem E. TeaTree(虚树)
    hdu6437 Problem L.Videos(网络流)
    Rikka with Prefix Sum(组合数学)
    借教室
    2018年全国多校算法寒假训练营练习比赛(第五场)H Tree Recovery
    1296 营业额统计
    FZU oj Problem 2082 过路费
    大数乘法(适合k进制)
    重载小于号
    莫比乌斯
  • 原文地址:https://www.cnblogs.com/ljq66/p/10669939.html
Copyright © 2020-2023  润新知