如何在 React 中使用 REST API —— 初學者指南

React 是一個流行的前端庫,開發者常常使用 React 來創建應用。如果想要將創建的應用投入使用,你需要將 API 集成到應用中。

如果想要使用 React 構建現代、強大的 Web 應用,你必須知道如何在 React 中 使用 API 來獲取數據。

在這份初學者指南中,你將學習如何在 React 中使用 RESTful API,其中包括獲取、刪除以及添加數據。同時,我們將講解兩種使用 RESTful API 的主要方法,以及如何搭配 React 鉤子來使用。

什麼是 REST API?

如果你接觸過編程,就應該碰到過 API 這個術語。

API 代表應用程序接口(Application Programming Interface),是不同應用之間相互通訊以及實時返回響應的媒介。

Roy Fielding 在 2000 年將 REST 定義爲一種互聯網服務(如分佈式超媒體系統)開發的架構—風格和方法,REST 是 REpresentational State Transfer(表現層狀態轉化)的縮寫。

當通過 REST API 發出請求時,它會將資源的當前狀態的表現發送給請求者或者終點。狀態表現通常採用 JSON 格式(JSON 即 JavaScript Object Notation),或者 XML 和 HTML 格式。

JSON 格式之所以最受歡迎,是因爲它和編程語言無關,人類和機器都可以理解。

以下是一個 JSON 示例:

[
   {
      "userId": 1,
      "id": 1,
      "title": "sunt excepturi",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur "
   },
   {
      "userId": 1,
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil"
   }
]

如何在 React 中使用 REST API?

你可以通過各種不同的方法在 React 中使用 REST API,但在這篇教程中我們只講解兩種主要的方法:Axios(基於 promise 的 HTTP 客戶端)和 Fetch API(瀏覽器內置的 Web API)。

注意: 你必須熟悉 JavaScript、React 和 React 鉤子才能完全理解本教程。

在我們正式開始在 React 中使用 REST API 之前,我必須強調在 React 中使用 API 與在 JavaScript 中完全不同,因爲請求是在 React 組件中完成。

這篇教程使用 React 函數組件,所以會使用兩大鉤子:

useEffect(() => {
    // 在這裏獲取數據
}, []);
const [posts, setPosts] = useState([]);

讓我們進入本文的正題,我們藉助 JSONPlaceholder posts API 來學習如何獲取、添加和刪除數據。因爲文章內容是針對初學者的,所以這裏講解的方法的應用面很廣。

如何使用 Fetch API 來獲取 API 數據?

Fetch API 是 JavaScript 內置從服務器或者 API 終點獲取資源的方法。因爲是內置的,所以使用 Fetch API 不需要安裝任何依賴項或者包。

fetch()方法有一個強制參數,即你想要獲取資源的路徑或者 URL,該方法返回一個 promise,可以使用then()catch()方法來處理成功或者失敗的情況。

一個基本的 fetch 請求簡單易寫,在下面示例中,我們從 URL 獲取數據後,返回 JSON 格式的數據然後打印在控制檯。

fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
   .then(response => response.json())
   .then(data => console.log(data));

默認響應是 HTTP 格式的,但是我們可以使用json()方法來把結果改成 JSON 對象。

在 React 中如何使用 Fetch API 來實現 GET 請求?

可以使用 HTTP GET 方法從終點請求數據。

如前文所述,Fetch API 有一個強制參數,但與此同時也接受一個選擇參數,當使用 GET 方法的時候,可以選擇寫或者不寫,但是如果使用 POST 和 DELETE 方法的話,就必須附上方法的名稱及詳情:

fetch(url, {
    method: "GET" //默認參數,可以忽略
})

在學習完原理之後,讓我們學以致用,從 API 中獲取數據。

我們將使用 free online API JSONPlaceholder 上的數據,獲取一組帖子的數據到應用:

import React, { useState, useEffect } from 'react';

const App = () => {
   const [posts, setPosts] = useState([]);
   useEffect(() => {
      fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
         .then((response) => response.json())
         .then((data) => {
            console.log(data);
            setPosts(data);
         })
         .catch((err) => {
            console.log(err.message);
         });
   }, []);

return (
   // ... 在這裏使用數據
);
};

