我已经使用 Mock Service Worker 或 MSW 为我的 React 应用程序创建了一个可以正常工作的假服务器。我发现用我真正的 Django REST API 替换假后端很麻烦。
这是我的假后端
index.js
//import React from "react";
import { setupWorker, rest, createResponseComposition, context } from "msw";
import { v4 as uuid } from "uuid";
const delayedResponse = createResponseComposition(null, [
context.delay("real"),
]);
const CACHE_KEY = "100-products-msw-plain";
const store = JSON.parse(localStorage.getItem(CACHE_KEY)) || {
products: [],
};
function updateStore(newStore) {
Object.assign(store, newStore);
localStorage.setItem(CACHE_KEY, JSON.stringify(store));
}
const worker = setupWorker(
// - AUTHORIZATION NOT REQUIRED -
// LOGIN
// GET ALL productS
rest.get("/api/products", (req, res, ctx) => {
const minimalProducts = store.products.map(({ id, title }) => ({
id,
title,
}));
return delayedResponse(() => res(ctx.json(minimalProducts)));
}),
// GET SINGLE product
rest.get("/api/products/:pid", (req, res, ctx) => {
const { pid } = req.params;
const product = store.products.find(({ id }) => id === pid);
return delayedResponse(() => res(ctx.json(product)));
}),
);
// Register the Service Worker and enable the mocking
export default worker;
这是我的数据API
使用API.js
import React from "react";
import { useState, useMemo } from "react";
const URLS = {
PRODUCTS: "/api/products/",
PRODUCT: (id) => `/api/products/${id}`,
};
const get = (url) => fetch(url);
function useAPI() {
const [isLoading, setLoading] = useState(false);
const API = useMemo(() => {
// common wrapper for all network requests
const wrap = (promise) => {
setLoading(true);
return (
promise
// This is invoked regardless of result
.finally(() => setLoading(false))
// This is invoked for all server responses,
// but .ok is only true for 20x and 30x responses
.then((res) => {
return res.json();
})
// Finally, this catches both network, auth, and server errors
.catch((e) => {
throw e;
})
);
};
// USER API
// API
const loadProducts = () => wrap(get(URLS.PRODUCTS));
const loadProduct = (id) => wrap(get(URLS.PRODUCT(id)));
return {
loadProducts,
loadProduct,
};
}, []);
return {
isLoading,
API,
};
}
export default useAPI;
DataProvider.js
import PropTypes from 'prop-types';
import { useState, useMemo } from "react";
import React from "react";
import DataContext from "./DataContext";
import Loader from "./Loader";
import useAPI from "./useAPI";
function DataProvider({ children }) {
const { isLoading, API } = useAPI();
const [products, setProducts] = useState([]);
const [currentId, setCurrentId] = useState(null);
const [currentProduct, setCurrentProduct] = useState(null);
const actions = useMemo(() => {
const loadProducts = () => API.loadProducts().then(setProducts);
const loadProduct = (id) => API.loadProduct(id).then(setCurrentProduct);
const seeProduct = (id) => setCurrentId(id);
const seeAllProducts = () => setCurrentId(null);
return {
loadProduct,
loadProducts,
seeAllProducts,
seeProduct,
};
}, [API]);
const value = {
state: {
products,
currentId,
currentProduct,
},
actions,
};
return (
<DataContext.Provider value={value}>
{isLoading && <Loader />}
{children}
</DataContext.Provider>
);
}
export default DataProvider;
Django REST API json 数据:
{
"id": 1,
"images": [
{
"image": "/media/product-images/43c39863-3c9d-4229-a60f-a57c96fd3278.png"
}
],
"title": "Asus Zenbook",
"image": null,
"is_active": true,
},
{
"id": 2,
"images": [
{
"image": "/media/product-images/f680b1ef-7563-4b10-9f68-b068c298a12a.png"
}
],
"title": "hp",
"image": null,
"is_active": true,
},
我正在尝试用真正的 Python REST API 替换我的假 msw 后端。
我尝试添加服务器的 api 数据源如下:(注意 ~ 注意 const URLS)
使用API.js
import React from "react";
import { useState, useMemo } from "react";
const URLS = {
PRODUCTS: `http://127.0.0.1:8000/api/products/`,
PRODUCT: (id) => `http://127.0.0.1:8000//api/products/${id}`,
};
const get = (url) => fetch(url);
function useAPI() {
const [isLoading, setLoading] = useState(false);
const API = useMemo(() => {
// common wrapper for all network requests
const wrap = (promise) => {
setLoading(true);
return (
promise
// This is invoked regardless of result
.finally(() => setLoading(false))
// This is invoked for all server responses,
// but .ok is only true for 20x and 30x responses
.then((res) => {
return res.json();
})
// Finally, this catches both network, auth, and server errors
.catch((e) => {
throw e;
})
);
};
// USER API
// API
const loadProducts = () => wrap(get(URLS.PRODUCTS));
const loadProduct = (id) => wrap(get(URLS.PRODUCT(id)));
return {
loadProducts,
loadProduct,
};
}, []);
return {
isLoading,
API,
};
}
export default useAPI;
然后我在我的主 index.js 中评论了假的 msw,如图所示:(注意第 4 个导入)。
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
//import backend from "./backend";
//backend.start();
createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
运行我的代码显示此错误:
undefined is not a function (near '...}).map(_ref3 => {...')
useAllProducts@http://localhost:3000/static/js/bundle.js:756:9
AllProducts@http://localhost:3000/static/js/bundle.js:1208:73
useAllProducts.js
import React from "react";
import { useEffect } from "react";
import useData from "./useData";
function useAllProducts() {
const loadProducts = useData(({ actions }) => actions.loadProducts);
useEffect(() => void loadProducts(), [loadProducts]);
return useData(({ state }) => state.products).map(({ id }) => id);
}
export default useAllProducts;
AllProducts.js
import React from "react";
import styled from "styled-components";
import { useAllProducts } from "../data";
import Product from "./Product";
//import AddAProduct from "./AddAProduct";
function AllProducts() {
const obj = {};
const products = useAllProducts();
return (
<Main>
<h1>All my products</h1>
{products.map((product) => (
<Product key={product} id={product}/>
))}
</Main>
);
}
export default AllProducts;
虽然我的 Django 后端显示这个:
[30/Mar/2023 14:30:50] "GET /api/products/ HTTP/1.1" 200 4980
[30/Mar/2023 14:30:50] "GET /api/products/ HTTP/1.1" 200 4980
基本上 useAPi.js 可以正常工作。 React 没有正确匹配我的 Django API 返回的对象是不是一个问题?帮助。