簡單介紹一下Suspense
Suspense主要用來解決網路IO問題,它早在2018年的React 16.6.0版本中就已釋出。它的相關用法有些已經比較成熟,有的相對不太穩定,甚至經歷了重新命名、刪除:
- 在render函式中,我們可以寫入一個非同步請求,請求資料
- react會從我們快取中讀取這個快取
- 如果有快取了,直接進行正常的render
- 如果沒有快取,那麼會丟擲一個異常,這個異常是一個promise
- 當這個promise完成後(請求資料完成),react會繼續回到原來的render中(實際上是重新執行一遍render),把資料render出來
- 完全同步寫法,沒有任何非同步callback之類的東西
如果你還沒有明白這是什麼意思那我簡單的表述成下面這句話:
呼叫render函式->發現有非同步請求->懸停,等待非同步請求結果->再渲染展示資料
看著是非常神奇的,用同步方法寫非同步,而且沒有yield/async/await,簡直能把人看傻眼了。這麼做的好處自然就是,我們的思維邏輯非常的簡單,清楚,沒有callback,沒有其他任何玩意,不能不說,看似優雅了非常多而且牛逼。
Suspense 的主要用法和場景
在前端開發中,經常會有這樣的需求,載入某個介面時,如果介面的資源比較大,前端對資料的處理也需要時間,載入比較慢,這時候我們需要用一個載入動畫或者提示,使得互動更加友好。
一. React18之前的做法:
在React18之前,我們要實現上面這個效果,請求資料或者載入新的元件的時機一般在componentDidMount,在State中需要一個flag變數來記錄請求資料的狀態,後續手動更改這個狀態,非常的不方便。程式碼如下:
class App extends Component {
state = {
isLoading: false,
}
componentDidMount() {
this.setState({
data: null,
isLoading: true,
});
axios.get('/api/getData').then((data) => {
this.setState({
data,
isLoading: false,
});
});
}
render() {
return this.state.loading ? '正在載入中...' : (
<Page data={data} />
);
}
}
二. React18之後:
1.React.lazy
React.lazy() 允許你定義一個動態載入的元件。這有助於縮減 bundle 的體積,並延遲載入在初次渲染時未用到的元件
const SomeComponent = React.lazy(() => import('./SomeComponent'));
渲染 lazy 元件依賴該元件渲染樹上層的 \<React.Suspense\> 元件。這是指定載入指示器(loading indicator)的方式。
2.React.Suspense
React.Suspense 可以指定載入指示器(loading indicator),以防其元件樹中的某些子元件尚未具備渲染條件:
// 該元件是動態載入的
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
// 顯示 <Spinner> 元件直至 OtherComponent 載入完成
<React.Suspense fallback={<Spinner />}>
<div>
<OtherComponent />
</div>
</React.Suspense>
);
}
Suspense嚐鮮:配合前端表格元件處理前後端IO非同步操作
因為沒有後端邏輯,前端表格元件主要用於在前端對 Excel、Grid 表格資料線上編輯和展示,而利用Suspense的技術特點,便可以輕鬆實現前後端IO非同步操作:
const PureSpread = React.lazy(() => import('./components/pureSpread'))
const SpreadDesigner = React.lazy(() => import('./components/designer'))
const {Content,Header} = Layout
const App = () => (
<Layout className="app">
<IndexSider/>
<Layout>
<Content className="index-content">
<HashRouter>
<Switch>
<Suspense fallback={<div>loading...</div>}>
<Route exact path="/" component={PureSpread}/>
<Route exact path="/designer" component={SpreadDesigner}/>
</Suspense>
</Switch>
</HashRouter>
</Content>
<IndexFooter/>
</Layout>
</Layout>
)
看一下效果:
瞭解更多線上demo:https://demo.grapecity.com.cn...