我們在代碼的一開始創建了一個狀態來存儲從 API 獲取的數據,以便之後可以在應用中使用。同時,我們將狀態的默認值設置爲空數組。

const [posts, setPosts] = useState([]);

主要的操作發生在 useEffect 中,一旦應用加載成功,就獲取數據(帖子)。fetch 請求得到一個 promise,我們可以接受或者拒絕:

useEffect(() => {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10').then(
      (response) => console.log(response)
   );
}, []);

response包含了大量的數據,如:狀態碼、文本以及其他我們之後要去處理的錯誤信息。

目前我們使用 .then()來處理 promise 決議,但此刻只返回一個響應對象,並不是我們想要的。所以我們要使用 json() 方法來修改決議格式爲 JSON 格式。此時也會返回一個 promise 需要我們使用第二個.then()來獲取真正的數據。

useEffect(() => {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((response) => response.json())
      .then((data) => {
         console.log(data);
         setPosts(data);
      });
}, []);

查看控制檯,會發現我們已經用 API 獲取了 10 條帖子,並且將狀態設置爲我們之前計劃的樣子。

還沒完,因爲我們只處理了決議沒有處理拒絕,此時需要.catch()方法:

useEffect(() => {
   fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((response) => response.json())
      .then((data) => {
         console.log(data);
         setPosts(data);
      })
      .catch((err) => {
         console.log(err.message);
      });
}, []);

我們已經知道如何使用GET請求,數據可以輕鬆通過數組循環在應用內使用:

const App = () => {
// ...

   return (
   <div class>
      {posts.map((post) => {
         return (
            <div class key={post.id}>
               <h2 class>{post.title}</h2>
               <p class>{post.body}</p>
               <div class>
               <div class>Delete</div>
               </div>
            </div>
         );
      })}
   </div>
   );
};

export default App;

在 React 中如何使用 Fetch API 發送 POST 請求?

可以使用 HTTPPOST方法從終點發送數據。該方法和GET請求類似,主要的區別在於需要添加方法名稱以及兩個額外的參數到選填對象中:

const addPosts = async (title, body) => {
await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
   title: title,
   body: body,
   userId: Math.random().toString(36).slice(2),
}),
headers: {
   'Content-type': 'application/json; charset=UTF-8',
},
})
.then((response) => response.json())
.then((data) => {
   setPosts((posts) => [data, ...posts]);
   setTitle('');
   setBody('');
})
.catch((err) => {
   console.log(err.message);
});
};

代碼中的body(請求體)和header(請求頭)對於你來說可能有點陌生。

body部分的數據是我們想要傳給 API 的數據,在傳輸給服務器之前必須先字符串化。header告知數據類型,通常和我們使用的 REST API 一致的類型。同時我們也使用狀態保存新的數據,並將剩下的數據分配到上文所述的循環數組中。

在我們創建的addPost()方法中期望從表單或者其他地方獲取數據。在我們的例子中,我創建了一個表單<form>,從狀態的變化獲得表單數據,然後在提交表單的時候將數據添加到方法。

import React, { useState, useEffect } from 'react';
const App = () => {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
// ...
const addPosts = async (title, body) => {
   await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      body: JSON.stringify({
         title: title,
         body: body,
         userId: Math.random().toString(36).slice(2),
      }),
      headers: {
         'Content-type': 'application/json; charset=UTF-8',
      },
   })
      .then((response) => response.json())
      .then((data) => {
         setPosts((posts) => [data, ...posts]);
         setTitle('');
         setBody('');
      })
      .catch((err) => {
         console.log(err.message);
      });
};

const handleSubmit = (e) => {
   e.preventDefault();
   addPosts(title, body);
};    

return (
   <div class>
      <div class>
         <form onSubmit={handleSubmit}>
            <input type="text" class value={title}
               onChange={(e) => setTitle(e.target.value)}
            />
            <textarea  
               value={body} onChange={(e) => setBody(e.target.value)} 
            ></textarea>
            <button type="submit">Add Post</button>
         </form>
      </div>
      {/* ... */}
   </div>
);
};

export default App;

在 React 中如何使用 Fetch API 執行 DELETE 請求?

可以使用 HTTPDELETE方法從終點刪除數據。這和GET請求類似,主要的區別在與這個方法附加的一些條件:

