Как я могу иметь несколько зон доступа на одной странице, которые просматривают несколько изображений при использовании react-dropzone?

#reactjs #react-dropzone

#reactjs #react-dropzone

Вопрос:

Я использую react-dropzone в своем приложении и хотел бы иметь несколько зон доступа на одной странице для предварительного просмотра нескольких изображений. Например, я хотел бы иметь возможность поместить изображение героя в выпадающую зону, которая отображает изображение героя в верхней части страницы. Затем я хотел бы поместить другое изображение в другую выпадающую зону, которая отображает изображение в контейнере эскизов.

 import React, { useState, useMemo, useEffect } from "react";
import Container from "../components/Container";
import { useDropzone } from "react-dropzone";

const Test = () => {
  // Dropzone
  const baseStyle = {
    flex: 1,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    padding: "20px",
    borderWidth: 2,
    borderRadius: 2,
    borderColor: "#eeeeee",
    borderStyle: "dashed",
    backgroundColor: "#fafafa",
    color: "#bdbdbd",
    outline: "none",
    transition: "border .24s ease-in-out",
  };

  const activeStyle = {
    borderColor: "#2196f3",
  };

  const acceptStyle = {
    borderColor: "#00e676",
  };

  const rejectStyle = {
    borderColor: "#ff1744",
  };

  const [files, setFiles] = useState({});
  const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
    accept: "image/*",
    onDrop: (acceptedFiles) => {
      console.log(acceptedFiles);
      setFiles(
        Object.assign(acceptedFiles[0], {
          preview: URL.createObjectURL(acceptedFiles[0]),
        })
      );
    },
  });

  const style = useMemo(
    () => ({
      ...baseStyle,
      ...(isDragActive ? activeStyle : {}),
      ...(isDragAccept ? acceptStyle : {}),
      ...(isDragReject ? rejectStyle : {}),
    }),
    [isDragActive, isDragReject, isDragAccept]
  );

  useEffect(
    () => () => {
      // Make sure to revoke the data uris to avoid memory leaks
      URL.revokeObjectURL(files.preview);
    },
    [files]
  );

  return (
    <Container>
      {/* This would be the dropzone for the Hero image */}
      <div>
        <div {...getRootProps({ style })}>
          <input {...getInputProps()} />
          <span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
        </div>
      </div>

      {/* This would be the dropzone for the Thumbnail image */}
      <div>
        <div {...getRootProps({ style })}>
          <input {...getInputProps()} />
          <span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
        </div>
      </div>

      {/* This would be where the Hero image is displayed */}
      <img
        style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
        src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
        alt="Hero Image"
      />

      {/* This would be where the Thumbnail image is displayed */}
      <img
        style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
        src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
        alt="Thumbnail Image"
      />
    </Container>
  );
};

export default Test;

  

Я предполагаю, что мне нужно изменить функцию onDrop, но я не могу понять, как это сделать. Любая помощь будет с благодарностью!

Ответ №1:

  • Создайте две отдельные файловые переменные и обрабатывайте их отдельно.

  • используйте два отдельных getRootsProps и getInputProps для обоих входов.

      const [file, setFile] = useState({}); 
     const [fileGallery, setFileGallery] = useState({}); 
    
     const { getRootProps:getRootfileProps, getInputProps:getInputfileProps  } = useDropzone({
         accept: 'image/*',
         onDrop: (acceptedFile) => {
             setFile(
                 Object.assign(acceptedFile[0], {
                     preview: URL.createObjectURL(acceptedFile[0]),
                 }),
             );
         },
     });
    
     const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
         accept: 'image/*',
         onDrop: (acceptedFile) => {
             setFileGallery(
                 Object.assign(acceptedFile[0], {
                     preview: URL.createObjectURL(acceptedFile[0]),
                 }),
             );
         },
     });
    
    
     return (
         <Container>
         {/* This would be the dropzone for the Hero image */}
         <div>
             <div {...getRootfileProps({ style })}>
             <input {...getInputfileProps()} />
             <span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
             </div>
         </div>
    
         {/* This would be the dropzone for the Thumbnail image */}
         <div>
             <div {...getRootGalleryProps({ style })}>
             <input {...getInputGalleryProps()} />
             <span style={{ fontSize: ".8rem" }}>Drop hero image here, or click to select file</span>
             </div>
         </div>
    
         {/* This would be where the Hero image is displayed */}
         <img
             style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
             src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
             alt="Hero Image"
         />
    
         {/* This would be where the Thumbnail image is displayed */}
         <img
             style={{ width: "600px", height: "200px", margin: "0", display: "block" }}
             src={files.preview ? files.preview : "https://via.placeholder.com/600x200"}
             alt="Thumbnail Image"
         />
         </Container>
     );
     };
    
     export default Test;
      

