React调用setState后let声明的FormData丢失数据,寻求更优实现方案
你遇到的问题核心是组件顶层声明的fd变量会在每次组件重渲染时被重新赋值为新的FormData实例,之前存储的内容自然就丢失了。你目前将图片存在state的方案是可行的,还有两种更简洁的实现方式:
方案1:使用useRef存储FormData实例(适配现有写法的最小改动优化)
useRef的存储值不会随组件重渲染重置,也不会触发重渲染,完全适配你需要持久化存储FormData的场景。
import { useRef } from 'react' const [ImageUploaded, setImageUploaded] = useState('') const [response, setResponse] = useState(null) const [error, setError] = useState(null) const [loading, setLoading] = useState(false) // 用useRef存FormData,重渲染不会重置 const fdRef = useRef(new FormData()) const onImageUpload = async (e) => { let file = e.target.files[0] // 操作ref的current属性 fdRef.current.append('file', file) setImageUploaded(file.name) } const uploadProduct = async(e) => { e.preventDefault() setLoading(true) try { const productData = { productName: inputState.productName.value, description: inputState.description.value, price: inputState.price.value, quantity: inputState.quantity.value } const {data} = await axios.post('/api/products/new', productData) const response = await axios.post(`/api/upload/${data.id}`, fdRef.current, { headers: { 'Content-Type': `multipart/form-data` }, onUploadProgress: (uploadState) => console.log(uploadState.loaded) }) setLoading(false) if (response.status===200) { setResponse(true) // 提交成功后可以清空FormData,避免重复提交 fdRef.current = new FormData() setImageUploaded('') } } catch (error) { setLoading(false) setError(true) } }
方案2:提交时再构建FormData(更推荐,逻辑更干净)
你已经把上传的文件存在state里了,完全不需要提前维护FormData实例,只需要在提交表单的时候,把state里的文件和其他数据一次性组装成FormData即可,不需要额外维护持久化实例,也不会出现数据丢失的问题,更符合React的状态管理逻辑。
// 新增state存储上传的文件对象 const [uploadedFile, setUploadedFile] = useState(null) const [ImageUploaded, setImageUploaded] = useState('') const [response, setResponse] = useState(null) const [error, setError] = useState(null) const [loading, setLoading] = useState(false) const onImageUpload = async (e) => { let file = e.target.files[0] // 只存文件对象到state,不提前处理FormData setUploadedFile(file) setImageUploaded(file.name) } const uploadProduct = async(e) => { e.preventDefault() setLoading(true) try { const productData = { productName: inputState.productName.value, description: inputState.description.value, price: inputState.price.value, quantity: inputState.quantity.value } const {data} = await axios.post('/api/products/new', productData) // 提交时才组装FormData const fd = new FormData() if (uploadedFile) { fd.append('file', uploadedFile) } const response = await axios.post(`/api/upload/${data.id}`, fd, { headers: { 'Content-Type': `multipart/form-data` }, onUploadProgress: (uploadState) => console.log(uploadState.loaded) }) setLoading(false) if (response.status===200) { setResponse(true) // 提交成功清空state即可 setUploadedFile(null) setImageUploaded('') } } catch (error) { setLoading(false) setError(true) } }
内容的提问来源于stack exchange,提问作者Amasa Abubakar
相关产品推荐
相关产品推荐