const deletePost = async (id) => {
await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
   method: 'DELETE',
}).then((response) => {
   if (response.status === 200) {
      setPosts(
         posts.filter((post) => {
            return post.id !== id;
         })
      );
   } else {
      return;
   }
});
};

一旦點擊按鈕就觸發這個行爲,我們獲得按鈕所在的具體帖子的id,然後從整個返回數據中刪除這個數據。

這樣操作會將數據從 API 刪除,但是不從 UI 刪除,所以我們添加了一個filter方法來在 UI 上刪除響應的數據。每一個在循環中的刪除鍵代碼如下:

const App = () => {
// ...

   return (
   <div class>
      {posts.map((post) => {
         return (
            <div class key={post.id}>
               {/* ... */}
               <div class>
                  <div class onClick={() => deletePost(post.id)}>
                     Delete
                  </div>
               </div>    
            </div>
         );
      })}
   </div>
   );
};

export default App;

如何在 Fetch API 中使用 Async/Await?

目前我們使用 promise 語法來發送 fetch 請求,這個語法有時會造成理解上的困惑,特別是後續緊跟着鏈式調用。我們可以使用 async/await 取代.then()從而編寫更易讀的代碼。

使用 async/await 的第一步是在函數中添加async標識,然後在需要等待響應的部分添加await語法,等待 promise 決議。

使用 async/await 後我們的 fetch 請求會變成這個樣子:

import React, { useState, useEffect } from 'react';

const App = () => {
   const [title, setTitle] = useState('');
   const [body, setBody] = useState('');
   const [posts, setPosts] = useState([]);

   // fetch API 中的 GET 方法
   useEffect(() => {
      const fetchPost = async () => {
         const response = await fetch(
            'https://jsonplaceholder.typicode.com/posts?_limit=10'
         );
         const data = await response.json();
         console.log(data);
         setPosts(data);
      };
      fetchPost();
   }, []);

   //fetch API 中的 DELETE 方法
   const deletePost = async (id) => {
      let response = await fetch(
         `https://jsonplaceholder.typicode.com/posts/${id}`,
         {
            method: 'DELETE',
         }
      );
      if (response.status === 200) {
         setPosts(
            posts.filter((post) => {
               return post.id !== id;
            })
         );
      } else {
         return;
      }
   };

   // fetch API 中的 POST 方法
   const addPosts = async (title, body) => {
      let response = await fetch('https://jsonplaceholder.typicode.com/posts', {
         method: 'POST',
         body: JSON.stringify({
            title: title,
            body: body,
            userId: Math.random().toString(36).slice(2),
         }),
         headers: {
            'Content-type': 'application/json; charset=UTF-8',
         },
      });
      let data = await response.json();
      setPosts((posts) => [data, ...posts]);
      setTitle('');
      setBody('');
   };

   const handleSubmit = (e) => {
      e.preventDefault();
      addPosts(title, body);
   };

   return (
      // ...
   );
};

export default App;

如何使用 Fetch API 處理錯誤

在這個部分我們將討論如何使用傳統和 async/await 的方式來處理錯誤。

我們可以使用響應數據來處理 Fetch API 中的錯誤,或者在 async/await 中使用 try/catch 聲明來處理錯誤。

讓我們先看看如果使用傳統方式:

const fetchPost = () => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
   .then((response) => {
      if (!response.ok) {
         throw Error(response.statusText);
      }
      return response.json();
   })
   .then((data) => {
      console.log(data);
      setPosts(data);
   })
   .catch((err) => {
      console.log(err.message);
   });
};

更多相關內容可以閱讀這篇文章。

在 async/await 中可以這樣使用trycatch

const fetchPost = async () => {
   try {
      const response = await fetch(
         'https://jsonplaceholder.typicode.com/posts?_limit=10'
      );
      const data = await response.json();
      setPosts(data);
   } catch (error) {
      console.log(error);
   }
};

如何使用 Axios 來使用 API?

Axios 是基於 promise 的 HTTP 客戶端庫,使得向 REST 終點發送異步 HTTP 請求變得更容易。本文使用的終點是 JSONPlaceholder Posts API,我們會對它發出GETPOSTDELETE請求。

如何安裝和配置 Axios 實例?

