javascriptreactjsreact-dropzone

Edit Product with images using React-Dropzone


When creating a product I use React-Dropzone but when editing I intend to use it in the same way. I would like that when editing the product, the images that are already uploaded to the product are displayed under React-Dropzone so that the user can delete them all, or just one, etc.

This code works fine when uploading images, but when I pass the array with the images that already have the product in the database at the time of editing, it shows me the empty image preview:

import React from 'react';
import {useDropzone} from 'react-dropzone'
import { useState, useEffect } from 'react'

const DragAndDrop = ({files, setFiles, setDropError }) => {

  console.log(files); //Array of images that the product already has in the database

  const onDropRejected = () => {
    setDropError('Imágenes con tamaño Máximo de 1MB')
    setTimeout(() => {
      setDropError('')
    }, 3000)
  }

  const {
    acceptedFiles,
    fileRejections,
    getRootProps,
    getInputProps
  } = useDropzone({  
    accept: {
      'image/jpeg': [],
      'image/jpg': [],
      'image/png': []
    },  
    maxFiles:3,
    maxSize:1000000,
    onDropRejected,
    onDropAccepted: acceptedFiles => {
      console.log(acceptedFiles);
      if (files.length<1){
          setFiles(acceptedFiles.map(file =>
          Object.assign(file, {
            preview: URL.createObjectURL(file)
          }))); 
      } else {
        setFiles(files.map(file => 
          Object.assign(file, {
            preview: URL.createObjectURL(file) //Here I try to pass the images to create the preview but the images are not shown
          }))); 
      }
    }
  })

...

How can I accomplish this task? Thank you.


Solution

  • Solution:

    import React from 'react';
    import {useDropzone} from 'react-dropzone'
    import { useState, useEffect } from 'react'
    
    const DragAndDrop = ({files, setFiles, setDropError, totalFiles }) => {
    
      //const [files, setFiles] = useState([])
    
    
      const onDropRejected = () => {
        setDropError('Hasta 3 imágenes. máximo 2 MB')
        setTimeout(() => {
          setDropError('')
        }, 3000)
      }
    
      const {
        acceptedFiles,
        fileRejections,
        getRootProps,
        getInputProps
      } = useDropzone({  
        accept: {
          'image/jpeg': [],
          'image/jpg': [],
          'image/png': []
        },  
        maxFiles:3,
        maxSize:2000000,
        onDropRejected,
        onDropAccepted: acceptedFiles => {
         setFiles(acceptedFiles.map(file => 
          Object.assign(file, {
            preview: URL.createObjectURL(file)
          }))); 
        }
      })
    
      const removeFile = file => () => {
        const newFiles = [...files]
        newFiles.splice(newFiles.indexOf(file), 1)
        setFiles(newFiles)
      }
    
      const removeAll = () => {
        setFiles([])
      }
    
      const thumbs = files.map(file => (
    
          <div key={file.name}>
            <button onClick={removeFile(file)} className="text-center hover:bg-blue-200 absolute rounded">
              <span className='p-2 text-center text-lg'>x</span>
            </button>
            <div className='w-32'>
              <img
                src={file.preview}
                // Revoke data uri after image is loaded
                onLoad={() => { URL.revokeObjectURL(file.preview) }}
              />
            </div>
          </div>
      ))
    
      useEffect(() => {
        // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
        return () => files.forEach(file => URL.revokeObjectURL(file.preview));
      }, []);
    
      const acceptedFileItems = acceptedFiles.map(file => (
        <li key={file.path}>
          {file.path} - {file.size} bytes
        </li>
      ));
    
      const fileRejectionItems = fileRejections.map(({ file, errors  }) => { 
       return (
         <li key={file.path}>
              {file.path} - {file.size} bytes
              <ul>
                {errors.map(e => <li key={e.code}>{e.message}</li>)}
             </ul>
         </li>
       ) 
      });
      
    
      return (
        <section className={`container mt-6`}>
          <div {...getRootProps({ className: 'dropzone' })} 
          className={`flex flex-col w-full border-2 border-cyan-600 border-dashed p-4 cursor-pointer  ${ files.length === 3 || totalFiles && totalFiles.length === 3  && 'pointer-events-none'  }`}>
            <input {...getInputProps()} />
            {
              files.length === 3 || totalFiles && totalFiles.length === 3 ? (
                <div className='flex justify-center'>
                  <div className=' text-center gap-2 mb-2'>
                    <p>Deshabilitado - Máximo 3 imágenes</p>
                  </div>
                </div>
              ) : (
                <div className='text-center gap-2 mb-2'>
                  <p>Arrastra y suelta imágenes o selecciona dando click</p>
                  <em className='text-xs'>(Máximo 3 imágenes, .jpg, .png)</em>
                </div>
              )
            }
          </div>
          <aside className='text-xs mt-4'>
          {files.length === 3 && <div>{files.length}</div>}
        {/*     <h4>Archivos Correctos</h4>
            <ul>{acceptedFileItems}</ul>
            <h4>Archivos con error</h4>
            <ul>{fileRejectionItems}</ul> */}
            <div className="flex gap-4 justify-center">
              {thumbs}
            </div>
          </aside>
          {files.length > 0 && <button onClick={removeAll} className="btn btn-xs text-xs mt-4 btn-ghost">Eliminar</button>}
        </section>
      );
    }
    
    export default DragAndDrop