React程式設計規範

書生今天不吃飯發表於2018-08-22

一、工程結構

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標籤中bindthis

因為在每次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,儘管檢視並未需要更新。

相關文章