Axios 不像 Fetch API 一樣是內置的,所以需要我們在使用之前將其安裝在項目裏。

你可以使用以下命令來安裝 Axios:

npm install axios

成功安裝 Axios 之後,可以馬上創建實例,這一步是選擇性的,但是爲了避免不必要的重複,我建議你這樣操作。

我們使用.create()方法來創建實例,我們可以通過這個方法確定如 URL 和 header 等具體信息:

import axios from "axios";

const client = axios.create({
   baseURL: "https://jsonplaceholder.typicode.com/posts" 
});

在 React 中如何使用 Axios 執行 GET 請求?

我們將使用創建好的實例來執行 GET 請求。只需要設置好參數,就可以獲取默認 JSON 格式的響應。

和 Fetch API 方法不同的是,在 Axios 中沒有額外的選擇性參數。我們只需將方法添加到實例上,然後發出請求:

useEffect(() => {
   client.get('?_limit=10').then((response) => {
      setPosts(response.data);
   });
}, []);

在 React 中如何使用 Axios 執行 POST 請求?

如上文所述,可以通過POST方法將數據發送到終點,運行方式和GET請求類似,唯一的不同是在POST請求中需要指明請求方式以及添加我們需要發送的數據:

const addPosts = (title, body) => {
   client
      .post('', {
         title: title,
         body: body,
      })
      .then((response) => {
         setPosts((posts) => [response.data, ...posts]);
      });
};

在 React 中如何使用 Axios 執行 DELETE 請求?

我們可以通過delete方法來發送刪除請求,獲取id後,刪除 API 上對應的內容。和在 Fetch API 中的操作一樣,我們同樣需要使用filter方法來更新 UI:

const deletePost = (id) => {
   client.delete(`${id}`);
   setPosts(
      posts.filter((post) => {
         return post.id !== id;
      })
   );
};

如何在 Axios 中使用 Async/Await?

目前爲止我們都是使用 promise 的語法來發送 Axios 請求,現在讓我們看看如何使用 async/await 語法來避免使用.then()鏈式調用。

使用 async/await 後,Axios 請求可以改寫如下:

import React, { useState, useEffect } from 'react';

const App = () => {
   const [title, setTitle] = useState('');
   const [body, setBody] = useState('');
   const [posts, setPosts] = useState([]);

   // Axios 中的 GET
   useEffect(() => {
      const fetchPost = async () => {
         let response = await client.get('?_limit=10');
         setPosts(response.data);
      };
      fetchPost();
   }, []);

   // Axios 中的 DELETE
   const deletePost = async (id) => {
      await client.delete(`${id}`);
      setPosts(
         posts.filter((post) => {
            return post.id !== id;
         })
      );
   };

   // Axios 中的 POST
   const addPosts = async (title, body) => {
      let response = await client.post('', {
         title: title,
         body: body,
      });
      setPosts((posts) => [response.data, ...posts]);
   };

   const handleSubmit = (e) => {
      e.preventDefault();
      addPosts(title, body);
   };

   return (
      // ...
   );
};

export default App;

如何使用 Axios 處理錯誤?

如果是基於 promise 語法的 Axios 請求,我們使用.then().catch () 方法,如果是 async/await,我們使用try...catch代碼塊。這和使用 Fetch API 非常類似,try...catch代碼塊的示例如下:

const fetchPost = async () => {
   try {
      let response = await client.get('?_limit=10');
      setPosts(response.data);
   } catch (error) {
      console.log(error);
   }
};

更多相關內容可以閱讀這篇文章。

Fetch API vs Axios

你可以已經發現了一些不同,這裏我製作了一張表格列舉了兩個方法之間的不同。

兩者之間的區別可以幫助你決定在你的項目中採取哪種方法,兩者之間的區別是:

f82k67

總結

在這篇文章中我們學習瞭如何使用 Fetch API 和 Axios 在 React 中使用 REST API。

本文將開啓你的 React 使用 API 之旅,之後你將自己選擇 API 並進行更爲複雜的數據處理。

原文:https://www.freecodecamp.org/news/how-to-consume-rest-apis-in-react/

作者:Joel Olawanle

譯者:PapayaHUANG

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/CPWOqGKIhDhmjWJhR0_ZsQ