iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
0
Modern Web

給初入JS框架新手的React.js入門系列 第 15

【React.js入門 - 15】 使用Http request - Fetch Api

(2024/04/06更新) 因應React在18後更新了許多不同的語法,更新後的教學之後將陸續放在 新的blog 中,歡迎讀者到該處閱讀,我依然會回覆這邊的提問


不對啊,幹嘛不用jQuery的ajax?

簡單來說,因為jQuery運作模式/渲染DOM的方式和React不太一樣,為避免發生衝突,一般不會希望在React中使用jQuery,而是用其他native或專為React設計的方式來取代。所以這邊要介紹的,就是取代jQuery的Ajax的其中一個方法: Fetch Api。

2019/09/27
補充一下精確的說法: 如果只用 jQuery的ajax的話是沒關係的,只是我們不會為了ajax特別去載jQuery那一包。
(參考後設鐵人 Day22:塗鴉之城之後決定補充一下)

Fetch Api是內建於JavaScript web api的一部份。使用時,不需要額外下載或嵌入CDN。Fetch是一個Promise,我們有在第3篇【React.js入門 - 03】 開始之前應該要知道的DOM和ES6提過Promise的語法,而Fetch的用法是這樣的:

fetch( request的url, { /*設定request內容*/})
    .then(res => res.json()) /*把request json化*/
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

url的地方是你request的路徑,接收的是字串型態。因為fetch要先把接到的response json化之後才能拿到response中的data,所以這邊會有兩個.then()。接下來我們來講常見fetch使用方法:

最基本的使用方式 - 設定 method

設定fetch所執行的method,是使用字串。這個範例是使用GET方法:

fetch( request的url, {method: "GET"}) /*設定使用GET*/
    .then(res => res.json()) 
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

加上headers(1/2) - 設定Content-Type

headers必須要是個Headers物件。在下面的範例我們先用來設定Content-Type

fetch( request的url, {
        method: "GET",
        headers: new Headers({
            'Content-Type': 'application/json',
        })
    })
    .then(res => res.json())
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

加上headers(2/2) - 我要傳token!!!!!!!

在認證、會員系統中,後端常常會要求在要求只有該會員才能看到的資料時,由前端在header中傳送在登入時取得的token。在fetch api中要這樣夾帶:

const token = "Bearer "+ 我存好的token ;

fetch( request的url, {
        method: "GET",
        headers: new Headers({
            'Content-Type': 'application/json',
            'Authorization': token, /* 把token放在這 */
        })
    })
    .then(res => res.json())
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

注意要視你儲存token的方式、token的類型,決定是不是要做前處理,像jwt要在token前面加上"Bearer "

另外,token也能透過url以參數方式傳送。方式是url= 原url + '?token=' + 存好的token;,但一般還是會希望透過header傳token。

加上body(1/2) - 使用JSON type傳送資料

用fetch在body傳送 json type的資料時,要把原資料字串化,接收者才會接到json格式的資料

const data= { A:"資料A", B:"資料B" }

fetch( request的url, {
        method: "GET",
        body: JSON.stringify(data),   /*把json資料字串化*/
        headers: new Headers({
            'Content-Type': 'application/json'
        })
    })
    .then(res => res.json())
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

加上body(2/2) - 使用x-www-form-urlencoded type傳送資料

這個比較麻煩,我們必須要對data做這樣的前處理:

const data= { A:"資料A", B:"資料B" };
const formData = Object.keys(data).map(
    function (keyName) {
        return encodeURIComponent(keyName) + '=' + encodeURIComponent(data[keyName])
    }
).join('&');

其他就和前面差不多,改一下headers的content-type就好

const data= { A:"資料A", B:"資料B" };
const formData = Object.keys(data).map(
    function (keyName) {
        return encodeURIComponent(keyName) + '=' + encodeURIComponent(data[keyName])
    }
).join('&');


fetch( request的url, {
        method: "GET",
        body: formData,   /*使用處理後的資料*/
        headers: new Headers({
            "Content-type": "application/x-www-form-urlencoded"
        })
    })
    .then(res => res.json())
    .then(data => {
          /*接到request data後要做的事情*/
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
    })

範例: 取得在jserv大神(黃敬群教授)的Github中,以英文字母排序的第一個repository

這個範例中,只要我們按下按鍵,就能取得jserv大神在github中的repository,並顯示以英文字母排序後,第一個repository的名字。

獲取github上特定使用者repo的url是'https://api.github.com/users/使用者名稱/repos'。它是GET method,response data的格式是這個樣子的:

我們必須觸發fetch後,存取response第0個資料的「name」,才能做到我們要做的事情。
也就是所有的程式碼長這樣:

import React, { Component } from 'react';
class App extends Component {
  constructor(props) {
    super(props);
    this.state={
      repoName: null
    }
    this.handleClick=this.handleClick.bind(this);
  }

  
  handleClick(){
    fetch( 'https://api.github.com/users/jserv/repos',{method:"GET"})
    .then(res => res.json())
    .then(data => {
          /*接到request data後要做的事情*/
          this.setState({repoName: data[0]['name']});
    })
    .catch(e => {
        /*發生錯誤時要做的事情*/
        console.log(e);
    })
  }
  
  render() {
      return (
        <div className="App">
          <div className="data-display">
            {(this.state.repoName===null)?"目前還有沒有資料":this.state.repoName}
          </div>
          <button onClick={this.handleClick}>取得jserv以英文字母排序的第一個repo</button>
    	</div>
    )
  }
};

執行結果:

來看看老師是不是真的有這個repo:

小結

fetch還有許多可以設定的地方,可以翻閱MDN了解細節。

到這邊,你應該知道了fetch的使用方法。搭配button,你也有辦法讓網頁被動讓使用者呼叫fetch。但是有的時候,我們希望載入網頁時就主動用http request去取得資料,這又要怎麼處理呢?

從下一篇,我們會開始講生命週期,到時候就會討論到這個問題。


上一篇
【React.js入門 - 14】 Debug利器 : React-Developer-Tools
下一篇
【React.js入門 - 16】 React生命週期(1/4): Mount(上)- 在渲染以前
系列文
給初入JS框架新手的React.js入門31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言