前言:前一篇記錄了【後臺管理系統】目前進展開發中遇到的一些應用點,這一篇會梳理一些本身學習Ant Design Pro源碼的功能點。附:Ant Design Pro 在線預覽地址。 javascript
pages/Dashboard 目錄下:Analysis.js分析頁、Monitor.js指控頁、WorkPlace.js工做臺css
用到的一些技術點:react v16.6 動態 import,React.lazy()、Suspense、Error boundaries (來源:Postbird博客)html
在 Code-Splitting 部分,提出拆分組件的最佳方式(best way) 是使用動態的 import 方式。java
好比下面兩種使用方式的對比:react
以前:webpack
import { add } from './math'; console.log(add(16, 26));
以後: git
import("./math").then(math => { console.log(math.add(16, 26)); });
能夠發現動態 import 提供了 Promise 規範的 API,好比 .then()
,關於 ES 動態 import,能夠查看下面連接: github
一樣,下面這篇文章上也能夠參考:web
目前動態 import 仍舊是 ECMAScript 的提案,並無歸入規範,不過既然 react 可以大力的推動,應該下個標準會被寫入。能夠查看 TC39-https://github.com/tc39/proposal-dynamic-importbabel
動態 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()
動態 import 主要應用場景是延遲加載方法,對於組件來講,並非很適用,可是 React.lazy
對於組件的加載則是有比較大的幫助。
先看一下先後的區別,
以前代碼:
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,也就是引入的內容,而前面引入的是個組件,所以會打印出以下信息:
要使用 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 就沒意義,也沒效果了。
上面 Suspense
是對 loading 的一個打底,而錯誤邊界能夠在任何一個組件中進行錯誤的捕獲。
這裏只對錯誤邊界進行一個簡要的使用,具體的文檔見下:
這裏的錯誤邊界用在這個位置是爲了當組件懶加載失敗的時候,進行錯誤的捕獲和保護:
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; } }
將建立的錯誤邊界掛到組件中,不適用 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);
PureComponent 純組件是React新加的一個類,是優化 React
應用程序最重要的方法之一,易於實施。
只要把繼承類從 Component
換成 PureComponent
便可,能夠減小沒必要要的 render
操做的次數,從而提升性能,並且能夠少寫 shouldComponentUpdate
函數,節省了點代碼。
具體使用及原理可參看下面的連接:
.main { width: 100%; height: 100%; min-height: 100%; transition: 0.3s; &.wide { max-width: 1200px; margin: 0 auto; } }
利用 Ant Design Pro 提供的圖表套件,能夠靈活組合符合設計規範的圖表來知足複雜的業務需求。
迷你區域圖MiniArea | 迷你進度條MiniProgress |
迷你柱狀圖MiniBar | 柱狀圖Bar |
餅狀圖Pie, yuan | 迷你餅狀圖Pie |