Node React,Action到达后端但不保存产品
Posted
技术标签:
【中文标题】Node React,Action到达后端但不保存产品【英文标题】:Node React, Action reaches the backend but does not save the product 【发布时间】:2020-05-13 05:09:15 【问题描述】:所以,我创建了模型、路由、控制器,从代码来看一切都很好。我还为前端创建了减速器、动作和组件。当我尝试创建产品时,它会触发操作并且似乎正在成功调度,但在 redux devtools 中,我可以看到我在产品数组中获得的项目为 NULL。此外,当我检查我的数据库时,产品没有得到保存。奇怪的是,我可以在位于后端的图像文件夹中看到我的图像。我不知道我是否正确设置了动作、组件或控制器,甚至可能是路由。如果有人可以对此进行调查,我会很高兴,也许我的实施是错误的。我将链接我的 Github 并在下面粘贴一些代码。
顺便说一句,我能够注册、登录和获取用户,所以它与此功能有关。 如果您认为我的某些方法有误,我也很高兴更改我的应用程序中的内容,我是这个 Stack 的新手
Github 链接:https://github.com/tigerabrodi/eBuy
server.js(后端)
const express = require('express');
const connectDB = require('./config/db');
const uuidv4 = require("uuid/v4")
const colors = require("colors");
const morgan = require("morgan");
const multer = require("multer");
const path = require("path");
const app = express();
const PORT = process.env.PORT || 9045;
// Importing Routes
const authRoutes = require("./routes/auth");
const productRoutes = require("./routes/products");
// Connect Database
connectDB();
// Configuring Multer storage
const fileStorage = multer.diskStorage(
destination: (req, file, cb) =>
cb(null, 'images');
,
filename: (req, file, cb) =>
// I used a regex to trim the name from spaces
cb(null, uuidv4() + "_" + file.originalname.replace(/\s/g, ''));
);
const fileFilter = (req, file, cb) =>
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
)
cb(null, true);
else
cb(null, false);
;
// Init Middleware
app.use(express.json( extended: false ));
// Use Multer
app.use(
multer( storage: fileStorage, fileFilter: fileFilter ).single('image')
);
// Serving static for images folder
app.use('/images', express.static(path.join(__dirname, 'images')));
// Dev logging middleware
if (process.env.NODE_ENV === "development")
app.use(morgan("dev"));
// Define Routes
app.use('/auth', authRoutes);
app.use('/products', productRoutes);
// Serve static assets in production
if (process.env.NODE_ENV === 'production')
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
);
app.listen(PORT, () => console.log(`Server started on port $PORT`.cyan.underline.bold));
产品路线(后端)
const express = require("express");
const auth = require("../middleware/auth");
const check = require("express-validator");
const productController = require("../controllers/products");
const router = express.Router();
// Create Product
router.post("/", [
auth,
[
check("title", "Title is required").notEmpty(),
check("description", "Description is required").notEmpty(),
check("image", "Image is required").notEmpty(),
check("price", "Price is required").isNumeric()
]
], productController.createProduct);
module.exports = router;
产品模型(后端)
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ProductSchema = new Schema(
user:
type: Schema.Types.ObjectId,
ref: "User"
,
title:
type: String,
required: true
,
description:
type: String,
required: true
,
price:
type: Number,
required: true
,
image:
type: String,
required: true
,
date:
type: Date,
default: Date.now
,
,
toJSON: virtuals: true
)
ProductSchema.virtual("question",
ref: "Question",
localField: "_id",
foreignField: "product"
);
module.exports = mongoose.model("Product", ProductSchema);
产品控制器(后端)
const validationResult = require("express-validator");
const User = require("../models/User");
const Product = require("../models/Product");
// @route POST /products
// @desc Add Product
// @access Private
exports.createProduct = async (req, res, next) =>
const errors = validationResult(req);
if (!errors.isEmpty())
return res.status(400).json( errors: errors.array() );
try
const title, description, price = req.body;
if (!req.file)
return res.status(400).json(msg: "Please upload an Image!")
const image = "/" + req.file.path.replace("\\" ,"/");
const newProduct = new Product(
user: req.user.id,
title,
description,
price,
image
);
const product = await newProduct.save();
res.status(201).json(product);
console.log(product);
next();
catch (err)
console.error(err.message);
res.status(500).send("Server Error");
next(err);
产品减速器(前端)
import ProductActionTypes from "./product.types";
const initialState =
products: [],
totalProducts: null,
product: null,
loading: true,
error:
const productReducer = (state = initialState, action) =>
const payload, type = action;
switch(type)
case ProductActionTypes.ADD_PRODUCT:
return
...state,
products: [payload, ...state.products],
loading: false
case ProductActionTypes.PRODUCT_ERROR:
return
...state,
error: payload,
loading: false
default:
return state;
export default productReducer
产品操作(前端)
import ProductActionTypes from "./product.types"
import setAlert from "../alert/alert.actions"
import axios from "axios"
export const addProduct = (productData, history) => async dispatch =>
const config =
headers:
"Content-Type": "multipart/form-data"
;
const formData = new FormData();
formData.append("title", productData.title)
formData.append("description", productData.description)
formData.append("price", productData.price)
formData.append("image", productData.image)
try
const res = axios.post("/products/", formData, config);
dispatch(
type: ProductActionTypes.ADD_PRODUCT,
payload: res.data
)
history.push("/dashboard");
dispatch(setAlert("Product created successfully", "success"))
catch (err)
const errors = err.response.data.errors;
if (errors)
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
dispatch(
type: ProductActionTypes.PRODUCT_ERROR,
payload: msg: err.response.statusText, status: err.response.status
)
产品类型(前端)
export const ProductActionTypes =
ADD_PRODUCT: "ADD_PRODUCT",
PRODUCT_ERROR: "PRODUCT_ERROR"
产品组件(前端)
import React, Fragment, useState from 'react';
import withRouter from "react-router-dom";
import connect from "react-redux";
import addProduct from '../../redux/product/product.actions';
const CreateProduct = (history, addProduct) =>
const [formData,
setFormData] = useState(name: "", description: "", price: 10, image: "");
const [showImage, setShowImage] = useState(false);
const [imageName, setImageName] = useState("")
const onSubmit = e =>
e.preventDefault();
addProduct(formData, history);
const onChangeImage = e =>
setFormData(...formData, image: e.target.files[0]);
setShowImage(true);
setImageName(e.target.files[0].name)
const onChange = e => setFormData(
...formData,
[e.target.name]: e.target.value
);
const name, description, price = formData;
return (
<Fragment>
<div className="container">
<div className="row">
<div className="col text-info font-weight-bold m-2">
*- All Fields Requried
<form onSubmit=e => onSubmit(e)>
<div className="form-group m-2">
<label htmlFor="name">Name</label>
<input type="text" placeholder="Enter Products Name" name="name" value=name onChange=e => onChange(e) className="form-control" required/>
</div>
<div className="form-group m-2">
<label htmlFor="price">Price</label>
<input type="number" name="price" placeholder="Enter Products Price" value=price onChange=e => onChange(e) className="form-control" required/>
</div>
<div class="custom-file m-2">
<input type="file" onChange=e => onChangeImage(e) class="custom-file-input bg-info" required/>
<label class="custom-file-label">showImage ? imageName : "Upload Image"</label>
</div>
<div className="form-group m-2">
<label htmlFor="title">Description</label>
<textarea name="description" onChange=e => onChange(e) placeholder="Enter Products description" value=description className="form-control" required/>
</div>
<input type="submit" value="Add Product" className="btn btn-block btn-info"/>
</form>
</div>
</div>
</div>
</Fragment>
);
export default connect(null, addProduct)(withRouter(CreateProduct));
【问题讨论】:
在产品操作addProduct中,这里需要添加awaitconst res = axios.post("/products/", formData, config);
可以添加重试吗?
是的,我做到了,现在我正在努力上传图片,我在图片文件夹中看到图片,但它仍然说需要图片,我将如何优化我的控制器?
我需要以某种方式访问控制器中的图像:(
“需要图片”怎么说?你能把这个确切的错误添加到问题中吗?
现在我正在调试一下,因为它说名字是必需的,我的名字和标题出错了,但我现在需要去,我稍后会回来更新这个问题,我希望我应该能够解决这个问题
【参考方案1】:
没什么好说的,正如苏莱曼所说,我忘了等待。其他事情是删除标题,因为 formData 自己会这样做,并且可以通过 req.file.path 访问图像。我将在下面发布我的控制器和操作,供人们稍后参考。
产品负责人
// @route POST /products
// @desc Add Product
// @access Private
exports.createProduct = async (req, res, next) =>
const errors = validationResult(req);
if (!errors.isEmpty())
return res.status(400).json( errors: errors.array() );
try
console.log(req.body);
const name, description, price = req.body;
if (!req.file)
return res.status(400).json(msg: "Please upload an Image!")
const image = "/" + req.file.path.replace("\\" ,"/");
const newProduct = new Product(
user: req.user.id,
name,
description,
price,
image
);
const product = await newProduct.save();
res.status(201).json(product);
console.log(product);
next();
catch (err)
console.error(err.message);
res.status(500).send("Server Error");
next(err);
产品操作
export const addProduct = (productData, history) => async dispatch =>
const formData = new FormData();
formData.append("name", productData.name);
formData.append("description", productData.description);
formData.append("price", productData.price);
formData.append("image", productData.image);
try
const res = await axios.post("/products", formData);
dispatch(
type: ProductActionTypes.ADD_PRODUCT,
payload: res.data
);
history.push("/dashboard");
dispatch(setAlert("Product created successfully", "success"))
catch (err)
const errors = err.response.data.errors;
if (errors)
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
dispatch(
type: ProductActionTypes.PRODUCT_ERROR,
payload: msg: err.response.statusText, status: err.response.status
)
【讨论】:
以上是关于Node React,Action到达后端但不保存产品的主要内容,如果未能解决你的问题,请参考以下文章
Route.get() 需要一个回调函数但得到一个 [object Object]
两个独立的 Heroku(Node 后端和 React 前端)之间的通信?
React App 和 node.js 后端 api 安全获取