在寫 React 的時候,會發現一個元件通常是通過刷新資料狀態來改變它的UI,而 React 元件有兩種資料載體,分別是 state 跟 props
State
可以被稱作是元件中的內部狀態 (local state)Props
則是運用在元件間互相傳遞資料(通常是父元件到子元件)
這裏會實作一個計數器,利用 state 與 setState 實作,一開使先在 constructor 分別宣告:
bind
這時候會噴錯,原因是因為裡面的this
會呈現undefined
的狀態,無法抓到 ClickCounter
(詳細原因可以往前翻有一天是專門講 this 的)在 onClickButton 的內容裡,運用了 setState 去不斷更新 count 這個的 state 值,當 button.onClick (按鈕被點擊)這件事發生的時候。
檔案位置:src/ClickCounter.js,以下為程式碼:
import React from 'react';
export default class ClickCounter extends React.Component {
constructor() {
super();
this.state = { count: 0 };
this.onClickButton = this.onClickButton.bind(this);
}
onClickButton() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<button onClick={this.onClickButton}>Click Me</button>
<div>
Click Count: {this.state.count}
</div>
</div>
)
}
}
這邊 src/index.js 的工作就是負責渲染所有有引用到的元件到頁面上,而 document.getElementById('root')
裡面所指的root
是public資料夾中index.html檔案裡的<div id="root"></div>
檔案位置:src/index.js,以下為程式碼:
import React from 'react';
import ReactDOM from 'react-dom';
import ClickCounter from './ClickCounter';
ReactDOM.render(
<ClickCounter />,
document.getElementById('root')
);
從父元件看 prop 使用:
<SampleButton id="sample" onClick={onButtonClick} style={{color: 'green'}}/>
這裏的例子是使用了 SampleButton 的元件,React 的 prop 可以支持類型除了字串還可以是 Javascript 支持的數據類型,當 prop 不是字串時在 JSX 中要用 {}
,所以像是 style 有兩層{},外層代表 JSX 的語法,裡面那層則代表是常量。
這裏是實作如何從父元件(CounterPanel)傳值到子元件(Counter),每個 Counter 元件都用了 name 和 initValue 兩個 prop,而這兩個 prop 分別給 Counter 名稱跟初始值
檔案位置:src/CounterPanel.js,以下為程式碼:
import React from 'react';
import Counter from './Counter';
export defualt class CounterPanel extends React.Component {
render() {
return (
<div>
<Counter name="First" initValue={0} />
<Counter name="Second" initValue={20} />
</div>
)
}
}
這裏是從子元件的角度去看,如果子元件要定義自己的構造函數,一定要調用 super(props)
也就是繼承了React.Component的構造函數,以 ES6 來說會先創建父元件的 this,然後再用子元件的構造函數修改 this 成為自己的;在繼承父元件後,宣告一個名為 count 的 state 初始值為 父元件傳遞過來的 initValue
或是(如果不存在)為0
,以及兩個方法 onClickIncrementButton 與 onClickDecrementButton
檔案位置:src/Counter.js,以下為程式碼:
import React from 'react';
export default class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: props.initValue || 0,
}
this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
}
onClickIncrementButton() {
this.setState({ count: this.state.count + 1 })
}
onClickDecrementButton() {
this.setState({ count: this.state.count - 1 })
}
render() {
const {name} = this.props;
return (
<div>
<button onClick={this.onClickIncrementButton}>+</button>
<button onClick={this.onClickDecrementButton}>-</button>
<span>{name} count: {this.state.count}</span>
</div>
)
}
}
在 props 的範例中需更改,檔案位置:src/index.js,以下為程式碼:
import React from 'react';
import ReactDOM from 'react-dom';
import CounterPanel from './CounterPanel';
ReactDOM.render(
<CounterPanel />,
document.getElementById('root')
);
在 ES6 定義元件中,可以透過增加元件的propTypes
來定義 prop的格式,在運行檢查時,就可以根據propTypes判斷父元件是否正確使用了此元件的屬性。
增加 Counter 元件對 propTypes 的定義:
Counter.propTypes = {
name: PropTypes.string.isRequied,
initValue: PropTypes.number,
}
定義 propsType可以避免運用時犯錯,但在發布的時候可以使用 babel-react-optimize 消除 propTypes