cari

Rumah  >  Soal Jawab  >  teks badan

Ralat tindak balas: Item tidak boleh diubah apabila ditambahkan pada keadaan

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&nbsp;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

P粉709644700P粉709644700231 hari yang lalu457

membalas semua(1)saya akan balas

  • P粉293550575

    P粉2935505752024-03-28 15:52:21

    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.

    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 (
           <>
      );
    }

    balas
    0
  • Batalbalas