一、工程結構
1.1 工程目錄
目前大致工程目錄如下:
├─ src //原始碼
│ ├─ components //展示元件,巢狀在容器元件中,通過props獲取容器元件中的資料,負責展示和渲染
│ │ ├─ DemoComponent
│ │ │ ├─ index.tsx
│ │ │ └─ style.scss
│ │ └─ TestComponent
│ │ ├─ index.tsx
│ │ └─ style.scss
│ ├─ containers //容器元件,負責業務流程邏輯的處理,如傳送網路請求,處理請求資料
│ │ ├─ DemoContainer
│ │ │ ├─ reducer.ts //響應action,處理並更新state
│ │ │ ├─ saga.ts //發起http請求,分發請求之後的結果
│ │ │ ├─ action.ts //傳遞資料到store
│ │ │ ├─ constant.ts //定義事件常量
│ │ │ ├─ index.tsx
│ │ │ └─ style.scss
│ │ └─ TestContainer
│ │ ├─ reducer.ts
│ │ ├─ saga.ts
│ │ ├─ action.ts
│ │ ├─ constant.ts
│ │ ├─ index.tsx
│ │ └─ style.scss
│ ├─ images //存放圖片資源
│ │ ├─ Common
│ │ ├─ DemoComponent
│ │ ├─ TestComponent
│ │ ├─ DemoContainer
│ │ └─ TestContainer
│ ├─ mock //存放靜態json資料,多用於除錯
│ ├─ styles //全域性樣式
│ ├─ utils //工具庫
│ ├─ app.tsx //入口檔案,配置store,熱載入等
│ ├─ config.tsx //api介面
│ ├─ routes.ts //頁面路由
│ ├─ reducers.ts //合併reducer
│ ├─ sagas.ts //合併saga
│ ├─ index.html //入口html檔案
│ └─ tsconfig.json //TypeScript編譯配置檔案
├─ www
├─ .babelrc
├─ .gitignore
├─ Jenkinsfile
├─ webpack.config.js
├─ webpack.vendor.config.js
└─ package.json
複製程式碼
注:
1、其中components和containers資料夾中的資料夾命名規則以大駝峰式命名法(或叫Pascal命名法)為準,即每個單詞采用大寫字母,單詞之間不以空格、連線號或底線連線。
2、images資料夾中的圖片資源的命名以單詞底線連線規則,如login_bg.jpg
;common資料夾存放公共資原始檔
1.2 檔案示例
1.2.1 components中的檔案
import * as React from 'react';
//props宣告
interface DemoComponentProps {
dataSource: any;
}
//state宣告
interface DemoComponentState {
isLoading: boolean;
}
export default class DemoComponent extends React.Component<DemoComponentProps, DemoComponentState> {
construct(props: DemoComponentProps) {
super(props);
this.state = {
isLoading: false
};
}
render() {
return (
<div>123</div>
);
}
}
複製程式碼
1、元件繼承於Component或PureComponent可自行調整,PureComponent能夠進行資料的淺比較,減少不必要的
render
,提高效能,但使用了PureComponent不能再宣告shouldComponentUpdate
鉤子函式。
2、state和props中的變數以小駝峰式命名規則為準,即小寫字母開頭,其他單詞大寫,單詞之間不以空格、連線號或底線連線。
1.2.2 containers中的檔案
import * as React from 'react';
import { connect } from 'react-redux';
import { getUserInfo } from './action';
//元件自身props宣告,從其他元件傳入的值
interface DemoComponentOwnProps {
dataSource: any;
}
//從store傳入元件的值,即進過reducer處理的值
interface DemoComponentStateProps {
launchData?: any;
}
//傳送事件的方法
interface DemoComponentDispatchProps {
getUserInfo?: Function;
}
//state宣告
interface DemoComponentState {
isLoading: boolean;
}
//connect修飾器
@(connect<DemoComponentStateProps, DemoComponentOwnProps & DemoComponentDispatchProps, DemoComponentState>(
(state: any) => (
{
launchData: state.demoReducer.launchData
}
),
(dispatch: any) => (
{
getUserInfo: () => {
//多個引數使用物件形式進行傳參
dispatch(getUserInfo());
}
}
)
) as any)
export default class DemoComponent extends React.Component<
DemoComponentStateProps & DemoComponentOwnProps & DemoComponentDispatchProps,
DemoComponentState
> {
construct(props: DemoComponentStateProps & DemoComponentOwnProps & DemoComponentDispatchProps) {
super(props);
this.state = {
isLoading: false
};
}
render() {
return (
<div>123</div>
);
}
}
複製程式碼
1、元件繼承於Component或PureComponent可自行調整,PureComponent能夠進行資料的淺比較,減少不必要的
render
,提高效能,但使用了PureComponent不能再宣告shouldComponentUpdate
鉤子函式。
2、state和props中的變數以小駝峰式命名規則為準,即小寫字母開頭,其他單詞大寫,單詞之間不以空格、連線號或底線連線。
3、constant以全大寫為主,單詞之間以底線連線,如:
export const SHOW_MODAL = 'CUSTOM_MODAL/SHOW_MODAL' 複製程式碼
4、其他檔案的變數命名以小駝峰式命名為準。
1.3 React程式碼規範
1.3.1 基本程式碼風格
- 程式碼縮排
//能在一行顯示時,結尾空格分隔
<Foo bar="bar" baz="baz" />
//bad,不能在一行顯示時
<Foo bar="bar" baz="baz" ... />
//good
<Foo
bar="bar"
baz="baz"
...
/>
複製程式碼
- 雙引號使用
//bad
<Foo bar='bar' />
//good
<Foo bar="bar" />
//bad
<Foo style={{ left: "20px" }} />
//good
<Foo style={{ left: '20px' }} />
複製程式碼
- 總是使用回撥函式方式定義ref
//bad,這樣定義就會弱化語法型別,如:單詞寫錯了對應不上不會報錯提示
<Foo ref="myRef" />
//good
<Foo ref={ref => this.myRef = ref} />
複製程式碼
- 將多行JSX標籤寫在
()
中
//bad
render() {
return <MyComponent>
<MyChild />
</MyComponent>;
}
//good
render() {
return (
<MyComponent>
<MyChild />
</MyComponent>
);
}
//good,單行可以不需要()
render() {
return <MyComponent />;
}
複製程式碼
- JSX map返回
render() {
//推薦取props或state上的值通過這種方式取,不建議直接通過`this.props.`或`this.state.`取
const { data } = this.props;
return (
<ul>
{
//若直接返回元素,無中間計算過程,無需return,使用`()`進行返回
data.map((item: any) => (
<li key={item.id}>
{
//若存在計算,則通過`{}`包裹,使用return返回JSX標籤
item.map((piece: any) => {
const body = <span key={piece.id}>123</span>;
//do something
return body;
}
}
</li>
))
}
</ul>
)
}
複製程式碼
- 方法書寫規範
//bad
render() {
return <button onClick={() => this.handleClick()}>123</button>
}
//good,當無引數時
render() {
return <button onClick={this.handleClick}>123</button>
}
//good,但有引數時
render() {
return <button onClick={(e) => this.handleClick(e, other)}>123</button>
}
複製程式碼
1.3.2 影響效能的程式碼風格
- 在JSX標籤中bind
this
因為在每次
render
過程中,再呼叫bind
都會新建一個新的函式,浪費資源
//bad
class A extends React.Component {
handleClick() {
//do something
}
render() {
return <button onClick={this.handleClick.bind(this)}>123</button>
}
}
//good
class A extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
//do something
}
render() {
return <button onClick={this.handleClick}>123</button>
}
}
複製程式碼
- 使用const常量
因為在每次
render
過程中,都會新建一個新的變數,浪費資源
//bad
render() {
return <div style={{color: 'red'}}>123</div>
}
//good
render() {
const textColor = {color: 'red'};
return <div style={textColor}>123</div>
}
複製程式碼
- 對迴圈JSX標籤使用key
不推薦直接使用index,最好為唯一標識
render() {
return (
<ul>
{
data.map((item: any) => (
<li key={item.id}>123</li>
))
}
</ul>
)
}
複製程式碼
- 少用
display:none
來隱藏元素
使用return null而不是CSS的display:none來控制節點的顯示隱藏。保證同一時間頁面的DOM節點儘可能的少
//bad
render() {
const { isShow } = this.props;
return (
<div>
<span style={{ display: isShow ? 'block' : 'none' }}>123</span>
</div>
)
}
//good
render() {
const { isShow } = this.props;
return (
<div>
{
isShow &&
<span>123</span>
}
</div>
)
}
複製程式碼
- 避免兜底值字面量
有時我們會在
render
函式中建立一個兜底的值來避免undefined
報錯。在這些情況下,最好在元件外建立一個兜底的常量而不是建立一個新的字面量。
//bad
render() {
let arr = [];
if (this.props.things) {
arr = this.props.things;
}
return <Foo things={ things } />;
}
//bad
render() {
// 這在功能上和前一個例子一樣
return <Foo things={ this.props.things || [] } />
}
//good
// 在元件外部宣告
const NO_THINGS = [];
render() {
return <Foo things={ this.props.things || NO_THINGS } />
}
複製程式碼
- 不濫用{...this.props}
只傳遞component需要的props即可,傳遞的太多,或者層次傳的太深,都會加重
shuoldComponentUpdate
其裡面的資料比較負擔
- 慎用
setState
與檢視渲染無關的,但需儲存資料的,不要放在
state
中,每次setState
都會引起不必要的render
,儘管檢視並未需要更新。