Functional Componet
之前用的 Component 都是用 class 的形式來寫 ( Class Component ),而其實有另外一種方式寫 Component,叫做 functional Component。
以下是 Counter 這個 Component 用不同形式來寫:
/* Class Component */
class Counter extends Component {
render() {
console.log('Counter-render');
return <div>{this.props.number}</div>;
}
}
/* Functional Component */
function Counter(props) { // => 一樣有 props 的屬性可以使用
return <div>{props.number}</div>
}
/* Functional Component - 或是更進階一點,使用解構語法 */
function Counter({number}) { // => 其實就是 const {number} = props
return <div>{number}</div>
}
Class Component 跟 Functional Component 的差異
當你只是要寫個很單純的 Component,不需要儲存 state 也沒有其他事件監聽,功能只有 render 畫面時,就很適合用 Functional Component
,因為語法比起 Class Component 會比較簡潔一點。
Component 之間的溝通方式
在 React 裡面,children Component 沒有辦法改變 parent Component 的 state,所以最好的方式是把 parent 改變 state 的 function 傳下去給 children,當成其中一個 props 的屬性,讓 children Component 透過 parent Component 自己的 function 來改變自己的資料。
什麼意思?
假設有位老師代表著 parent Component,老師有一把鑰匙可以開教室的門,我們可以視作只有老師可以執行「開教室門」這個動作。而有一位學生代表著 children Component。當老師想請同學幫忙開教室門的時候,因為同學並沒有辦法執行「開教室門」這個動作,所以老師需要把自己的鑰匙交到學生手上,使同學能夠借助老師的「開教室門」這個動作來開門。
所以 children Component 如果要改變 parent Component 的 state,就要呼叫 parent Component 傳下來的方法,呼叫那個方法讓 parent Component 自己去改變自己的 state。
const Title = (props) => {
return (
// => 接收到 App 傳來的 handleClick,才能藉此改變 App 的 state
<h1 onClick={props.handleClick}>{props.text}</h1>
)
}
class App extends Component {
constructor() {
super();
this.state = {
counter : 1
}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
counter: this.state.counter + 1
})
}
render() {
return (
<div>
// => 把能夠改變 state 的 handleClick 傳給 Title
<Title handleClick={this.handleClick} text={this.state.counter}/>
</div>
)
}
}
步步拆解以上的流程解析:
- Title
- render Title props.text => App's state.counter: 1
- props.handleClick => App.handleClick: func
- Trigger Title => h1 => onClick => props.handleClick => App.handleClick
- App.handleClick => setState => counter : 2
- App state changed => re-render
- render Title props.text => App's state.counter: 2
把上面範例改寫成「 每點一次,counter 就變成一個隨機數 」,示範傳進去的 function 有帶參數的例子,變成很像在寫 callback function:
const Title = (props) => {
return (
<h1 onClick={() => {
props.changeCounter(Math.random()) // => 就像一個 callback function 的寫法
}}>{props.text}</h1>
)
}
class App extends Component {
constructor() {
super();
this.state = {
counter : 1
}
this.changeCounter = this.changeCounter.bind(this); // => 不要忘了 bind
}
changeCounter(num) {
this.setState({
counter: num
})
}
render() {
return (
<div>
// => 一樣把能夠改變 App state 的 function 傳進去
<Title changeCounter={this.changeCounter} text={this.state.counter}/>
</div>
)
}
}
小記
- children 必須透過 parent 傳進來的 function 來改變 props
- 要記住的重要觀念就是,只有 Component 可以改變自己的 state,如果要改變其他 Component 的 state ,只有該 Component 有提供的方法才可行。