歡迎來到「24 小時,React 快速入門」系列教學 🎓 Level 11 ~!
:Wish you have a happy learning!
- 完成主線任務:使用 AJAX 向後端取得待辦資料
- 獲得新技能:
- [React] 使用 component lifecycle methods
- [ES6] 使用 promise 處理延遲(deferred)和非同步(asynchronous)
- [Web API] 使用 fetch API 處理 AJAX
- 習得心法:
- 理解元件的生命週期,及 component lifecycle methods 被調用的順序
- 了解 component lifecycle methods 使用時機
通常我們與後端介接資料會使用 REST API,後端的同事可能會提供如下的 API 文件:
URL: https://<baseApiUrl>/todos
HTTP Verb: GET
JSON Response Format:
[
{
"id": 1,
"title": "Item 1",
"completed": false
}
]
上方文件中,讓我們得知只要向 URL 發出 GET 請求,即可得到 JSON 格式的待辦陣列。偶爾,後端夥伴並沒那麼快將程式開發完成,這僅僅是一個規格而已,這時你可以做個假的 JSON 檔案,就像我們在這個範例要做的:
- 新增一個 todos.json 檔案
- 在 todos.json 加入一些假的待辦資料
還有另外一種方式可以讓你得到假的 API,譬如:JSONPlaceholder 等其他第三方資源有提供。
如果我們要在 TodoApp 元件開始渲染後,立馬去抓取待辦資料:
class TodoApp extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
todos: [] // 1. 將原本的 todos 狀態清空
};
}
// 2. 實作 componentDidMount 方法:
// 該方法在元件第一次 render 後,會被呼叫;
// 更多細節請見[學習筆記 1]
componentDidMount() {
// 3. 使用 ajax 請求 API:
// 並將取回的待辦資料更新元件 state(見下一步)
}
}
從 cdnjs 中,複製 github/fetch 最新版本的連結,並貼到 index.html 中。
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.js"></script>
:如果你心裡正想為什麼要使用 github/fetch 的話?其實你可以使用很多方法調用 API,如 jQuery.ajax() 等。不過考量到我們只是為了處理簡單的 ajax 請求,將整包 jQuery 拉進來,成本似乎太高了。因此我建議大家使用 github/fetch 這個程式庫,它實作了 Web 最新的 Fetch API,簡單又漂亮!:)
如果要使用 fetch 調用 todos API,用法大致如下:
/** TodoApp.js */
componentDidMount() {
fetch('./todos.json') // 1. 使用 fetch 回傳的是 promise 物件
.then((response) => response.json()) // 2. 解析 response 資料,將它轉成 js 物件
.then((todos) => this.setState({ todos })); // 3. 更新元件 state
}
- github/fetch | Github
- axios | Github:AJAX 的其他解決方案
- jQuery.ajax() | jQuery
React 提供七個 component lifecycle methods:
- componentWillMount
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
- componentWillUnmount
讓你可以在元件生命週期中做一些事情。
:***什麼是生命週期?***你可以想像就是元件的生老病死 👶 👧 👩 👵 👼。
一個元件從被建立到消滅,共會經歷以下三種狀態:
- 👶 Mounting: 當元件實例(instance)被建立,並且根據 props 作第一次的渲染時
- 👩 Updating: 當元件 props 或 state 被更新,並重新渲染時
- 👼 Unmounting: 當元件實例被消滅時
而在每一種狀態切換時,React 會執行上方七種方法,讓你在切換點做點事情。
// 1. 你只需要在 class 中,實作生命週期方法:
class App extends React.Component {
componentWillMount() {...}
componentDidMount() {...}
render() {...}
}
// 2. 如果你用 React.createClass(),使用方式也是一樣的
const App = React.createClass({
componentWillMount() {...},
componentDidMount() {...},
render() {...}
});
上方圖中:
- 調用順序:第一排 Mounting -> 第二排 Updating * N 次(每當元件 props 和 state 更新,就會跑一次第二排)-> 第三排 Unmounting
- 需要注意:
- 第一次 render 和第 N 次 render 前後呼叫的方法是不一樣的
- 有一些方法無法使用 this.setState()
class App extends React.Component {
// Mounting:
componentWillMount() {
// 1. 這是第一次 render 前,更新 state 的最後機會:
this.setState({ ageText: this.props.age + '歲' });
}
// Mounting:
componentDidMount() {
// 1. 如果你要操作實際的 DOM 元素:
$('#app').hide();
// 2. 如果你要請求 AJAX,或是設置 timer:
$.ajax({ ... });
}
// Updating:
componentWillReceiveProps(nextProps) {
// 1. 如果你要根據新的 props 做一些運算:
this.setState({ ageText: nextProps.age + '歲' });
}
// Updating:
shouldComponentUpdate(nextProps, nextState) {
// 1. 如果你想調校元件效能,不想要做沒有意義的 re-render,
// 如下方只有在 id 不相同的情況下再 render 的話:
return nextProps.id !== this.props.id;
}
// Updating:
componentWillUpdate(nextProps, nextState) {
// 1. 這是第 N 次 render 前,最後被調用的方法,
// 通常可以拿來做 log
}
// Updating:
componentDidUpdate(prevProps, prevState) {
// 1. 如果你要操作更新後實際的 DOM 元素:
$('#app').hide();
}
// Unmounting:
componentWillUnmount() {
// 1. 如果該元件消滅,也需要移除不必要的 AJAX 請求的話:
xhr.abort();
// 2. 如果你要移除不必要的傾聽事件:
store.removeChangeListener(...);
}
}
const promise = new Promise((resolve, reject) => {
// resolve 用來傳遞非同步的成功結果,例如:AJAX 最後取得的資料或一秒後定義的值
// reject 用來傳遞非同步的錯誤結果
setTimeout(() => resolve('async'), 1000);
});
promise
.then((res) => console.log(res)) // 透過 promise.then 可以先定義非同步成功後,要執行什麼
.catch((err) => console.log(err)); // 透過 promise.catch 可以先定義非同步錯誤後,要執行什麼
const url = '/login';
const options = {
method: 'POST',
headers: {}
};
fetch(url, options) // 使用 fetch 調用 AJAX 回傳 promise 物件
.then((res) => res.json());
| 主頁 | 上一關 | 下一關. 深入淺出 Flux |
| 🙋 我要提問 |