简体   繁体   中英

React Warning, setState(…) in ComponentDidMount

I get this warning with the setState in the functin below, can anone tell me how I need to structure my code to get rid of it?

warning.js:46 Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the FileInput component.

    componentDidMount: function () {
    var self = this;
    this.initUploader();

    this.uploader.init();

    EVENTS.forEach(function (event) {
        var handler = self.props['on' + event];
        if (typeof handler === 'function') {
            self.uploader.bind(event, handler);
        }
    });


   this.uploader.bind('FileUploaded', function (up, file, res) {
        var objResponse = JSON.parse(res.response);
        console.log(objResponse.reference);
        self.props.getFileRef(objResponse.reference);


        var stateFiles = self.state.files;
        _.map(stateFiles, function (val, key) {
            if (val.id === file.id) {
                val.uploaded = true;
                stateFiles[key] = val;
            }
        });
        // setState causing warning
        self.setState({ files: stateFiles }, function () {
            self.removeFile(file.id);
        });
    });

The FileUploaded event handler is invoking setState using a closure self reference. This causes leaks where the component has been unmounted and then the FileUploaded event triggers and setState is invoked on an unmounted component. You can read more about this in this article which is somewhat related - https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html .

Now how to fix this depends on if your uploader object allows for unbinding the event handler. If it allows, then you can do this -

  1. Define the FileUploaded handler code as a named function (instead of anonymous). You need to do this to be able to unbind it later.
  2. Change the code in componentDidMount to bind the named function as the FileUploaded event handler.
  3. Add a componentWillUnmount event handler to your component and call the unbind mechanism of uploader , passing it the named handler reference.

This way, when the component gets unmounted, the corresponding handler will also be removed and this warning will no longer be reported.

PS: You should remove (unbind) all handlers you are registering in your code above, otherwise you will be leaking references all over the place and more importantly, will be left with a whole bulk of orphaned event handlers.

==UPDATE==

Per your Fiddle, you can -

  1. Declare these new methods in your component -

     registerHandler: function(uploader, event, handler){ this.handlers = this.handlers || []; this.handlers.push({e: event, h: handler}); uploader.bind(event, handler); }, unregisterAllHandlers : function(uploader){ for (var i = 0; i < this.handlers.length; i++){ var handler = this.handlers[i], e = handler.e, h = handler.h; // REPLACE with the actual event unbinding method // of uploader. uploader.unbind(e, h); delete this.handlers[i]; } }, componentWillUnmount: function(){ this.unregisterAllHandlers(this.uploader); } 
  2. Use registerHandler in all the places where you are invoking uploader.bind -

    self.registerHandler(self.uploader, event, handler);

    OR

    this.registerHandler(this.uploader,'FilesAdded', function (up, files) { if (_.get(self.props, 'multi_selection') === false) {...});

This is a very crude implementation, basically we are storing all event handler references in an array and then during unmount, removing them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM