環境變量和封裝fetch
環境變量
一般做開發,都會將接口地址配置到環境變量里。在Expo
建的項目里,也可以使用環境變量。
在項目根目錄新建一個.env
文件,里面添加上:
EXPO_PUBLIC_API_URL=http://localhost:3000
如果你用手機真機等局域網設備訪問,就改成電腦的IP
地址,例如:
EXPO_PUBLIC_API_URL=http://192.168.x.xx:3000
在Expo
里:
- 環境變量的命名,全部要大寫。
- 而且必須以
EXPO_PUBLIC
開頭,后面再自己添加其他的。
安裝 urlcat
封裝請求文件之前,先去安裝下urlcat包:
npm i urlcat
利用它,可以非常簡單的拼接URL
路徑和查詢參數。要不然就得自己很麻煩的處理URL
路徑里的?
號和&
符號。
例如傳這些參數進去:
urlcat('http://localhost:3000', '/articles', { page: 1, limit: 10 })
它就會自動轉換成:
http://localhost:3000/articles?page=1&limit=10
封裝 request
- 在
headers
里,告訴接口,返回的數據格式是JSON
,發送的數據格式也是JSON
。 config
里,將各種參數都丟進去。根據React Native
官方文檔里的Fetch API 說明,傳給接口的數據,要將JavaScript
對象轉為JSON
字符串。
import urlcat from "urlcat";/*** 基礎請求函數* @param { string } url - API 請求路徑(如 '/articles')* @param { object } [options] - 請求配置項* @param { string } [options.method='GET'] - HTTP 方法* @param { object } [options.params] - URL 查詢參數(如 { page: 1, limit: 10 })* @param { object } [options.body] - 請求體數據* @returns { Promise<object> } 返回解析后的JSON數據** @example* // 基礎調用示例* request('/articles').then(data => console.log(data))** @example* // 帶查詢參數的 GET 請求* request('/articles', {* params: { page: 1, limit: 10 }* })** @example* // POST 請求* // 提交表單數據* request('/auth/sign_in', {* method: 'POST',* body: { login: 'user', password: '123123' }* })*/
const request = async (url, { method = "GET", params, body } = {}) => {// 完整的接口地址const apiUrl = process.env.EXPO_PUBLIC_API_URL;const requestUrl = urlcat(apiUrl, url, params);// 請求頭const headers = {Accept: "application/json","Content-Type": "application/json",// 待完成:傳遞 token};const config = {method,headers,...(body && { body: JSON.stringify(body) }),};const response = await fetch(requestUrl, config);if (!response.ok) {// 待完成:登錄超時處理const { message, errors } = await response.json().catch(() => null);const error = new Error(message);error.status = response.status;error.errors = errors;throw error;}return await response.json();
};/*** GET 請求* @param { string } url - 請求地址* @param { object } [params] - 查詢參數* @returns { Promise<any> } 返回解析后的JSON數據** @example* // 基本 GET 請求* get('/articles').then(data => console.log(data))** @example* // 帶查詢參數的 GET 請求* get('/articles', { page: 1, limit: 10 })*/
export const get = (url, params) => request(url, { method: "GET", params });/*** POST 請求* @param { string } url - 請求地址* @param { object } body - 請求體數據* @returns { Promise<any> } 返回解析后的 JSON 數據** @example* // 提交表單數據* post('/auth/sign_in', { login: 'user', password: '123123' })*/
export const post = (url, body) => request(url, { method: "POST", body });/*** PUT 請求* @param { string } url - 請求地址* @param { object } body - 請求體數據* @returns { Promise<any> } 返回解析后的 JSON 數據** @example* // 更新數據* put('/users/info', { nickname: 'clwy', company: '長樂未央公司' })*/
export const put = (url, body) => request(url, { method: "PUT", body });/*** PATCH 請求* @param { string } url - 請求地址* @param { object } body - 請求體數據* @returns { Promise<any> } 返回解析后的 JSON 數據** @example* // 部分更新數據* 注意:本項目無任何接口使用 PATCH*/
export const patch = (url, body) => request(url, { method: "PATCH", body });/*** DELETE 請求* @param { string } url - 請求地址* @returns { Promise<any> } 返回解析后的 JSON 數據** @example* // 注銷用戶* del('/users/me')*/
export const del = (url) => request(url, { method: "DELETE" });export default request;
// const res = await fetch(`http://192.168.1.138/search?q=${keyword}`);
// const res = await request("/search", { params: { q: keyword } });
const res = await get("/search", { q: keyword });
// 當依賴參數是一個對象或引用類型,例如 params,// 即使它的內容沒有變化,每次組件重新渲染時它的引用都會不同。// 從而導致 useEffect 不斷觸發,會造成無限循環請求。// 可以使用 JSON.stringify(params) 轉換為字符串,來解決這個問題。useEffect(() => {fetchData();}, [url, JSON.stringify(params)]);