[react] 元件(component)
未閱讀:Writing Resilient Components @ OverReacted
本文以 Class Component 為主要範例。自 React 16.8 起,Function Component 搭配 Hooks 已成為撰寫 React 元件的標準方式,不再需要繼承 Component class。建議搭配 React Hooks 一起閱讀。
建立元件(Component)
React 中的元件(component)是一個小而可重複使用的程式碼 。在早期版本中,元件需要從 Component 這個類別(class)而來,但自 React 16.8 起,可以透過 Function Component 搭配 Hooks 來建立元件,這也是目前推薦的做法。以下的 component class 就像是一個可以用來建立許多不同元件的工廠。
在 render() 方法中,記得要使用 return 回傳樣版:
import React from 'react';
import ReactDOM from 'react-dom';
class MyComponentClass extends React.Component {
render() {
return <h1>Hello world</h1>;
}
}
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<MyComponentClass />);
轉譯多行的樣版(template)
當在 React Component 中要轉譯多行的樣版時,要使用括號 () 把多行的程式碼包起來:
import React from 'react';
import ReactDOM from 'react-dom';
class QuoteMaker extends React.Component {
render() {
return (
<blockquote>
<p>What is important now is to recover our senses.</p>
<cite>
<a target="_blank" href="https://en.wikipedia.org/wiki/Susan_Sontag">
Susan Sontag
</a>
</cite>
</blockquote>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<QuoteMaker />);
Stateful 或 Stateless
在 React 中,Stateful 指的是帶有 state 屬性的元件;而 stateless 則是指任何不帶有 state 屬性的元件。
在 React 元件中,props 只可以透過自己以外的其他元件來修改它,絕不應該更新它自己的 this.props;而 state 則相反,只應該透過自己更新 this.state,其他的元件都不應該更改自己以外其他的元件。
States
在 React 元件中有兩種方式可以存取動態的資料,分別是 props 和 state。與 props 不同的地方在於,state 不是透過外部傳進來的,而是由一個元件決定它自己內部 state。
定義 States
我們可以在 Class(類別)的建構式(constructor)中,透過 this.state 來定義 state 的內容:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { mood: 'decent' };
}
render() {
return <h1>I'm feeling {this.state.mood}!</h1>;
}
}
<Example />;
使用 States
keywords: this.state
在元件中,只需要透過 this.state.name-of-property 就可以取得 state 的內容。
更新 State
keywords: this.setState
使用 this.setState 可以更新資料狀態(state),這個方法會將新的物件合併(merge)進原本的物件,因此資料狀態中沒有被更新到的部分,則會保留原有的狀態。
每當呼叫 this.setState() 時,this.setState() 會在資料狀態改變時,自動呼叫 .render() ,進而導致畫面重新轉譯。
簡單來說,在
this.setState()之後,會自動呼叫.render(),因此不能在 render 函式中使用this.setState(),因為這將導致無窮迴圈。
需要留意的是,在 <button onClick={this.toggleMood}> 中,它會尚失其原本的 this 所指稱的對象,因此需要在 constructor 中先使用 this.toggleMood = this.toggleMood.bind(this); 把指稱到的 this 綁定好:
import React from 'react';
import ReactDOM from 'react-dom';
class Mood extends React.Component {
constructor(props) {
super(props);
this.state = { mood: 'good' };
// 這段是必要的,如果沒有這樣寫的話, toggleMood 在 onClick 的 callback 執行時,
// this 會變成 Window 物件,而不是原本的 Mood 這個類別。
this.toggleMood = this.toggleMood.bind(this);
}
toggleMood() {
const newMood = this.state.mood == 'good' ? 'bad' : 'good';
this.setState({ mood: newMood });
}
render() {
return (
<div>
<h1>I'm feeling {this.state.mood}!</h1>
<button onClick={this.toggleMood}>Click Me</button>
</div>
);
}
}
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<Mood />);
當你透過
this來定義事件處理器(event handler)時,記得要在建構式中加上this.methodName = this.methodName.bind(this)。若想瞭解背後的理由,可參考 Handling Events @ React。
如果不想使用在 constructor 中去綁定 this
使用 public class fields 語法
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
};
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}