Polaris-react: DropZone allowMultiple disables selecting another image

Created on 17 Jul 2019  路  9Comments  路  Source: Shopify/polaris-react

Issue summary

When a DropZone component has the allowMultiple set to false it disables the ability to click on the DropZone.FileUpload "Add file" button after one file is selected in the file dialog.

Expected behavior

I expected that the allowMultiple prop simply disallows multiple files to be selected at once from the file dialog, but the DropZone can be interacted with to select a new file after one has already been chosen. Basically just ensuring that the onDrop function will only ever get one file at a time. This may be working as originally intended, though I think it's a useful use case to limit the file dialog to one file, but allow multiple interactions with the same component. Our use case is selecting a single image, but allowing the user to change the image after they made an initial selection.

Actual behavior

When the allowMultiple prop is false, the DropZone.FileUpload can no longer be interacted with. A workaround is to set a new key on the DropZone after each interaction, which will re-render the component and reset that internal state.

Steps to reproduce the problem

  1. Create a DropZone component with allowMultiple set to false that has a DropZone.FileUpload component as a child.
  2. Click on the "Add file" button and select a file in the dialog.
  3. Try clicking the "Add file" button again and the file dialog won't come back up.

Reduced test case

The following Code Sandbox reproduces the issue: https://codesandbox.io/s/vigorous-chatelet-8k7q4. It's originally based on the example from the Polaris documentation.

Specifications

  • Are you using the React components? (Y/N): Y
  • Polaris version number: 3.20.0
  • Browser: Google Chrome 75.0.3770.142
  • Device: Macbook Pro
  • Operating System: macOS Mojave 10.14.5
鈿楋笍 Development 馃悰Bug

Most helpful comment

@Tzelon A relatively crude workaround is to generate a new key prop whenever the onDrop function is called. This causes the DropZone component to be rebuilt by React and resets all of the internal state. You could do something like keeping track of the total number of upload attempts in your component's state and increment that state variable every time onDrop is called and then use that state variable as the key. Something like this (though it doesn't have to be Hooks-based):

const [uploadCount, setUploadCount] = useState(0);
const onFileDrop = (files, acceptedFiles, rejectedFiles) => {
    setUploadCount(prevCount => prevCount + 1);
    // handle your file uploads here
};
return (
    <DropZone
        key={uploadCount}
        onDrop={onFileDrop}
        allowMultiple={false}>
        <DropZone.FileUpload />
    </DropZone>
);

All 9 comments

If this is all working as designed and preferred and the best way to accomplish this is to continue using the key prop change approach, feel free to close this. It seems like if a user of this component wants to stop an interaction with a drop zone after a file has been chosen, that can easily be handled by the consumer of the component by disabling or unmounting it entirely. However, there appears to be no other way to accomplish the case of re-using the single DropZone to only allow picking one file and then changing the selected file. Perhaps our use case is weird though. :)

Thanks @mbaumbach. I agree with you that it should allow you to replace the selected file so I'll file it as a bug for now and investigate before closing. I vaguely remember this coming up before.

I see how this was purposely done, but it is unexpected, from a UX perspective, to still have the button and not be able to replace the selected file.

In connection with issue #1229

@mbaumbach How did you solve this?

@Tzelon A relatively crude workaround is to generate a new key prop whenever the onDrop function is called. This causes the DropZone component to be rebuilt by React and resets all of the internal state. You could do something like keeping track of the total number of upload attempts in your component's state and increment that state variable every time onDrop is called and then use that state variable as the key. Something like this (though it doesn't have to be Hooks-based):

const [uploadCount, setUploadCount] = useState(0);
const onFileDrop = (files, acceptedFiles, rejectedFiles) => {
    setUploadCount(prevCount => prevCount + 1);
    // handle your file uploads here
};
return (
    <DropZone
        key={uploadCount}
        onDrop={onFileDrop}
        allowMultiple={false}>
        <DropZone.FileUpload />
    </DropZone>
);

@Tzelon A relatively crude workaround is to generate a new key prop whenever the onDrop function is called. This causes the DropZone component to be rebuilt by React and resets all of the internal state. You could do something like keeping track of the total number of upload attempts in your components state and increment that state variable every time onDrop is called and then use that state variable as the key. Something like this (though it doesn't have to be Hooks-based):

const [uploadCount, setUploadCount] = useState(0);
const onFileDrop = (files, acceptedFiles, rejectedFiles) => {
    setUploadCount(prevCount => prevCount + 1);
    // handle your file uploads here
};
return (
    <DropZone
        key={uploadCount}
        onDrop={onFileDrop}
        allowMultiple={false}>
        <DropZone.FileUpload />
    </DropZone>
);

This is perfect! Thank you so much.

Taking on this issue...

Thanks @devonpmack! I confirmed this is fixed in 4.15.1, no more key hacks required. 馃憤

Was this page helpful?
0 / 5 - 0 ratings