1. XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("get", "/api/test", true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var result = JSON.parse(xhr.responseText);
}
}
xhr.send();
2. fetch
fetch("/api/test")
.then(res => res.json())
.then(data => console.log(data))
3. Axios (Using XMLHttpRequest)
axios.post(url)
axios.get(url, { params: opt }
Build a Mock Service in front-end
Mockjs
1) Install
npm install mockjs --save
if it is typescript, also should install: npm i --save-dev @types/mockjs
Mockjs can only hijack XMLHttpRequest, cannot hijack fetch
index.ts:
import Mock from "mockjs";
Mock.mock("/api/test", "get", () => {
return {
errno: 0,
data: {
name: `Yingxu${Date.now()}`,
},
};
});
import it from xx.tsx:
import "../_mock/index";
axios.get("/api/test").then((res) => console.log(res));
Then it will hijack XMLHttpRequest
Build a Mock Service in server side (node.js)
example:
const Mock = require('mockjs')
const Random = Mock.Random
module.export = [
{
url: '/api/question/:id',
method: 'get',
response() {
return {
errno: 0,
data: {
id: Random.id(),
title: Random.ctitle()
}
}
}
}
]
index.js
const Koa = require('koa')
const Router = require('koa-router')
const mockList = require('./mock/index')
const app = new Koa()
const router = new Router()
// register mock router
mockList.forEach(item => {
const { url, method, response} = item
router[method](url, async ctx => {
const res = response()
ctx.body = res
})
})
app.use(router.routes())
app.listen(3001)
then we can use nodemon index.js to start the service.
to mimic real situation, we can set 1s delay
async function getRes(fn) {
return new Promise(resolve => {
setTimeout(() => {
const res = fn()
resolve(res)
}, 1000)
})
}
// register mock router
mockList.forEach(item => {
const { url, method, response} = item
router[method](url, async ctx => {
const res = await getRes(response)
ctx.body = res
})
})
app.use(router.routes())
app.listen(3001)
跨域 (Cross Domain)
use devServer as proxy to visit mock service
1. install
npm i -D @craco/craco
2. In root directory, create a new file:
craco.config.js
add the following content will redirect all the request related to /api to localhost:3001
module.exports = {
devServer: {
proxy: {
"/api": "http://localhost:3001",
},
},
};
3. In package.json, revise the following:
"scripts": {
- "start": "react-scripts start"
+ "start": "craco start"
- "build": "react-scripts build"
+ "build": "craco build"
- "test": "react-scripts test"
+ "test": "craco test"
}
4. npm start
Deal with response error all together
create an ajax.ts
import axios from "axios";
import { message } from "antd";
const instance = axios.create({
timeout: 10 * 1000,
});
instance.interceptors.response.use((res) => {
const resData = (res.data || {}) as ResType;
const { errno, data, msg } = resData;
if (errno !== 0) {
// error tip
if (msg) {
message.error(msg);
}
throw new Error(msg);
}
return data as any;
});
export default instance;
export type ResType = {
errno: number;
data?: ResDataType;
msg?: string;
};
export type ResDataType = {
[key: string]: any;
};
for one service called question, we could create another file called question.ts
import axios from "./ajax";
import type { ResDataType } from "./ajax";
export async function getQuestionService(id: string): Promise<ResDataType> {
const url = `/api/question/${id}`;
const data = (await axios.get(url)) as ResDataType;
return data;
}
and then import { getQuestionService } from this file, and use as following:
useEffect(() => {
async function fn() {
const data = await getQuestionService(id);
console.log("edit page data", data);
}
fn();
}, []);
Define my own hooks to deal with loading status before getting the data
We should name each hook we define as useXXX.
For example, useLoadQuestionData.ts
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { getQuestionService } from "../services/question";
function useLoadQuestionData() {
const { id = "" } = useParams();
const [loading, setLoading] = useState(true);
const [questionData, setQuestionData] = useState({});
useEffect(() => {
async function fn() {
const data = await getQuestionService(id);
setQuestionData(data);
setLoading(false);
console.log("edit page data", data);
}
fn();
}, []);
return { loading, questionData };
}
export default useLoadQuestionData;
then, we can retrieve by using const { loading, questionData } = useLoadQuestionData()
Use useRequest hook from ahooks
function useLoadQuestionData() {
const { id = "" } = useParams();
async function load() {
const data = await getQuestionService(id);
return data;
}
const { loading, data, error } = useRequest(load);
return { loading, data, error };
}
export default useLoadQuestionData;
then, can directly use loading, data, error:
const { loading, data, error } = useLoadQuestionData();
It will trigger automatically, however, you can trigger manually:
const {
loading,
run: handleCreateNew,
error,
} = useRequest(createQuestionService, {
manual: true,
onSuccess(result) {
message.success("创建成功");
nav(`/question/edit/${result.id}`);
},
});
Other components can trigger it by using run() function, here I rename it to be handleCreateNew():
onClick={handleCreateNew}
Request Data and refresh with url parameter change
async function loadAllList() {
const keyword = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";
const data = await getQuestionListService({ keyword });
return data;
}
const { data, loading, error } = useRequest(loadAllList, {
refreshDeps: [searchParams],
});
Comments
Post a Comment