node.js - 快速发布请求将我重定向到 json 页面,而不是显示成功或错误消息 toast
问题描述
我正在使用 MERN 堆栈制作一个 crud 应用程序来练习我的技能,因为我对此很陌生它在 Postman 上运行良好,但是当我将数据传递到前端(React 和 Redux)时,它也运行良好,但浏览器没有使用 toastfy 向我显示成功或错误消息,而是将我重定向到带有 json 数据的新页面我发了
PS。我尝试使用 formik 处理我的表单状态和错误,但它没有将我重定向到 json 页面,它显示了我从 toast 后端发送的错误消息,但对我不起作用,因为 formik 真的很复杂处理文件,所以我用简单的方法做到了
- 我使用 multer 处理图像
- 为前端做出反应
- redux 作为 react 的 store
- react-toastify 显示成功和错误信息
// multer 中间件来处理图像
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads/");
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({ storage, fileFilter });
这是验证和使用后端,它是一组方法
const createProduct = [
//validate product that it's not empthy
// then sanitize it with trima and escape
body("name")
.isLength({ min: 5 })
.withMessage("Must be at least 2 letters")
.trim()
.escape(),
body("description")
.isLength({ min: 20 })
.withMessage("Must be at least 10 letters")
.trim()
.escape(),
body("category")
.isLength({ min: 1 })
.withMessage("This field is required")
.trim()
.escape(),
body("price")
.isLength({ min: 1 })
.withMessage("Must be at least 1 number")
.isNumeric()
.withMessage("Must be Numeric")
.trim()
.escape(),
body("numberInStock")
.isLength({ min: 1 })
.withMessage("Must be at least 1 number")
.isNumeric()
.withMessage("Must be Numeric")
.trim()
.escape(),
// continue process after validation
(req, res, next) => {
console.log(req.file);
// get the validation errors from the request
const errors = validationResult(req);
// create new product after being validated and sanitized
let newProduct = new Product({
name: req.body.name,
description: req.body.description,
category: req.body.category,
price: req.body.price,
numberInStock: req.body.numberInStock,
productImage: req.file.path
});
// if there are validation errors send them as json
if (!errors.isEmpty()) {
//i only show the first error
let field = errors.errors[0].param;
let message = errors.errors[0].msg;
let errorMessage = field + " " + message;
res.status(400).json({
message: errorMessage
});
} else {
newProduct.save(function (err, product) {
if (err) {
console.log(err);
res.json({
message: "Couldn't create please try again"
});
} else {
res.redirect({
message: "Created Successfully",
product
});
}
});
}
}
];
处理路线
router.post("/api/product/create",upload.single("productImage"), createProduct);
//添加产品动作
export const addProduct = product => dispatch => {
return new Promise((resolve, reject) => {
axios
.post("/api/product/create", product)
.then(res => {
let newProduct = res.data.product;
let successMessage = res.data.message;
dispatch(addProductSuccess(newProduct, successMessage));
resolve(successMessage);
})
.catch(error => {
console.log(error.message);
dispatch(addProductFailure(error));
reject(error.message);
});
});
};
const addProductSuccess = (product, successMessage) => {
return {
type: ADD_PRODUCT_SUCCESS,
payload: {
product,
successMessage
}
};
};
const addProductFailure = error => {
return {
type: ADD_PRODUCT_FAILURE,
payload: {
error
}
};
};
//添加产品表单
function AddProductForm() {
// importing categories and laoding state from out store
const { categories, error, loading } = useSelector(
state => state.categoriesss
);
const [state, setState] = useState({
name: "",
description: "",
category: "",
price: "",
numberInStock: "",
productImage: ""
});
const handleChange = e => {
const { name, value } = e.target;
setState(prevState => ({
...prevState,
[name]: value
}));
};
// react redux method to dispatch our functions
const dispatch = useDispatch();
// fetch all the the categories with dispatch before our component render
useEffect(() => {
dispatch(fetchCategories());
}, [dispatch]);
// handle submit our form
const handleSubmitt = product => {
dispatch(addProduct(product))
.then(res => {
toast.success(res, {
position: toast.POSITION.BOTTOM_LEFT,
transition: Slide
});
})
.catch(err => {
toast.error(err, {
position: toast.POSITION.BOTTOM_LEFT,
autoClose: false
});
});
};
let newProduct = {
name: state.name,
description: state.description,
category: state.category,
price: state.price,
numberInStock: state.numberInStock,
productImage: state.productImage
};
return (
<Container>
<form
action='/api/product/create'
method='post'
enctype='multipart/form-data'
onSubmit={() => handleSubmitt(newProduct)}>
<div className='form-group'>
<input
className='form-control mb-2'
type='text'
placeholder='Enter Product name'
name='name'
required
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
className='form-control mb-2'
as='textarea'
placeholder='Enter Product description'
name='description'
required
onChange={handleChange}
/>
</div>
<div className='form-group'>
<select
className='custom-select mb-2'
name='category'
required
onChange={handleChange}>
{loading && <option>loading...</option>}
{categories.map(cat => {
return (
<option key={cat._id} value={cat._id}>
{cat.name}
</option>
);
})}
</select>
</div>
<div className='form-group'>
<input
className='form-control mb-2'
type='text'
placeholder='Enter Product price'
name='price'
required
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
className='form-control mb-2'
type='text'
placeholder='Enter Product numberInStock'
name='numberInStock'
required
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
className='custom custom-file mb-2'
type='file'
name='productImage'
required
onChange={handleChange}
/>
</div>
<Button
variant='primary'
type='submit'
onClick={() => handleSubmitt(newProduct)}>
Submit{" "}
</Button>{" "}
</form>
</Container>
);
}
export default AddProductForm;
解决方案
尝试这个
<form
action='/api/product/create'
method='post'
enctype='multipart/form-data'
onSubmit={(e) => {
handleSubmitt(newProduct)
e.preventDefault()
}>
推荐阅读
- php - Stripe:“必须提供来源或客户”
- typescript - 向 .vue 文件添加选项
- spring-boot - Spring Boot 中的速率限制 API
- javascript - 如何检查从数组创建的复选框是否设置为 TRUE
- javascript - Angular 9 中的单例服务不起作用
- reactjs - jspdf 没有以正确的高度和宽度(以像素为单位)呈现
- r - 使用新数据评估线性模型会返回拟合值
- javascript - 为什么使用函数来创建数据结构而不是类?它甚至正确吗?
- python - 使用 Threading.Timer 与 Arduino 发生串行通信错误
- javascript - 如何使我的暗模式在全屏打开时工作?