uploadcare / react-widget

Uploadcare React Widget
MIT License
85 stars 18 forks source link

Remove file from widget after upload. #254

Open stevesizer opened 3 years ago

stevesizer commented 3 years ago

I'm using the widget api to open the dialog and then on file change creating my object to save to the database. After I have uploaded the image I am trying to remove it from widget using the getInput function.

This is not removing the image. So when I go to reopen the widget the last image uploaded is in preview mode. ANy help would be appreciated. Here is my code below.

const fileChange = (fileInfo) => { let newAttachment = { name: fileInfo.name, file_type: fileInfo.mimeType, size: fileInfo.size, attachment_url: fileInfo.cdnUrl, };

let newMessage = { ...props.message };
newMessage.attachments_attributes.push(newAttachment);
props.updateAttachment(newMessage);
props.postMessage(conversation.id);
let fileInput = widgetApi.current.getInput();
fileInput.value = null;

};

nd0ut commented 3 years ago

Hey @stevesizer You need to use value prop to reset the widget value. Here is the example sandbox - https://codesandbox.io/s/laughing-golick-f95t2?file=/src/App.js:0-523

const [value, setValue] = useState();

const onChange = (fileInfo) => {
  setValue(null);
};

<Widget
  value={value}
  publicKey="demopublickey"
  onChange={onChange}
/>
Mosquid commented 3 years ago

I can't make this work:

  1. Value property type is string while onChange handler receives FileInfo
  2. Setting FileInfo as value is causing Incorrect value error
stevesizer commented 3 years ago

you need to use separate state for you value of the widget to make it work.

Mosquid commented 3 years ago

@stevesizer thanks for you quick response. Here's how I made it work:

const [value, setValue] = useState<FileInfo>();

const resetValue = () => {
  setValue();
};

...

{value && <img className="preview" src={value.cdnUrl} />}
<Widget
  value={value?.uuid ?? ""}
  onChange={setValue}
  ref={widgetRef}
  publicKey={UPLOADCARE_KEY}
/>
stevesizer commented 3 years ago

It might be best to have some state for the image.

const [value, setValue] = useState();
const [imageUrl, setImageUrl] = useState(null);

const onChange = (fileInfo) => {
  setImageUrl(fileInfo.cdnUrl);
  setValue(null);
};

{imageUrl && <img className="preview" src={imageUrl} />}

<Widget
  value={value}
  publicKey="demopublickey"
  onChange={onChange}
/>
line1 commented 2 years ago

@nd0ut Not sure if you'd prefer to resurrect an old question or open a new one, but I'm working on the same use case and notice that the example you provided (https://codesandbox.io/s/laughing-golick-f95t2?file=/src/App.js:0-523) only works once. The first upload is cleared, but after a second file is uploaded, the state persists.

This matches the behavior I'm seeing with my own project. How can we guarantee that the value is properly cleared out on every upload, instead of just the first?

line1 commented 2 years ago

Apologies for the unnecessary update to an old question - the issue was with value never getting set to a non-null value. Updating that state when the upload starts, then flipping back to null when done, was all it took to resolve this.

barbalex commented 2 years ago

I have been using a self built widget for some years now. Seing this react widget I wanted to switch. Took me 10 minutes to rebuild.

Now I have been debugging this issue for a full hour. From the docs I have NO idea what the value is for. Nor how manipulating it would influence the behaviour.

All I want is that the button saying "Choose a file" never changes. Which seems the logical behaviour for a button.

But instead I get first this button:

1

(Below the button is a list. At the left it would show an image preview for image files)

And after clicking it and choosing a file this weirdo:

2

Why should the button suddenly mutate to a link and some information? For the life of me I can't figure out why this would make any sense.

I have tried introducing state and mutating it as mentioned above. Though it is above me to understand why this state should be necessary for a simple button. It did not work.

I have then tried to monkeypatch this widget by giving it an id and changing that on change to force re-initiating this widget. Not even that solved the issue!?

How can I achieve that the button stays a button?

I get the impression that this widget wants to achieve something very opinionated that is not explained. It would be much better to have it much more simple - just a button to add files.

wub commented 1 year ago

@barbalex I struggled with that for a while as well. I think it's because the Widget itself wants to "own" the list of files inside it, whereas it would be very useful to have a more React-y component that allowed us to control it from top to bottom.

nd0ut commented 1 year ago

Hey guys, I agree that the value prop has a pretty strange behavior. It doesn't work as expected with controlled components, since it only calls widget.value() internally on changes. To empty the file list, you should pass an empty array instead of null. This is missing in the docs.

Therefore, I want to rename the value prop to defaultValue and ignore it after mounting. And to update the internal file list state, an imperative API should be used.

freejosh commented 1 year ago

I was able to clear the selected file more than once by randomizing the key prop to force React to re-mount the component:

const [key, setKey] = useState(0);
function onChange() {
  setKey(Math.random());
}
<Widget key={key} onChange={onChange} />