深入淺出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,
}
上面程式碼。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 存在的目的就是讓元件來改變的 。