@mantine dropzone React image upload issues while image upload on login form

4.8k Views Asked by At

I tried for getting the image path with Dropzone in this way {...form.getInputProps("tourImages")} but it gives undefined . Also, I tried getting an image input with useState hooks, image path is displaying but, it is not displaying inside of form. Please, see the below :

      const getImage = (imageFile: any) => {
           setImageUpload(imageFile[0].path);
      };
      const [imageUpload, setImageUpload] = useState( );
    
      const form = useForm({
        schema: joiResolver(schema),
        initialValues: {
          name: "",
          sername: "",
          email: "",
          tourImages : "" ,
          imageUpload,
         
        },
      });

 <Dropzone
                    onDrop={(files) => {
                      getImage(files);
                    
                    }}
                    onReject={(files) => console.log("rejected files", files)}
                    maxSize={3 * 1024 ** 2}
                    accept={IMAGE_MIME_TYPE}
                    {...form.getInputProps("tourImages")}
                  >
                    {(status) => dropzoneChildren(status, theme)}
                  </Dropzone>
    
2

There are 2 best solutions below

2
On

With Mantine dropzone provider you could upload your files with files parameter in onDrop={} method. This onDrop function calls after file selected from user successfully. So after file selection you will able to upload your files to upload server with multipart/form-data request using Fetch Api like shown below. If you want to validate upload url. You should pass api returned url string to react state in the end of the onDrop() method.
Example usage of Dropzone:

export default function DropzoneExample() {
    return (
        <Dropzone
            multiple={false}
            onDrop={(files) => {
                console.log(files);
                const formData = new FormData();
                formData.append('file', files[0]);
                fetch('http://MY_UPLOAD_SERVER.COM/api/upload', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    },
                    body: formData
                }).then(res => {
                    const respJson = res.json();
                    // console.log("File uploaded", respJson);
                    // TODO: Update ui and states....
                    // setUploads(respJson.url);
                    return respJson;
                }).catch(err => {
                    console.log("File upload error", err);
                    // TODO: Update ui and states with error....
                });

            }}
            onReject={(files) => console.log('rejected files', files)}
            accept={IMAGE_MIME_TYPE}
        >
            {(status) => dropzoneChildren(status, theme)}
        </Dropzone>
    );
}

const dropzoneChildren = (status: DropzoneStatus, theme: MantineTheme) => (
    <Group position="center" spacing="xl" style={{ minHeight: 220, pointerEvents: 'none' }}>
        <ImageUploadIcon status={status} style={{ color: getIconColor(status, theme) }} size={80} />

        <div>
            <Text size="xl" inline>
                Drag images here or click to select files
            </Text>
            <Text size="sm" color="dimmed" inline mt={7}>
                Attach as many files as you like, each file should not exceed 5mb
            </Text>
        </div>
    </Group>
);
0
On

Just spent hours banging my head on this one. There's actually an issue with the underlying react dropzone implementation, it doesn't allow for normal use of the underlying <input type="file">.

The onDrop prevents the normal updating of the input's value. This results in a 0 byte file being sent in the request. You can also tell because the name will be ''.

The solution I came up with to allow for normal form usage (I'm using Remix):

const fileInput = useRef<HTMLInputElement>(null);
const _onDrop = (files: FileWithPath[]) => {
  if (!fileInput.current) {
    throw new Error("Dropzone input ref is not set yet")
  }
  const dataTransfer = new DataTransfer();
  files.forEach(f => dataTransfer.items.add(f));
  fileInput.current.files = dataTransfer.files;
  // Call an *additional* onDrop if you want
  if (onDrop) {
    onDrop(files);
  }
}
...
return (
  ...
  <input type="file" hidden ref={fileInput} name={name}/>
  <Dropzone onDrop={_onDrop} ... other props ...>
...

I'll try and get to a PR but hopefully this helps anyone else who's struggling.