父組件與子組件根本就是現代社會家庭的寫照
要提到 React 的 state
及 props
前,應該要先講一個觀念,子組件與父組件的設計:
class Counter extends Component {
render(){
return (
<div>
<button>-1</button>
<h1>1</h1>
<button>+1</button>
</div>
)
}
}
class App extends Component {
state = {
name: 'Frank'
}
render() {
return (
<div className="App">
<header className="App-header">
<Counter/>
</header>
</div>
);
}
}
先嘗試弄個計數器試試看,背景我採用原本 create-react-app。
請注意:Component 的命名開頭要大寫,而 tag 屬性採駝峰式命名。
從程式碼可以看出,App
中有一個 Counter
tag,也就是在 App
裡面加入了一個 Counter
組件,而這樣的關係我們稱 App
為父組件,Counter
為子組件,既然有這樣的關係,是必須要一些父子溝通,state
跟 props
就是扮演溝通很重要的腳色,先從 state
開始吧。
state
state
可以掌握一個組件的狀態,也可以透過 state
的值來控制 UI 會顯示的值。
class Counter extends Component {
state = {
count: 1
}
render(){
return (
<div>
<button>-1</button>
<h1>{this.state.count}</h1>
<button>+1</button>
</div>
)
}
}
這邊就不去用 css 去調整版型了,若要使用 css,可以 import css 檔在 src 目錄中。
state
以物件方式呈現,裡面可以包著很多狀態,對應到 UI 上,不過這也只能是把值綁定到 h1
中,要怎麼去改它的值?在原本 JavaScript 的做法會是寫 onClick
的監聽事件,在 React 也可以用 onClick
的方式帶入 Function
,再透過 setState
的方式變更值:
class Counter extends Component {
state = {
count: 1
}
addCount = () => {
this.setState({
count: this.state.count + 1
})
}
minusCount = () => {
this.setState({
count: this.state.count - 1
})
}
render(){
return (
<div>
<button onClick={this.minusCount}>-1</button>
<h1>{this.state.count}</h1>
<button onClick={this.addCount}>+1</button>
</div>
)
}
}
這邊有幾個重點需要整理:
setState
的用法是把一個也像state
的物件,包起來再做想要做的運算。- 這邊使用的是箭頭函式的 babel plugin,因此
button
裡的this
會指向 Component,而不會指向button
本身。 - 雖然函式名稱不用駝峰式命名還是可以使用,但還是有個習慣比較好,畢竟像是
onClick
就必須使用這樣命名(我也是寫 React 才養成這習慣)。 - 請記得:
setState
是一個非同步函式,另外每當觸發setState
,component 會重新 render。
這樣已經完成一個簡單的計數器,而還可以再將它優化。
render(){
const {count} = this.state
return (
<div>
<button onClick={this.minusCount}>-1</button>
<h1>{count}</h1>
<button onClick={this.addCount}>+1</button>
</div>
)
}
加上解構賦值,當
state
東西一多、結構更繁雜時,不用每次都寫 this.state%&$#。
另外其實除了箭頭函式以外也有別種方式解決 this
的問題:
render(){
const {count} = this.state
return (
<div>
<button onClick={this.minusCount.bind(this)}>-1</button>
<h1>{count}</h1>
<button onClick={this.addCount.bind(this)}>+1</button>
</div>
)
}
透過
bind
綁定的方式直接將this
指定給 Component
props
最一開始提到的父子組件溝通,嘗試了把計數器寫成一個 Counter
組件,既然都拆成兩個組件,是不是可以改寫成讓父組件控制子組件?透過 props
確實可以辦到,props
可以接受外來的組件給予的值,嘗試將子組件的 state
讓 App
去控制:
class Counter extends Component {
render(){
return (
<div>
<button>-1</button>
<h1>{this.props.number}</h1>
<button>+1</button>
</div>
)
}
}
class App extends Component {
state = {
count: 1
}
render() {
return (
<div className="App">
<header className="App-header">
<Counter number={this.state.count}/>
</header>
</div>
);
}
}
將子組件
Counter
的state.count
交給父組件管,就像爸爸管兒子的零用錢一樣。
除了 state
,我們也可以把 button
的 onClick
事件傳進去:
class Counter extends Component {
render(){
return (
<div>
<button onClick={this.props.minus}>-1</button>
<h1>{this.props.number}</h1>
<button onClick={this.props.add}>+1</button>
</div>
)
}
}
class App extends Component {
state = {
count: 1
}
addCount = () => {
this.setState({
count: this.state.count + 1
})
}
minusCount = () => {
this.setState({
count: this.state.count - 1
})
}
render() {
return (
<div className="App">
<header className="App-header">
<Counter number={this.state.count}
add={this.addCount}
minus={this.minusCount}/>
</header>
</div>
);
}
}
從上可以發現 Counter
組件變得很簡潔,我在子組件它只有結構,事情都父組件做,子組件遵從父組件給予的值、Function
來回傳子組件結構。不過除了這寫法,也可以這樣寫:
class Counter extends Component {
render(){
return (
<div>
<button onClick={this.props.minus}>-1</button>
<h1>{this.props.children}</h1>
<button onClick={this.props.add}>+1</button>
</div>
)
}
}
class App extends Component {
state = {
count: 1
}
addCount = () => {
this.setState({
count: this.state.count + 1
})
}
minusCount = () => {
this.setState({
count: this.state.count - 1
})
}
render() {
return (
<div className="App">
<header className="App-header">
<Counter add={this.addCount}
minus={this.minusCount}>{this.state.count}</Counter>
</header>
</div>
);
}
}
由於 tag 與 close tag 之間只有一個值,所以可以直接把
this.state.count
放進來,而在子組件端可以用this.props.children
接收,這是 React 的內建用法。
總結
這篇提到了 state
跟 props
基本運用,可以發現 React 每個細節都有不同方法,我一開始在接觸時也是被搞得蠻亂的,下一篇會提關於 state
與 props
的應用,我覺得能好好的使用 state
跟 props
,對資料的基本掌握應該就沒什麼太大的問題了。