如何在React类组件中保存FormData并通过Cloudinary实现图片上传
问题解决指南
1. FormData为空及数据保存功能修复
你遇到的FormData为空的问题是由以下几个代码错误导致的,修复后即可正常提交:
- 普通文本输入和文件输入的状态更新逻辑混用:当前
onChange方法只适配普通文本输入,文件选择时需要取e.target.files[0]而非e.target.value - axios调用语法错误:你混用了fetch的请求配置写法,axios.post第二个参数直接传FormData实例即可,不需要封装为
{body: formData}结构 - FormData打印方式错误:直接打印FormData实例看不到内部数据,需要用
formData.get(字段名)或者遍历entries方法查看内容,你以为的null属于打印方式不对导致的误判 - 缺少form-data专属请求头:发送form-data格式数据需要指定
Content-Type: multipart/form-data请求头
修复后的代码片段
首先修改onChange方法:
// 别忘了先导入axios:import axios from 'axios' onChange(e) { // 区分普通输入和文件输入 if (e.target.type === 'file') { this.setState({ [e.target.name]: e.target.files[0] }); } else { this.setState({ [e.target.name]: e.target.value }); } }
然后修改onSubmit中的axios请求部分:
axios.post(`${APIURL}/menulist/add-item-to-menu`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then((res) => { // 原有业务逻辑保持不变 if (res.data.code === 200) { toast.success(res.data.message); window.setTimeout(function () { window.location.href = "/login"; }, 2000); } else { toast.error(res.data.message); } });
注意:你的文件选择input标签需要设置name="image"属性,和state中的字段对应
2. React类组件使用Cloudinary上传图片
推荐使用前端直传方案,逻辑如下:
- 先在Cloudinary控制台获取你的
cloud_name,并开启unsigned上传拿到上传预设值 - 新增图片上传方法,先把图片传到Cloudinary拿到资源链接和ID,再把这两个参数和菜品信息一起传给你的后端接口
代码示例
// 新增Cloudinary上传方法 uploadToCloudinary = (file) => { const cloudFormData = new FormData(); cloudFormData.append('file', file); cloudFormData.append('upload_preset', '你的上传预设值'); return axios.post('https://api.cloudinary.com/v1_1/你的cloud_name/image/upload', cloudFormData); } // 修改onSubmit逻辑 onSubmit = async (event) => { event.preventDefault(); try { // 先上传图片到Cloudinary const cloudRes = await this.uploadToCloudinary(this.state.image); // 提取Cloudinary返回的资源信息 const item_url = cloudRes.data.secure_url; const cloudinary_id = cloudRes.data.public_id; // 组装你自己的接口请求参数 const formData = new FormData(); formData.append("item_name", this.state.item_name); formData.append("item_type", this.state.item_type); formData.append("item_time", this.state.item_time); formData.append("item_price_type_small", this.state.item_price_type_small); formData.append("item_price_type_medium", this.state.item_price_type_medium); formData.append("item_price_type_large", this.state.item_price_type_large); formData.append("item_url", item_url); formData.append("cloudinary_id", cloudinary_id); // 调用你自己的新增菜品接口 const res = await axios.post(`${APIURL}/menulist/add-item-to-menu`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }); // 原有业务逻辑不变 if (res.data.code === 200) { toast.success(res.data.message); setTimeout(() => window.location.href = "/login", 2000); } else { toast.error(res.data.message); } } catch (err) { toast.error('操作失败,请重试'); } }
内容的提问来源于stack exchange,提问作者Thanukshi Wickramasinghe
相关产品推荐
相关产品推荐

