13

Using react-dropzone (https://www.npmjs.com/package/react-dropzone) and getting files logging to the console, but can't get image preview to populate on state change. Any idea what I'm doing wrong?

export default class JoinForm extends Component {
    constructor(props) {
    super(props)
        this.state = {
            imageFiles: []
    }
}

onDrop(imageFiles) {
    this.setState({
        imageFiles: imageFiles
    })
    console.log(imageFiles)  
}

render() {

    return(
        <form className='join-form' ref='joinForm' autoComplete='off'>
            <Dropzone
                onDrop={this.onDrop}
                className='dropzone'
                activeClassName='active-dropzone'
                multiple={false}>
      <div>Drag and drop or click to select a 550x550px file to upload.</div>
    </Dropzone>

            {this.state.imageFiles.length > 0 ? <div>
    <h2>Uploading {this.state.imageFiles.length} files...</h2>
    <div>{this.state.imageFiles.map((file) => <img src={file.preview} /> )}</div>
    </div> : null}
        </form>
    )
}

};

megkadams
  • 717
  • 1
  • 10
  • 19

3 Answers3

14

Correct answer to this: being a dummy and forgot to bind this.

<Dropzone
  onDrop={this.onDrop.bind(this)} //<= Here
  className='dropzone'
  activeClassName='active-dropzone'
  multiple={false}
  style={imageUploadStyle}>
    <div>Drag and drop or click to select a 550x550px file to upload.</div>
</Dropzone>

https://toddmotto.com/react-create-class-versus-component/

megkadams
  • 717
  • 1
  • 10
  • 19
  • 3
    JSX props should not use .bind(). Bind in constructor. – igo Aug 02 '17 at 07:20
  • 3
    Never bind a function directly in Dropzone onDrop call. The drawback here is every time you upload an image or when ever your component renders/re-renders a new function will be created in webpack bundle.js and thus your bundle.js file size will be increased. So instead of doing that do binding in constructor always and then call that reference wherever required. This only creates a new function when components loads for the first time. – Hemadri Dasari Jan 13 '18 at 04:13
8

You are storing files in imageFiles, but in render method you are mapping over this.state.files array.

Change:

<div>{this.state.files.map((file) => <img src={file.preview} /> )}</div>

To:

<div>{this.state.imageFiles.map((file) => <img src={file.preview} /> )}</div>

Or, because you have this constant const files = this.state.imageFiles, you can change mentioned statement to:

<div>{files.map((file) => <img src={file.preview} /> )}</div>
Alexandr Lazarev
  • 12,554
  • 4
  • 38
  • 47
  • Definite late-breaking typo and good catch - but not the issue, unfortunately... {this.state.imageFiles.length > 0 ?

    Uploading {this.state.imageFiles.length} this.state.imageFiles...

    {this.state.imageFiles.map((file) => )}
    : null} still doesn't update. Am I setting state incorrectly somehow?
    – megkadams Jul 13 '16 at 18:56
  • 1
    Update your post please, it's hard to read code from the comment. – Alexandr Lazarev Jul 13 '16 at 19:14
  • Posted correct answer below ~ Thanks for the help, LA! – megkadams Jul 13 '16 at 19:58
1

Change your render function to imageFiles

render() {
    const files = this.state.imageFiles

    return(
        <form className='join-form' ref='joinForm' autoComplete='off'>
            <Dropzone
                onDrop={this.onDrop}
                className='dropzone'
                activeClassName='active-dropzone'
                multiple={false}>
      <div>Drag and drop or click to select a 550x550px file to upload.</div>
    </Dropzone>

            {this.state.imageFiles.length > 0 ? <div>
    <h2>Uploading {this.state.imageFiles.length} files...</h2>
    <div>{this.state.imageFiles.map((file) => <img src={file.preview} /> )}</div>
    </div> : null}
        </form>
    )
Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21