在 ReactJs 状态下将项目添加到数组,并超时以进行自我删除

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

我创建了一个 MessageList 组件,用于显示来自服务器的 return 消息,我希望这些消息只在该状态下存在大约 5 秒左右,我可以按我想要的方式运行添加和显示,但我终生无法思考如何超时从其父数组中删除特定项目。Vanilla JS 答案将超时从数组中删除自身。

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>
        );
    }
});

一种方法是在消息上使用时间戳并在 5 秒超时时添加单独的清理方法:

  • showMessage() 中,使用新消息更新您的状态,并向新消息添加时间戳。
  • 添加一个 componentDidUpdate() 生命周期方法,它调用一个 cleanMessages() 方法,并触发 5 秒超时以再次调用 cleanMessages() 方法。
  • cleanMessages() 方法中,检查列表中的任何消息是否超过 5 秒(通过将当前时间与每条消息中的时间戳进行比较),删除找到的旧消息,并且 仅当删除了消息时,使用更新后的消息列表执行setState()

顺便说一下,您的代码中的 }.bind(this); 行似乎破坏了代码,应该将其删除。

让我们尝试从您的视图逻辑中对此进行抽象。我们可以创建一个数据类型来负责存储带时间戳的消息。我们还可以添加一些辅助函数来删除旧项目并检索当前项目列表。然后你需要做的就是偶尔清除任何旧项目:

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);
}

这基本上只是存储了一个带时间戳的数据列表,允许您随时清除任何项目。在您的组件中,您可以设置一个时间间隔(可能每隔一秒左右)来删除超过 5 秒的项目。每次执行此操作时,您都会将当前消息列表重置为 messages.current().

您需要做的就是将删除包装在 setTimeout 中。类似下面的内容:

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

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