user1641172
user1641172

Reputation:

Add item to array on ReactJs state with timeout for self removal

I have a created a MessageList component for displaying return messages from the server, I want these messages to only exist in the state for around 5 seconds or so, I have it all working as I want for adding and displaying, but I cant think for the life of me how to timeout the removal of a specific item from its parent array.. a Vanilla JS answer will do for timeout removal of self from array.

var MainApp = React.createClass({
     AddComment: function() {
        //do some stuff 
        this.showMessage({
            alerttype: "success", 
            title: "Success!", 
            message: "Comment saved to the database."})
        }
    },
    showMessage: function(message) {
        //how to I push this message onto messages for 5 seconds?
    },
    getInitialState: function() {
        return {messages: []};
    },
    render: function () {
        return (
            <div className="mainApp">
                <CommentForm messages={this.state.messages} />
            </div>
        );
    }
});

Upvotes: 1

Views: 1803

Answers (3)

James Brierley
James Brierley

Reputation: 4670

All you need to do is wrap the removal in a setTimeout. Something like the below:

showMessage: function(message) {
    this.setState({
        messages: this.state.messages.concat([message])
    });

    setTimeout(() => this.setState({
        messages: this.state.messages.filter(m => m !== message)
    }), 5000);
},

Upvotes: 0

Calvin Belden
Calvin Belden

Reputation: 3114

Let's try to abstract this from your view logic. We can make a data type that's responsible for storing timestamped messages. We can also add some helper functions to remove old items and to retrieve the current list of items. Then all you need to do is occasionally purge any old items:

function ExpiringMessages(expirationTime) {
    this.messages = [];
}

ExpiringMessages.prototype.add = function (data) {
    this.messages.push({ timestamp: Date.now(), data });
}

ExpiringMessages.prototype.removeOlderThan = function (delta) {
    this.messages = this.messages.filter(m => (Date.now() -  m.time) - delta > 0);
}

ExpiringMessages.prototype.current = function () {
    return this.messages.map(m => m.data);
}

This basically just stores a list of timestamped data that allows you to purge any items whenever you want. Within your component, you would set an interval (maybe every second or so) that would remove items that are older than 5 seconds. Each time you do this, you would reset the current list of messages to be messages.current().

Upvotes: 1

wintvelt
wintvelt

Reputation: 14101

One way to do this is use timestamps on messages and add a separate cleanup method on a 5 second timeout:

  • inside showMessage(), update your state with the new message, and add a timestamp to the new message.
  • add a componentDidUpdate() lifecycle method, which calls a cleanMessages() method, and fires a 5 second timeout to call the cleanMessages() method` again.
  • inside the cleanMessages() method, check if any of the messages in the list is > 5 seconds old (by comparing current time to timestamp in each message), remove found old messages, and only if there are messages removed, do a setState() with the updated messages list.

By the way, it looks like the line }.bind(this); in your code breaks the code and should be removed.

Upvotes: 0

Related Questions