Saya sedang cuba menggunakan operator spread untuk menolak item ke dalam tatasusunan dalam React, tetapi saya mendapat ralat berikut.
Ralat berlaku dalam komponen PhotoUploader dalam PlacesForm.jsx. Saya telah memasukkan kod ke dalam komponen di bawah.
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} />
Ralat berlaku dalam fungsi addPhotobyLink() dan uploadPhoto(). Permintaan siaran dan bahagian belakang berfungsi dengan baik dan "nama fail" ditakrifkan untuk kedua-duanya, tetapi ada yang tidak kena dengan bahagian "setAddedPhotos". Berikut ialah komponen itu sendiri (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
Setakat ini saya telah mencuba:
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
Dalam React, biasanya tidak disyorkan untuk lulus fungsi kemas kini status
Salah satu sebab untuk melakukan ini ialah ia boleh menyebabkan pemaparan semula yang tidak perlu dan menjadikan kod lebih sukar untuk difikirkan. Jika komponen anak menerima fungsi setAddedPhotos sebagai prop dan memanggilnya, ia akan mencetuskan kemas kini keadaan dalam komponen induk, yang seterusnya mencetuskan penyajian semula komponen induk dan semua anak-anaknya. Ini boleh menjadi masalah jika pepohon komponen besar dan/atau keadaan berubah dengan kerap, kerana ia boleh menyebabkan banyak pemaparan semula yang tidak perlu.
Sebab lain ialah ia mungkin melanggar prinsip enkapsulasi, yang merupakan salah satu faedah utama menggunakan React. Enkapsulasi bermaksud bahawa setiap komponen harus mempunyai keadaan dan tingkah laku bebasnya sendiri, dan tidak boleh mengubah suai secara langsung keadaan komponen induk atau saudaranya. Apabila komponen kanak-kanak menerima fungsi pengemas kini keadaan sebagai prop, ia boleh mengakses dan mengubah suai keadaan komponen induknya, yang boleh menjadikannya lebih sukar untuk membuat alasan tentang kelakuan pepohon komponen.
Daripada menghantar fungsi setAddedPhotos kepada komponen anak. Anda boleh lulus fungsi tingkah laku seperti ini.