0

I'm working on a workaround for another problem I'm having but with this I got a "this.setState is not a function" error. I found this answer which advises to bind it within the constructor, which I did.

This is part of my constructor:

this.newProject = this.newProject.bind(this);
this.openProject = this.openProject.bind(this);
this.saveProject = this.saveProject.bind(this);

And this is my function:

// Open a file, set data as session item and reload page
openProject(FileObject) {
    var read = new FileReader();
    read.readAsBinaryString(FileObject);
    read.onloadend = function() {
        //sessionStorage.setItem("reloading", "true");
        //sessionStorage.setItem("data", read.result);
        //document.location.reload();

        // Fix for missing data.
        var jsonData = JSON.parse(read.result);
        for (var i = 0; i < jsonData.blocks.length; i++) {
            var name = jsonData.blocks[i].name;
            var id = jsonData.blocks[i].id;
            var ip = jsonData.blocks[i].ip;
            var port = jsonData.blocks[i].port;
            this.setState( { blockCount: (i + 1), });

            // Add block to the list
            this.setState({
                blocks: this.state.blocks.concat({
                    id: id,
                    name: name,
                    ref: React.createRef(),
                    positionX: window.innerWidth*0.4  - 125 / 2,
                    positionY: 75 + ( 50 * this.state.blocks.length),
                    links:[],
                    requires: this.state.parameters.blockRequires
                })
            });
        }
    }
}

What would be a solution to this?

Ivaldir
  • 185
  • 12

2 Answers2

1

this belongs to the closest function context, which in your case is read.onloadend = function()...NOT the class.

You can solve this problem by assigning the class-level this to a new variable before you enter that ad-hoc function:

openProject(FileObject) {
    var read = new FileReader();
    read.readAsBinaryString(FileObject);
    var that = this;
    read.onloadend = function() {
        // ...
        that.setState(/*... etc*/

And of course you'll want to change all instances of this within your onloadend callback function to that (or whatever variable name you choose).

*Edit: as @MDTabishMahfuz describes, you can also use an arrow function, because unlike the function declaration, an arrow function:

Does not have its own bindings to this or super

David784
  • 7,031
  • 2
  • 22
  • 29
1

Binding this is necessary for functions of the class but you have an additional callback (onloadend function) which is a different function and the component's this is not available there.

Conventional Functions in JS have their on this in their context. You can either use the method suggested by @David784 or use an arrow function for the onloadend handler like so:

read.onloadend = () => {
    ....
    this.setState(....);
    ....
}

Arrow functions have this from the parent's context, that is the React component in your case.