Redux-form: Example Request: File inputs

Created on 19 Oct 2016  路  21Comments  路  Source: redux-form/redux-form

it's really hard to google for examples of this working with the v6 api...

Are there any examples out there, can we make some official ones on the docs page?

docs help wanted

Most helpful comment

This is what I ended up doing, which keeps it nice and simple:

const adaptFileEventToValue = delegate =>
  e => delegate(e.target.files[0])

const FileInput = ({
  input: {
    value: omitValue,
    onChange,
    onBlur,
    ...inputProps,
  },
  meta: omitMeta,
  ...props,
}) =>
  <input
    onChange={adaptFileEventToValue(onChange)}
    onBlur={adaptFileEventToValue(onBlur)}
    type="file"
    {...inputProps}
    {...props}
  />

And then use FileInput as the component in a Field:

      <Field
        component={FileInput}
        name="videoFile"
      />

Redux Form is pretty impressively composable.

All 21 comments

We ended up using react-dropzone. Just put a hidden <Field ... /> with your field name and then in your dropzone component in the onDrop prop just dispatch to that field. You may need to use the HTML5 FileReaderto handle the file.

Example image upload:
`

<Field name="file" component='input' type="hidden" />

<Dropzone
    ref="dropzone"
    onDrop={(upload) => dispatch(change('FileUploadExampleForm', 'file', upload[0]))}
    multiple={false}
    accept='image/*'>
    <div>Click here select files to upload.</div>
</Dropzone>

`

@dmason30 seems like a pretty great example! I still think it might be worth adding some notes about working with file inputs to the documentation, even if it is a suggestion to "work with an external plugin for file uploads"

@dmason30 ... I second @gnarf

It would be good to have an explanation of how to do this without using dropzones. Often I just want the standard file upload behavior.

i made a FileField demo using [react-dropzone]

/**
 * file field that supported dnd
 */
export default class FileField extends React.Component {

  handleDropOrClick = (acceptedFiles, rejectedFiles, e) => {
    let eventOrValue = e;
    let {input: {onChange, onBlur}} = this.props;
    if (e.type === 'drop') {
      if (acceptedFiles.length) {
        // FileList or [File]
        eventOrValue = (e.dataTransfer && e.dataTransfer.files) || acceptedFiles;
      } else {
        eventOrValue = null;
      }
    }
    onBlur(eventOrValue); // update touched
    onChange(eventOrValue); // update value
  }


  render() {
    let {input, meta: {touched, error}} = this.props;
    let {accept, multiple} = this.props;
    let selectedFile = (input && input.value && input.value[0]) || null;
    let dropzoneProps = {
      accept,
      multiple
      onDrop: this.handleDropOrClick,
    };
    return (
      <div>
        <input type='hidden' disabled {...input} />
        {selectedFile? <span>{selectedFile.name}</span> : null}
        <Dropzone {...dropzoneProps} />  
      </div>
      );
  }
}




// use 
<Field component={ FileField } name='uploadfile' accept='application/vnd.ms-excel'
/>

@houfeng0923 when reaching onBlur(eventOrValue); it shows error. and after checkup, when calling handleDropOrClick there is no input passed to props... what could possibly be wrong?

@gnarf @morgante Any doc, example of implementing this without dropzones

Hello,

I have the same request @yokodev, I would like to avoid using dropzone and I would love to see an example of a file upload with redux form :) Any help @erikras ? :)

This is what I ended up doing, which keeps it nice and simple:

const adaptFileEventToValue = delegate =>
  e => delegate(e.target.files[0])

const FileInput = ({
  input: {
    value: omitValue,
    onChange,
    onBlur,
    ...inputProps,
  },
  meta: omitMeta,
  ...props,
}) =>
  <input
    onChange={adaptFileEventToValue(onChange)}
    onBlur={adaptFileEventToValue(onBlur)}
    type="file"
    {...inputProps}
    {...props}
  />

And then use FileInput as the component in a Field:

      <Field
        component={FileInput}
        name="videoFile"
      />

Redux Form is pretty impressively composable.

@damonmaria, @houfeng0923, @dmason30 - Thanks for the examples but how do you reference the file that has been selected? I can't see any reference to it in the store.

I am using redux-form/immutable in case that makes a difference..

@bristoljon With what I posted above you should have a File (details here) object assigned to the appropriate property in the fields provided to onSubmit. From my example above it would be:

reduxForm({
    form: 'my-form',
    onSubmit: ({ videoFile }) => {
      ...do something with videoFile here...
    },
})(...)

At the moment I use the AWS SDK to upload it to S3 at that point. The SDK accepts a File object.

@damonmaria Ah yeah, cool. Sorry I'm a Redux-form newb! Cheers for the quick reply

@damonmaria Not working for me :-( When I click the input, it doesn't do anything.

This method worked for me:

  1. Create a field component and remove input.value ( ref: https://redux-form.com/5.2.5/#/examples/file?_k=57hmlw )
export const field_file = ({ input, type, meta: { touched, error, warning } }) => {
  delete input.value

  return (
    <div>
      <label htmlFor={input.name}>
        Choose File from your Computer
        <input {...input} type={type}/>
      </label>
    </div>
  )
}
  1. Use it like so
<form onSubmit={postFile}>
  <Field name="file" type="file" component={field_file} />
</form>

The file will be stored in the form object just like any other normal input.

  1. Send it via async POST.
const postFile = (data) => {
  let formData = new FormData()
  formData.append('File', data.file[0])

  return axios.post('http://test.url', formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
    .then(res => res.data)
}

Here's a compilation of solutions from this issue and #71 :
https://gist.github.com/barraponto/c370c17b2499c36a625fe1326c57ab21

I "solved" it by not including the file input in redux form. I realized it was actually not necessary to keep it there.

@AndreiBru Thanks, I'm using your approach and so far it seems the simplest way to implement a non dropzone file upload.

@barraponto this actually appears to work properly, thanks. Now I need to figure out why it works where others didn't.

@damonmaria This worked for me, but curious as to why you took out the field.input.value prop?

@brycelarkin Sorry. That was a while ago so I'm not sure. Must have been a reason. Is it possible to specify value to a file input as a string?

I also faced the same problem of file input
just tried : value={null}

<input {...this.props} type={type} accept="image/*" value={null} />

Was this page helpful?
0 / 5 - 0 ratings