2

I am new to React so I may not understand the correct concept of thinking.

I want to do auto update data component that can me mounted and unmounted.

This is a error that I get when I unmounted and then mounted component:

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 MeasurementsDataTable component.

and here is the code:

var getDataInretval;
var listenersService = new ListenersService();
var Data = [{}];

function ListenersService(){
    var listeners = {};
    this.addListener = function(callback){
        var id;
        if(typeof callback === 'function'){
            id = Math.random().toString(36).slice(2);
            listeners[id] = callback;
        }
        return id;
    }
    this.removeListener = function( id){
        if(listeners[id]){
            delete listeners[id];
            return true;
        }
        return false;
    }
    this.notifyListeners = function(data){
        for (var id in listeners) {
            if(listeners.hasOwnProperty(id)){
                listeners[id](data);
            }
        }
    }
}


var dataSevice = new DataMeasurementService(ListenersService);

function DataMeasurementService(ListenersService){

    Data.push( new MeasurementDataForTable("header1", "th", "Phase measurements", "L1", "L2", "L3", "Total", "Others") );
    var self = this;

    //var listenersService = new ListenersService();
    this.addListener = listenersService.addListener;
    this.removeListener = listenersService.removeListener;
    this.getData = function(){
        return Data;
    }

    $.ajax({
        url: "BL/getMeasurementsData.php",
        type: "GET",
        dataType: "html",
        async: false,
        success: function(res) {
            var parseData = parseMeasurementsData( res );
            Data = createOriginData( parseData );
        },
        error: function(request, status, error) {
            alert("error: " + request.responseText);
        }
    });
    listenersService.notifyListeners(Data);
}

var ThElement = React.createClass({
   render: function(){
       return <th  width={this.props.width}>{this.props.data}</th>;
   }
});

var TdElement = React.createClass({
    render: function(){
        return <td>{this.props.data}</td>;
    }
});

var MeasurementsDataTable = React.createClass({
    getInitialState: function() {
        return {
            data: this.props.dataService.getData()
        };
    },
    componentDidMount: function() {
        getDataInretval = setInterval(function(){
            $.ajax({
                url: "BL/getMeasurementsData.php",
                type: "GET",
                dataType: "html",
                async: false,
                success: function(res) {
                    var parseData = parseMeasurementsData( res );
                    Data = createOriginData( parseData );
                },
                error: function(request, status, error) {
                    alert("error: " + request.responseText);
                }
            });

            listenersService.notifyListeners(Data);
        }, 1000);


    },
    componentWillMount: function () {
        this.props.dataService.addListener(this.updateHandler);
    },
    componentWillUnmount: function () {
        this.removeListener = listenersService.removeListener;
        clearInterval(getDataInretval);
    },
    updateHandler: function(data) {
        this.setState({
            data: data
        });
    },
    render: function() {
        return (
            <div>
                <table>
                    {
                        this.state.data.map(function(item) {
                                if( item.element == "th" ){
                                    return (
                                        <thead><tr>
                                            <ThElement width="280" data={item.description}/>
                                            <ThElement width="150" data={item.L1}/>
                                            <ThElement width="150" data={item.L2}/>
                                            <ThElement width="150" data={item.L3}/>
                                            <ThElement width="150" data={item.total}/>
                                            <ThElement width="150" data={item.others}/>
                                        </tr></thead>
                                    )
                                }
                                else{
                                        return (
                                            <tr>
                                                <TdElement data={item.description}/>
                                                <TdElement data={item.L1}/>
                                                <TdElement data={item.L2}/>
                                                <TdElement data={item.L3}/>
                                                <TdElement data={item.total}/>
                                                <TdElement data={item.others}/>
                                            </tr>
                                        )
                                    }
                        })
                    }
               </table>
            </div>
        );
    }
});
ReactDOM.render( <MeasurementsDataTable dataService={dataSevice} />, document.getElementById("tablePlaceHolder") );
Jan
  • 167
  • 2
  • 5
  • 16

3 Answers3

1

I believe the problem is in your componentWillMount.

Before the component is mounted you do the following

Add a listener in componentWillMount

componentWillMount: function () {
    this.props.dataService.addListener(this.updateHandler);
},

Which means you run this function

DataMeasurementService(ListenersService)

At the very end of executing that function you run

listenersService.notifyListeners(Data);

Which in turn run whatever listeners you have added, including the just added this.updateHandler, that looks like this

updateHandler: function(data) {
    this.setState({
        data: data
    });
},

And will setState().

This all happens before the component mounts, since it all happens in componentWillMount, Will being the keyword here. In other words, exactly what the error message says.

This usually means you called setState() on an unmounted component.

You should add anything that could possibly change the state of the component in componentDidMount, which happens after the component has mounted, to make sure it doesn't get stuck in a loop or tries to update an unmounted component.

Remember, it's perfectly fine to render the component twice. The first time around, you mount it and render something like Loading.... Then in componentDidMount, you do whatever api fetching, add event listeners and other things that needs to be done. Finally you update (setState()) the component with it's actual content.

Magnus Engdal
  • 5,446
  • 3
  • 31
  • 50
1

You have to make sure that your component isn't still listening to an attached event-listener and trying to update itself after being unmounted.

You need to keep track of ALL event listeners while using React. If data from event listeners cause your component to update, you must attach the listener to the Lifecycle method componentWillMount() and detach all your listeners in componentWillUnmount().

Listeners can be anything which your component listens to and changes itself by setState() method. It can be data from socket, data from server, on window resize event, setInterval listener etc.

Naisheel Verdhan
  • 4,905
  • 22
  • 34
  • I add ID to listener and then remove it in 'componentWillMount'. It works. Thank you. – Jan Dec 18 '15 at 06:39
0

Actually you are setting interval in componentDidMount which is going on behind the scene and trying to set state of your component which get unmounted.

So Just check Is your interval getting cleared successfully or not? And one thing more in your componentWillUnmount try to remove all listeners with specific id or clear all ,

Now you are not clearing you are not passing any id So I think issue is with listeners.

Bhuvnesh
  • 44
  • 5