在react項(xiàng)目中webpack使用mock數(shù)據(jù)的操作方法
1. 創(chuàng)建react項(xiàng)目
使用 create-react-app 創(chuàng)建項(xiàng)目
npx create-react-app react-mock
執(zhí)行 eject 命令
npm run eject
刪除 package.json 文件中的 eslintConfig 選項(xiàng)
2. 安裝依賴包
npm i path-to-regexp fast-glob chokidar axios
3. 創(chuàng)建中間件
在 config 文件夾中創(chuàng)建 WebpackMiddlewareMock.js 文件
讓webpack-dev-server加載中間件,把mock配置文件的請求地址和響應(yīng)數(shù)據(jù)映射到dev server的路由上
const { pathToRegexp } = require("path-to-regexp"); const fg = require("fast-glob"); const path = require("path"); const chokidar = require("chokidar"); const VALID_METHODS = [ "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", ]; const DEFAULT_METHOD = "GET"; const MOCK_FILE_PATTERN = "mock/**/*.{js,ts}"; const DEFAULT_OPTIONS = { rootDir: "", exclude: [], }; class WebpackMiddlewareMock { constructor(options = {}) { this.options = { ...DEFAULT_OPTIONS, ...options }; const { rootDir, exclude } = this.options; this.mockConfigs = this.getConfigs(rootDir, exclude); } parseMockKey(key) { const keyItems = key.split(/\s+/); if (keyItems.length === 1) { return { method: DEFAULT_METHOD, path: keyItems[0], }; } else { const [method, path] = keyItems; const upperCaseMethod = method.toLocaleUpperCase(); if (!VALID_METHODS.includes(upperCaseMethod)) { console.error(`method ${method} is not supported`); } if (!path) { console.error(`${key} path is not defined`); } return { method, path, }; } } getConfigs(rootDir, exclude) { const ignore = exclude.map( (ele) => `mock${ele.startsWith("/") ? "" : "/"}${ele}` ); const mockFiles = fg .sync(MOCK_FILE_PATTERN, { cwd: rootDir, ignore, }) .map((file) => path.join(rootDir, file)); const mockConfigs = []; mockFiles.forEach((mockFile) => { // disable require cache delete require.cache[mockFile]; let mockModule; try { mockModule = require(mockFile); } catch (error) { console.error(`Failed to parse mock file ${mockFile}`); console.error(error); return; } const config = mockModule.default || mockModule || {}; for (const key of Object.keys(config)) { const { method, path } = this.parseMockKey(key); const handler = config[key]; if ( !( typeof handler === "function" || typeof handler === "object" || typeof handler === "string" ) ) { console.error( `mock value of ${key} should be function or object or string, but got ${typeof handler}` ); } mockConfigs.push({ method, path, handler, }); } }); return mockConfigs; } matchPath(req, mockConfigs) { for (const mockConfig of mockConfigs) { const keys = []; if (req.method.toLocaleUpperCase() === mockConfig.method) { const re = pathToRegexp(mockConfig.path, keys); const match = re.exec(req.path); if (re.exec(req.path)) { return { keys, match, mockConfig, }; } } } } decodeParam(val) { if (typeof val !== "string" || val.length === 0) { return val; } try { return decodeURIComponent(val); } catch (error) { if (error instanceof URIError) { error.message = `Failed to decode param ' ${val} '`; error.status = 400; error.statusCode = 400; } throw error; } } createWatch() { const watchDir = this.options.rootDir; const watcher = chokidar .watch(watchDir, { ignoreInitial: true, ignored: [/node_modules/], }) .on("all", () => { const { rootDir, exclude } = this.options; this.mockConfigs = this.getConfigs(rootDir, exclude); }); return watcher; } createMiddleware() { const middleware = (req, res, next) => { const matchResult = this.matchPath(req, this.mockConfigs); if (matchResult) { const { match, mockConfig, keys } = matchResult; const { handler } = mockConfig; if (typeof handler === "function") { const params = {}; for (let i = 1; i < match.length; i += 1) { const key = keys[i - 1]; const prop = key.name; const val = this.decodeParam(match[i]); if (val !== undefined) { params[prop] = val; } } req.params = params; handler(req, res, next); return; } else { return res.status(200).json(handler); } } else { next(); } }; this.createWatch(); return { name: "mock", middleware: middleware, }; } static use(options) { const instance = new WebpackMiddlewareMock(options); const middleware = instance.createMiddleware(); return middleware; } } module.exports = WebpackMiddlewareMock;
4. 修改webpackDevServer
修改 config/webpackDevServer.config.js 文件
引入 WebpackMiddlewareMock 中間件
const WebpackMiddlewareMock = require("./WebpackMiddlewareMock");
刪除 onBeforeSetupMiddleware 和 onAfterSetupMiddleware 選項(xiàng),替換 setupMiddlewares 選項(xiàng)
setupMiddlewares: (middlewares, devServer) => { const mockMiddleware = WebpackMiddlewareMock.use({ rootDir: paths.appPath, }); middlewares.unshift(mockMiddleware); return middlewares; },
在項(xiàng)目根目錄創(chuàng)建 mock 文件夾,并創(chuàng)建 user.js 文件
module.exports = { // 返回值是 String 類型 "GET /api/name": "tom", // 返回值 Array 類型 "POST /api/users": [ { name: "foo", id: 0 }, { name: "bar", id: 1 }, ], "GET /api/users/:id": (req, res) => { res.send({ params: req.params, }); }, // 返回值是 Object 類型 "DELETE /api/users/1": { name: "bar", id: 1 }, };
5. 測試mock請求
修改 App.js 文件
import { useState } from "react"; import axios from "axios"; function App() { const [resultGet, setResultGet] = useState(""); const [resultPost, setResultPost] = useState(""); const [resultParams, setResultParams] = useState(""); const [resultDelete, setResultDelete] = useState(""); const handleGet = async () => { const res = await axios.get("/api/name"); setResultGet(res.data); }; const handlePost = async () => { const res = await axios.post("/api/users"); setResultPost(JSON.stringify(res.data)); }; const handleParams = async () => { const res = await axios.get("/api/users/100"); setResultParams(JSON.stringify(res.data)); }; const handleDelete = async () => { const res = await axios.delete("/api/users/1"); setResultDelete(JSON.stringify(res.data)); }; return ( <div className="App"> <button onClick={handleGet}>"GET /api/name"</button> <h2>{resultGet}</h2> <hr /> <button onClick={handlePost}>"POST /api/users"</button> <h2>{resultPost}</h2> <hr /> <button onClick={handleParams}>"GET /api/users/:id"</button> <h2>{resultParams}</h2> <hr /> <button onClick={handleDelete}>"DELETE /api/users/1"</button> <h2>{resultDelete}</h2> <hr /> </div> ); } export default App;
啟動項(xiàng)目測試
到此這篇關(guān)于在react項(xiàng)目中讓webpack使用mock數(shù)據(jù)的文章就介紹到這了,更多相關(guān)react項(xiàng)目webpack使用mock數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React利用props的children實(shí)現(xiàn)插槽功能
React中并沒有vue中的?slot?插槽概念?不過?可以通過props.children?實(shí)現(xiàn)類似功能,本文為大家整理了實(shí)現(xiàn)的具體方,需要的可以參考一下2023-07-07基于React.js實(shí)現(xiàn)簡單的文字跑馬燈效果
剛好手上有一個(gè)要實(shí)現(xiàn)文字跑馬燈的react項(xiàng)目,然后ant-design上面沒有這個(gè)組件,于是只能自己手?jǐn)]一個(gè),文中的實(shí)現(xiàn)方法講解詳細(xì),希望對大家有所幫助2023-01-01react native實(shí)現(xiàn)監(jiān)控手勢上下拉動效果
這篇文章主要為大家詳細(xì)介紹了react native實(shí)現(xiàn)監(jiān)控手勢上下拉動效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05