react 前端項目技術選型、開發工具、周邊生態
聲明:這不是一篇介紹 React 基礎知識的文章,需要熟悉 React 相關知識
- 主架構:react, react-router, redux, redux-thunk, redux-saga, react-redux, dva, umi
- 擴展架構:styled-components, recompose, react-loadable
- UI 框架:ant-design, ant-design-mobile, material-ui, Semantic-UI-React, blueprint, react-bootstrap
- 服務器端渲染:next.js, razzle, react-server, beidou
- 開發工具:storybook, react-devtools, redux-devtools, redux-devtools-extension
- 測試:enzyme, react-testing-library, jest
- 替代庫:preact, inferno
- 插件庫:react-motion, react-select, reselect, react-beautiful-dnd, react-canvas, redux-form, recharts, react-dnd, react-helmet
1. 架構選型演進
- 如果頁面比較簡單,可以只用
react
- 如果需要本地路由功能,比如在單頁面應用(SPA)中維持多個頁面,並且可以本地控制路由跳轉邏輯,這時就需要搭配使用
react-router
- 一般稍複雜的頁面都會遇到一些問題:組件之間的通信問題(比如 A 組件想要改變 B 組件的
state
)、跨組件數據儲存與共享問題(比如多頁面購物車數據存儲)。react
本身並不能很好的解決這個問題,需要搭配使用redux
-
redux
本身只實現了 flux 理念,以及一些基礎的功能,但在使用中,還需要擴展一些功能,比如異步派發action
,這時可以選擇搭配使用redux-thunk
來解決異步派發action
的問題。另外,也是選擇redux-saga
,但redux-saga
不僅僅是異步派發action
,它擁有強大的異步數據流處理功能,幾乎改變了整個redux
的使用方式,是個重量級的傢伙,如果是龐大且複雜的項目,推薦使用redux-saga
-
redux
本身並不與react
綁定,你依然可以把redux
與 vue、angular 等其他框架一起使用。爲了使redux
與react
開發時更流暢,可以使用react-redux
把兩者鏈接起來,這樣開發體驗更佳 - 當在一個大型項目中使用以上的架構,就會使項目變得異常複雜和不可控(比如目錄結構、
action
定義方式等),這時就需要用dva
來簡化數據流操作,降低項目的複雜度 - 以上涉及的都是代碼層面的架構,如果搭配
umi
一起使用,會有更佳的開發體驗。umi
內部使用 roadhog(webpack 封裝庫), 具有動態路由、dva model
的自動加載、通過插件支持 PWA(Progressive Web App)、以路由爲單元的 code splitting 等
總結:
- 簡單頁面直接用
react
,如果需要本地路由功能再加react-router
- 如果需要跨組件通信、共享數據的話,不太複雜的頁面可以用
redux
+redux-thunk
,複雜的頁面可以用redux
+redux-saga
- 複雜大型應用(比如整個項目就是一個單頁面應用),可以用
react
+react-router
+redux
+redux-saga
+react-redux
+dva
+umi
2. 一些擴展的可選架構
2.1 styled-components
使用 styled-components
,可以把 css
樣式代碼寫到 js
文件中。
一般來說,寫一個 react
組件,需要如下的結構:
- ComponentA.js
- ComponentA.css
- ComponentB.js
- ComponentB.css
- ...
# ComponentA.css
.container {
padding: 10px;
}
# ComponentA.js
import styles from './ComponentA.css';
export default props => (
<div className={styles.container}>
{props.children}
</div>
);
使用 styled-components
後,就可以去掉 css
文件:
- ComponentA.js
- ComponentB.js
- ...
# ComponentA.js
import styled from 'styled-components';
const Container = styled.div`
padding: 10px;
`;
export default props => (
<Container>
{props.children}
</Container>
);
2.2 recompose
寫了大量 react
組件之後(特別是使用 redux
+ react-redux
之後,組件的 state
已經被剝離出去),感覺使用類聲明式(class
)寫 react
組件其實並非最好的方式,而使用函數式組件會更佳:
- 函數式組件邏輯更清晰
- 避免
state
被濫用
類聲明式寫法:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0,
};
}
setCounter(cb) {
const { counter } = this.state;
setState({
counter: cb(counter),
});
}
render() {
const { counter } = this.state;
const setCounter = this.setCounter;
return (
<div>
Count: {counter}
<button onClick={() => setCounter(n => n + 1)}>Increment</button>
<button onClick={() => setCounter(n => n - 1)}>Decrement</button>
</div>
);
}
}
函數式寫法:
import { withState } from 'recompose'
const enhance = withState('counter', 'setCounter', 0)
const Counter = enhance(({ counter, setCounter }) =>
<div>
Count: {counter}
<button onClick={() => setCounter(n => n + 1)}>Increment</button>
<button onClick={() => setCounter(n => n - 1)}>Decrement</button>
</div>
)
相比較而言,函數式寫法要清晰很多呢。
2.3 react-loadable
有些時候,我們想要動態的加載一些組件(按需加載),比如在一個單頁面應用中:
- pages
- PageA.js # a 頁面的組件
- PageB.js # b 頁面的組件
- PageC.js # c 頁面的組件
- ...
只有真正要實例化當前頁面的時候,纔會去加載相應的組件。使用 react-loadable
封裝原來的組件,然後使用封裝後的組件,就像使用原來的組件一樣,react-loadable
會自動幫我們處理腳本加載。
import Loadable from 'react-loadable';
import Loading from './loading-component'; # 頁面組件還沒有加載成功時,顯示一個 loading 組件
const LoadableComponent = Loadable({
loader: () => import('./real-component-a'), # 動態加載真正的 A 組件
loading: Loading,
});
export default class ComponentA extends React.Component { # 封裝後的組件,使用方式與原來一致
render() {
return <LoadableComponent/>;
}
}
3. 選擇 UI 框架
使用一個現成的 UI 框架,可以少寫很多代碼。
目前比較推薦的是:
- ant-design + ant-design-mobile: 螞蟻金服出品
- material-ui: google 材質設計的實現
-
Semantic-UI-React: Semantic-UI for
react
- blueprint: 一套比較好用針對移動端的 UI 框架
4. 服務器端渲染
服務器端渲染用得最多的是 next.js,其他可供選擇的有 razzle、react-server、beidou。
一般這些框架都會有一些目錄結構、書寫方式、組件集成、項目構建的要求,自定義屬性可能不是很強。
以 next.js 爲例,整個應用中是沒有 html
文件的,所有的響應 html
都是 node 動態渲染的,包括裏面的元信息、css, js
路徑等。渲染過程中,next.js
會根據路由,將首頁所有的組件渲染成 html
,餘下的頁面保留原生組件的格式,在客戶端渲染。
更多參考:細說後端模板渲染、客戶端渲染、node 中間層、服務器端渲染(ssr)
5. 開發工具
開發時主要會用到的工具。
5.1 storybook
storybook
爲組件開發搭建了一個強大的開發環境,並提供了以下的幾個功能:
- 提供了一個強大的 UI 組件管理頁面,可以很便捷、清晰的分組、管理多個組件或一個組件的多個不同狀態
- 在自動化交互測試之外,可以很方便的進行手動交互測試,並且可以動態改變組件參數,查看視圖變化
- 可以將組件預覽導出爲靜態資源,這樣就可以很方便查看組件的文檔和不同參數對應的不同視圖
- 還有一系列的插件,提供了很多額外的功能,幫助你更好的開發、測試、優化組件
社區已經有很多組件庫都在使用 storybook 開發,比如:
-
react-dates 的
storybook
react-dates - storybook -
react-native-web 的
storybook
react-native-web - storybook
更多參考:react、vue 組件開發利器:storybook
5.2 react-devtools
這是專門針對 react
組件開發的 chrome 開發者工具插件,就像開發者工具的 Elements
一樣,可以查看整個頁面的 react
組件樹和每個組件的屬性和狀態,並且可以動態的更改屬性和狀態,然後會更新 UI 到應用上。
安裝
通過 chrome 應用商店安裝 chrome - react-developer-tools.
其他安裝方式查看 react-devtools.
5.3 redux-devtools 與 redux-devtools-extension
這是專門針對 redux
開發的 chrome 開發者工具插件,就像 react-devtools 一樣,可以查看整個頁面的 redux
store 及其變化,並且可以動態的派發 action
,然後會更新 UI 到應用上。
5.3.1 安裝 redux-devtools
這種安裝方式,redux-devtools
會嵌入到頁面中,成爲頁面的一部分。
npm install --save-dev redux-devtools
# 還可以安裝
npm install --save-dev redux-devtools-log-monitor
npm install --save-dev redux-devtools-dock-monitor
更多信息參考 redux-devtools - Walkthrough.
5.3.2 安裝 redux-devtools-extension
這種安裝方式是成爲瀏覽器開發者工具的一個插件。
通過 chrome 應用商店安裝 chrome - redux-devtools.
其他安裝方式查看 redux-devtools-extension.
6. 測試
一般 react
組件的測試,會用 enzyme + jest,jest
用來測試 JavaScript,enzyme 用來測試 react
組件。
另外,可以使用 react-testing-library 代替 react-dom/test-utils
,達到更佳的測試體驗。
7. 替代庫
如果你對組件的性能、虛擬 DOM 的算法有極致的追求,可以嘗試 react
的替代庫,如:
8. 插件庫
一些很實用的插件庫:
- react-motion: 動畫組件
- react-select: 下拉選擇組件
-
reselect:
redux
的路徑選擇器 - react-beautiful-dnd: 拖拽組件
- react-canvas: canvas 組件
-
redux-form:
redux
與表單綁定 -
recharts: D3 的
react
封裝 - react-dnd: 又一個拖拽組件
- react-helmet: document head 區域管理器
後續
更多博客,查看 https://github.com/senntyou/blogs
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)