如何在React应用中调用自建Node.js+Express+MongoDB API路由
Hey there! Let's work through getting your React e-commerce app talking to your custom API smoothly. Since you’ve confirmed the API works perfectly in Postman, the issue is almost certainly in how React is structuring requests or a small configuration gap. Here’s a step-by-step breakdown to fix this:
This is the most common culprit when local React apps can’t talk to local APIs. React runs on localhost:3000 by default, while your Express API is likely on a different port (like 5000). Browsers block cross-origin requests unless the API explicitly allows them.
To fix this:
- Install the
corspackage in your Express project:npm install cors - Add it to your Express app setup:
// In your Express server file (e.g., server.js) const cors = require('cors'); const app = express(); // Allow all origins (for development only; lock this down in production!) app.use(cors()); // Or restrict to your React app's origin for better security: // app.use(cors({ origin: 'http://localhost:3000' }));
Stop using relative paths (like /api/products) in React—they’ll point to React’s port (3000) instead of your API’s port. Create a reusable utility file to manage your API endpoints:
// src/utils/api.js // Replace with your actual API port and base path const BASE_API_URL = 'http://localhost:5000/api'; // Helper function for GET requests export const fetchProducts = async () => { const response = await fetch(`${BASE_API_URL}/products`); // Always check if the response is successful first! if (!response.ok) throw new Error(`Failed to fetch: ${response.statusText}`); return response.json(); };
For production, store this URL in a .env file (React automatically picks up variables prefixed with REACT_APP_):
# .env file in your React project root REACT_APP_API_URL=http://your-production-api-url.com/api
Then update your utility file:
const BASE_API_URL = process.env.REACT_APP_API_URL;
Here’s how to map each CRUD action to your API, with error handling:
Read (Fetch Products)
Use useEffect to load data when your component mounts:
// src/components/ProductList.js import { useState, useEffect } from 'react'; import { fetchProducts } from '../utils/api'; function ProductList() { const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const loadProducts = async () => { try { const data = await fetchProducts(); setProducts(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }; loadProducts(); }, []); if (loading) return <div>Loading products...</div>; if (error) return <div className="error">Oops: {error}</div>; return ( <div className="product-grid"> {products.map(product => ( <div key={product._id} className="product-card"> <h3>{product.name}</h3> <p>${product.price}</p> </div> ))} </div> ); } export default ProductList;
Create (Add a Product)
Handle form submissions with a POST request:
// Add to src/utils/api.js export const createProduct = async (productData) => { const response = await fetch(`${BASE_API_URL}/products`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(productData), }); if (!response.ok) throw new Error('Failed to create product'); return response.json(); }; // In your AddProduct component const handleSubmit = async (e) => { e.preventDefault(); try { const newProduct = await createProduct({ name, price, description }); // Update local state to show the new product immediately setProducts(prev => [...prev, newProduct]); // Reset form setName(''); setPrice(''); setDescription(''); } catch (err) { setError(err.message); } };
Update (Edit a Product)
Use a PUT request with the product ID:
// Add to src/utils/api.js export const updateProduct = async (productId, updatedData) => { const response = await fetch(`${BASE_API_URL}/products/${productId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(updatedData), }); if (!response.ok) throw new Error('Failed to update product'); return response.json(); };
Delete (Remove a Product)
Use a DELETE request:
// Add to src/utils/api.js export const deleteProduct = async (productId) => { const response = await fetch(`${BASE_API_URL}/products/${productId}`, { method: 'DELETE', }); if (!response.ok) throw new Error('Failed to delete product'); }; // In your ProductList component const handleDelete = async (productId) => { try { await deleteProduct(productId); // Update local state to remove the deleted product setProducts(prev => prev.filter(p => p._id !== productId)); } catch (err) { setError(err.message); } };
If something still isn’t working:
- Open your browser’s Network tab (F12 > Network)
- Compare the request details (method, headers, body) to what you sent in Postman
- Look for error status codes (4xx = client error, 5xx = server error) and check the response body for clues
- Make sure your Express API is running when you start your React app
- Double-check that your API routes match exactly what you’re calling in React (e.g.,
/api/productsvs/products) - Ensure MongoDB is connected and your API is correctly reading/writing to the database
内容的提问来源于stack exchange,提问作者VColson

