React / TypeError: files.map is not a function

I am trying to upload some files via <input type="file"> to the state, in order to pass it back to the main component. With the code below I get the Uncaught TypeError: Cannot read property 'setState' of undefined when trying to update the state with the uploaded files.

import React, { Component } from 'react'
import * as RB from 'react-bootstrap'

import Button from 'components/Button/Button'

class uploadMob extends Component {
    constructor(props) {
        super(props)
        this.state = {
            files: [],
        }
    }

    onFilesAdded(files) {
        this.setState((prevState) => ({
            files: prevState.files.concat(files),
        }))
        this.handleUpload()
    }

    handleUpload = (e) => {
        const { pdfUploadToState } = this.props

        debugger
        pdfUploadToState(this.state.files)
        console.log('PUSHED FILE', this.state.files)
    }

    render() {
        const files = this.state.files
        return (
            <RB.Form.Group>
                <div className="upload-btn-wrapper">
                    <div className="Files">
                        {files.map((file, key) => {
                            return (
                                <div key={key} className="Row">
                                    <span className="Filename">
                                        {file.value}
                                    </span>
                                </div>
                            )
                        })}
                    </div>
                    <Button size="sm" variant="light">
                        Dateien hochladen
                    </Button>

                    <input
                        type="file"
                        name="file"
                        id="files"
                        onChange={this.onFilesAdded}
                    />
                </div>
            </RB.Form.Group>
        )
    }
}

export default uploadMob

I would very much appreciate the help with this. It is driving me a bit crazy..

Upvotes: 0

Views: 4333

Answers (2)

Olivier Boiss&#233;
Olivier Boiss&#233;

Reputation: 18083

You need to use an arrow function to have the correct value of this.

setState is asynchronous so you need to pass the this.handleUpload function as a callback in order to updload the files once setState is completed.

From the documentation :

The second parameter to setState() is an optional callback function that will be executed once setState is completed and the component is re-rendered. Generally we recommend using componentDidUpdate() for such logic instead.

onFilesAdded = files => {
    this.setState(prevState => ({
        files: [...prevState.files, ...files]
    }), this.handleUpdload)
}

Upvotes: 0

technophyle
technophyle

Reputation: 9118

The problem is with this line:

onFilesAdded(files) {

You need to either bind() it to this like this:

constructor(props) {
    super(props)
    this.state = {
        files: [],
    };

    this.onFilesAdded = this.onFilesAdded.bind(this);
}

or convert it to an arrow function:

onFilesAdded = files => {

The problem is this referred inside onFilesAdded does not point the component instance by default. By using the two methods above, we make sure that by calling this., the component is correctly referred.

Upvotes: 2

Related Questions