Ответ №2:

вам нужно создать две отдельные файловые переменные и обрабатывать их отдельно. также вы используете одни и те же getRootsProps и getInputProps для обоих входов, что неверно.

 const [file, setFile] = useState({}); 
  const [fileGallery, setFileGallery] = useState({}); 
    const { getRootProps:getRootfileProps, getInputProps:getInputfileProps  } = useDropzone({
        accept: 'image/*',
        onDrop: (acceptedFile) => {
          setFile(
            Object.assign(acceptedFile[0], {
              preview: URL.createObjectURL(acceptedFile[0]),
            }),
          );
        },
      });
      const { getRootProps:getRootGalleryProps, getInputProps:getInputGalleryProps } = useDropzone({
        accept: 'image/*',
        onDrop: (acceptedFile) => {
          setFileGallery(
            Object.assign(acceptedFile[0], {
              preview: URL.createObjectURL(acceptedFile[0]),
            }),
          );
        },
      });
  

Ответ №3:

Вы должны использовать два отдельных имени файлов в состоянии одно для героя одно для миниатюры и управлять каждым из них для каждой выпадающей зоны примерно так:

 const [heroFiles, setHeroFiles] = useState({});
const [filesThumb, setFilesThumb] = useState({});
  

Ответ №4:

вы используете перехват Dropzone, и это затруднит достижение того, к чему вы стремитесь, вместо этого используйте компонент Dropzone и объявляйте состояние для каждого ввода Dropzone, который вы собираетесь использовать.

 import React, { useState } from "react";
import Container from "../components/Container";
import Dropzone from "react-dropzone";

const Test = () => {
    const [heroFiles, setHeroFiles] = useState([]);
    const [thumbnailFiles, setThumbnailFiles] = useState([]);
    
    return (
        <Container>
            {/* This would be the dropzone for the Hero image */}
            <Dropzone  onDrop={(acceptedFiles) => {
                  setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
                      preview: URL.createObjectURL(file)
                  })));
               }} name="heroImage" multiple={false}>
               {({getRootProps, getInputProps}) => (
                   <div {...getRootProps({className: 'dropzone'})}>
                       <input {...getInputProps()} />
                       <span style={{ fontSize: ".8rem" }}>
                            Drop hero image here, or click to select file
                       </span>
                   </div>
               )}
          </Dropzone>
          {/* This would be the dropzone for the Thumbnail image */}
          <Dropzone  onDrop={(acceptedFiles) => {
                  setHeroFiles(acceptedFiles.map(file => Object.assign(file, {
                      preview: URL.createObjectURL(file)
                  })));
               }} name="heroImage" multiple={false}>
               {({getRootProps, getInputProps}) => (
                   <div {...getRootProps({className: 'dropzone'})}>
                       <input {...getInputProps()} />
                       <span style={{ fontSize: ".8rem" }}>
                            Drop hero image here, or click to select file
                       </span>
                   </div>
               )}
            </Dropzone>
            {/* This would be where the Hero image is displayed */}
            <img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={heroFiles.length > 0 ? heroFiles[0].preview : "https://via.placeholder.com/600x200"} alt="Hero Image"/>
            {/* This would be where the Thumbnail image is displayed */}
            <img style={{ width: "600px", height: "200px", margin: "0", display: "block" }} src={thumbnailFiles.length > 0  ? thumbnailFiles[0].preview  : "https://via.placeholder.com/600x200"} alt="Thumbnail Image"/>
        </Container>
    );
}

export default Test;
  

предполагается, что это решит ваши проблемы.