1. 程式人生 > >深入淺出React+Redux(一:React 元件的資料)

深入淺出React+Redux(一:React 元件的資料)

前言

“差勁的程式設計師操心程式碼,優秀的程式設計師操心資料結構和它們之間的關係 。 ”
一一Linus Torvalds, Linux 創始人

首先附上package.json的依賴包,版本問題導致包匯入問題,需要自行調整

{
  "name": "read-react-redux",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react
": "^16.2.0", "react-dom": "^16.2.0", "react-scripts": "1.1.0" }
, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "devDependencies": { "react-router": "3.0.5" }
}

本文是筆者閱讀深入淺出React+Redux過程中,紀錄整理自己知識點文章。(PS:一本書差不多重點在於20%,其他80%是作者為了出版湊得字數。)

毫無疑問,如何組織資料是程式的最重要問題。

React 元件的資料分為兩種, prop 和 state ,無論 prop 或者 state 的改變,都可能引發元件的重新渲染,那麼,設計一個元件的時候,什麼時候選擇用 prop 什麼時候選擇state 呢?

其實原則很簡單, prop 是元件的對外介面, state 是元件的內部狀態,對外用prop ,內部用 state。

(一)React 的 prop

prop ( property 的簡寫)是從外部傳遞給元件的資料, 一個 React 元件通過定義自己能夠接受的 prop 就定義了自己的對外公共介面 。

(1) 給 prop 賦值

<SampleButton
id="sample" borderWidth={2} onClick={onButtonClick}
style={{color: "red"}}
/>

上面例子中,建立了名為 SampleButton 的元件例項,使用了名字分別為 id 、 borderWidth 、 onClick 和 style 的 prop ,看起來, React 元件的 prop 很像是 HTML 元素的屬性,
不過, HTML 元件屬性的值都是字串型別,即使是內嵌 JavaScript ,也依然是字串形式表示程式碼 。

React 元件的 prop 所能支援的型別則豐富得多,除了字串,可以是任何一種 JavaScript 語言支援的資料型別

當 prop 的型別不是字串型別時,在 JSX 中必須用花括號{}把 prop 值包住,所以 style 的值有兩層花括號,外層花括號代表是 JSX 的語法,內層的花括號代表這是一個物件常量

重點PS

因為prop可以是函式,內部元件可以通過它反饋資料給外部元件。

(2)讀取 prop 值

  • (1)首先增加外部容器ControlPanel.jsx
import React, { Component } from 'react';
import Counter from './Counter';

class ControlPanel extends Component {
    render() {
        return (
            <div>
                <Counter caption="First" initValue={0}/>
                <Counter caption="Second" initValue={10}/>
                <Counter caption="Third" initValue={20}/>
            </div>
        )
    }
}

export default ControlPanel;
  • (2)然後增加內部子元件Counter.jsx

    2.1)構造呼叫props

import React, { Component } from 'react';

/*** 暫時去掉stateless元件寫法
const Counter= ({ caption, initValue= 0 })=> {
    return (
        <div>
            {caption}, {initValue}
        </div>
    );
};

export default Counter;*/

export default class Counter extends Component {
    constructor(props){
        super(props);
    }
}

上面程式碼在建構函式的第一行通過 super(props)
呼叫父類也就是 React.Component 的建構函式。如果在建構函式中沒有呼叫 super(props),那麼元件例項被構造之後,類例項的所有成員函式就無法通過 this.props 訪問到父元件傳遞過來的 props 值。

2.2)繫結方法this

constructor(props){
        super(props);
  +     this.clickIncrementHandler= this.clickIncrementHandler.bind(this);
  +     this.clickDecrementHandler= this.clickDecrementHandler.bind(this);
}

+   clickIncrementHandler(){}
+   clickDecrementHandler(){}

上面程式碼。ES6方法創造的 React 元件類並不自動給我們繫結 this 到當前例項物件。這是區別createClass(ps:這是過時方法)自動繫結的。

當然,如果你不想用bind的方式繫結。也提供一種高逼格的寫法(箭頭函式)

constructor(props){
        super(props);
}

clickIncrementHandler=() =>{}
clickDecrementHandler=() =>{}

(3)propTypes 檢查

propTypes宣告元件的介面規範,簡單理解

這個元件支援哪些 prop
每個 prop 應該是什麼樣的格式
// 這是原來v15版本,PropType的匯入方式和約束方式
import React, { Component, PropTypes } from 'react';
Counter.PropTypes= {
    caption: PropTypes.string.isRequired,
    initValue: PropTypes.number.isRequired,
}

// v16的版本移除後變為
import PropTypes from 'prop-types';
Counter.propTypes= { // 注意大小寫
    caption: PropTypes.string.isRequired,
    initValue: PropTypes.number.isRequired,
}

PropTypes

上面程式碼。caption 帶上了 isRequried ,這表示使用 Counter元件必須要指定 caption ;

但是。沒有 propTypes 定義,元件依然能夠正常工作,而且,即使在上面 propTypes 檢查出錯的情況下,元件依舊能工作 。 也就是說 propTypes 檢查只是一個輔助開發的功能,並不會改變元件的行為 。

所以定義類的 propTypes 屬性,無疑是要佔用一些程式碼空間,而且 propTypes 檢查也是要消耗 CPU 計算資源的 。這在開發環境可以。但是產品上線環境就是不理想。

(二)React 的 state

state 代表元件的內部狀態 。 由於 React元件不能修改傳入的 prop ,所以需要記錄自身資料變化,就要使用 state 。

(1)初始化 state

this.state= {
   count: props.initValue || 0,
}

上面程式碼,我們在建構函式中初始化count的值。但是建構函式中放入判斷邏輯,本身就不是一件太美觀的事。這裡你可以使用React 的 defaultProps 功能

+   Counter.defaultProps = {
+      initValue: 0
+   };

這樣,即使 Counter 的使用者沒有指定 initValue ,在元件中就會收到一個預設的屬
性值 0。(stateless可以使用物件的解構)

(2)讀取和更新 state

clickIncrementHandler=() =>{
+        this.setState({count : this.state.count + 1}, ()=>{
+           console.log('finish');
+       });

};

通過setState修改state的值。第二個引數是成功回撥(試圖渲染成功回撥)

PS:直接修改 this.state 的值,雖然事實上改變了元件的內部狀態,但只是野蠻地修改了
state ,卻沒有驅動元件進行重新渲染

(三)prop 和 state 的區別

總結一下 prop 和 state 的區別:

1) prop 用於定義外部介面, state 用於記錄內部狀態;
2) prop 的賦值在外部世界使用元件時, state 的賦值在元件內部;
3) 元件不應該改變 prop 的值,而 state 存在的目的就是讓元件來改變的 。