我目前正在嘗試使用展開運算子將專案推送到 React 中的陣列中,但收到以下錯誤。
該錯誤發生在 PlacesForm.jsx 內的 PhotoUploader 元件中。我已將程式碼包含到下面的元件中。
PlacesForm.jsx:
import axios from 'axios' import React, { useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import AccountNav from './AccountNav' import Perks from './Perks' import PhotosUploader from './PhotosUploader' function PlacesForm() { const {id} = useParams() const [title, setTitle] = useState("") const [address, setAddress] = useState("") const [addedPhotos, setAddedPhotos] = useState([]) //state in question const [description, setDescription] = useState("") const [perks, setPerks] = useState([]) const [extraInfo, setExtraInfo] = useState("") const [checkIn, setCheckIn] = useState("") const [checkOut, setCheckOut] = useState("") const [maxGuests, setMaxGuests] = useState(1) useEffect(() => { if (!id) return const getPlace = async () => { try { const {data} = await axios.get(`/places/${id}`) setTitle(data.title) setAddress(data.address) setAddedPhotos(data.addedPhotos) setDescription(data.description) setPerks(data.perks) setExtraInfo(data.extraInfo) setCheckIn(data.checkIn) setCheckOut(data.checkOut) setMaxGuests(data.maxGuests) } catch (e) { console.log(e) } } getPlace() }, [id]) const navigate = useNavigate() const inputHeader = (text) => { return ( <h2 className='text-2xl mt-4'>{text}</h2> ) } const inputDescription = (text) => { return ( <p className="text-gray-500 text-sm">{text}</p> ) } const preInput = (header, description) => { return ( <> {inputHeader(header)} {inputDescription(description)} </> ) } const handleSubmit = async (e) => { e.preventDefault() const placeData = { title, address, addedPhotos, description, perks, extraInfo, checkIn, checkOut, maxGuests } if (id) { //update try { const res = await axios.put('/places', { id, ...placeData, }) navigate('/account/places') } catch (error) { console.log(error) } } else { //create new place try { const res = await axios.post('/places', placeData) navigate('/account/places') } catch (error) { console.log(error) } } } return ( <> <div> <AccountNav /> <form onSubmit={handleSubmit}> {preInput('Title', 'Something catchy and memorable')} <input type="text" placeholder="title" value={title} onChange={e => setTitle(e.target.value)} /> {preInput('Address', 'be specific')} <input type="text" placeholder="address" value={address} onChange={e => setAddress(e.target.value)} /> {preInput('Photos', 'Best to have at least 4')} <PhotosUploader addedPhotos={addedPhotos} setAddedPhotos={setAddedPhotos} />
該錯誤發生在 addPhotobyLink() 和 uploadPhoto() 函數中。發布請求和後端工作正常,並且為兩者定義了“檔案名稱”,但是“setAddedPhotos”部分出現了問題。這是元件本身 (PhotoUploader.jsx):
import axios from 'axios' import React, { useState } from 'react' function PhotosUploader({addedPhotos, setAddedPhotos}) { const [photoLink, setPhotoLink] = useState("") const addPhotoByLink = async (e) => { e.preventDefault() try { const {data:filename} = await axios.post('/upload-by-link', {link: photoLink}) setAddedPhotos(prev => [...prev, filename]) } catch (error) { console.log(error) } setPhotoLink("") } const uploadPhoto = async (e) => { const files = e.target.files const data = new FormData() for (let i = 0; i < files.length; i++) { data.append('photos', files[i]) } try { const {data:filenames} = await axios.post('/upload', data, { headers: {'Content-type': 'multipart/form-data'} }) setAddedPhotos(prev => [...prev, ...filenames]) } catch (error) { console.log(error) } } return ( <> <div className='flex gap-2' > <input value={photoLink} onChange={e => setPhotoLink(e.target.value)} type="text" placeholder="Add using link ....jpg" /> <button onClick={addPhotoByLink} className='bg-gray-200 px-4 rounded-2xl' > Add photo </button> </div> <div className="grid gap-2 grid-cols-3 lg:grid-cols-6 md:grid-cols-4 mt-2"> {addedPhotos?.length > 0 && addedPhotos.map((link) => ( <div key={link} className="h-32 flex"> <img src={'http://localhost:3000/uploads/' + link} alt="" className='rounded-2xl w-full object-cover position' /> </div> ))} <label className="h-32 cursor-pointer flex items-center justify-center gap-2 border bg-transparent rounded-2xl p-2 text-2xl text-gray-600"> <input type="file" multiple className='hidden' onChange={uploadPhoto}/> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-8 h-8"> <path strokeLinecap="round" strokeLinejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" /> </svg> Upload </label> </div> </> ) } export default PhotosUploader
到目前為止,我已經嘗試過:
setAddedPhotos(prev => [...prev, filename]) //didn't work setAddedPhotos([...prev, filename]) //didn't work setAddedPhotos([...addedPhotos, filename]) //didn't work, addPhotos isn't iterable error setAddedPhotos(prev => [...addedPhotos, filename]) //didn't work
P粉2935505752024-03-28 15:52:21
在React中,一般不建議傳遞狀態更新函數
#這樣做的一個原因是它可能導致不必要的重新渲染並使程式碼更難以推理。如果子元件接收 setAddedPhotos 函數為 prop 並呼叫它,它將觸發父元件中的狀態更新,進而觸發父元件及其所有子元件的重新渲染。如果元件樹很大和/或狀態頻繁更改,這可能會成為問題,因為它可能導致大量不必要的重新渲染。
另一個原因是它可能違反封裝原則,而封裝原則是使用 React 的主要好處之一。封裝意味著每個元件應該有自己獨立的狀態和行為,並且不應該直接修改其父元件或兄弟元件的狀態。當子元件接收狀態更新器函數作為 prop 時,它可以存取並修改其父元件的狀態,這可能會使推理元件樹的行為變得更加困難。
而不是將 setAddedPhotos 函數傳遞給子元件。你可以像這樣傳遞行為函數。
import React from 'react'; function PlacesForm() { const [addedPhotos, setAddedPhotos] = useState([]); const handleAddedPhotos = (newStates) => { setAddedPhotos(prev => [...prev, ...newStates]); }; return (); } function PhotosUploader({ addedPhotos, handleAddedPhotos }) { const uploadPhoto = async (e) => { const files = e.target.files const data = new FormData() for (let i = 0; i < files.length; i++) { data.append('photos', files[i]) } try { const {data:filenames} = await axios.post('/upload', data, { headers: {'Content-type': 'multipart/form-data'} }) handleAddedPhotos(filenames) } catch (error) { console.log(error) } } return ( <>> ); }