javascript - 调用 setState() 改变集合时,是否可以在 React 中返回一个空对象?

标签 javascript reactjs ecmascript-6

背景

我一直在研究 React,并制作了一个简单的待办事项列表应用来探索一些概念。在测试我的代码时,我意识到在更改/更新状态存储集合时似乎没有必要从 setState() 返回新状态。

根据其他几个 StackOverflow 问题和 React 文档,我编写的代码要么不起作用,要么产生意外结果。然而,在我的所有测试中,代码似乎确实有效,并且比建议的改变集合的方法更具可读性和简洁性。

为什么我的代码可以工作,如果有的话,将它用作模式有什么危险?

我已经为我的应用创建了两个版本。一种使用提到的更新集合的方法 in this question , 而另一个具有 setState() 的则返回一个空对象。我已将该应用程序的完整版本上传到 CodePen,因此您可以看到它们的行为相同。

代码段

这是原文的关键代码段。我正在使用 setState() 的回调来保证状态读取和状态写入自动发生(在调用之间发生异步状态更改的情况下)。

addTask(taskText) {
        this.setState(prevState => {
            const updatedTasks = prevState.tasks;
            updatedTasks.set(prevState.uid, taskText);   // use the original, un-incremented uid
            return {
                uid: ++prevState.uid,   // increment prev uid and store it as new state
                tasks: updatedTasks, // set tasks to updated tasks
            }
        }, this.logState);
    }


但是,对于集合(或任何其他引用值对象)来说,返回实际更改的状态似乎是不必要的。由于以下代码也有效。唯一的区别是我将 uid 提升到一个类属性并且没有费心返回更新后的 map 。

addTask(taskText) {
    this.setState(prevState => {
        const updatedTasks = prevState.tasks;
        updatedTasks.set(this.uid, taskText);   // use the original, un-incremented uid
        this.uid++;
        return {
            // return an empty object
            //uid: ++prevState.uid,   // update uid to one more than prev uid
            //tasks: updatedTasks, // set tasks to updated tasks
        }
    }, this.logState);
}


如果我不关心将突变包装在箭头函数中作为异步守卫,那么该方法可以进一步简化:

addTask(taskText) {
        this.state.tasks.set(this.uid, taskText);   // use the original, un-incremented uid
        this.uid++;
        this.setState({});
}


似乎唯一真正重要的是 setState() 调用本身。我最初的理解是 React 非常高效,并且 onyl 会检查它所告知的状态变化。然而,最后一个例子似乎表明 setState() 导致 React 检查所有已知状态的任何变化(不管它们是如何到达那里的),然后相应地更新/渲染。

对基元的更改仍需要包装在返回的 setState() 对象中,但对于对象(或至少是 Maps),消除复杂性并仅使用裸 setState() 调用的缺点是什么?


引用

我正在使用以下内容:

  • React 和 ReactDOM v16.2.0(CodePens 上为 15.1.0)
  • Babel 6.26.0(具有对类属性的第 2 阶段支持)
  • ECMAScript 6

最佳答案

1) React setState 很聪明,可以识别状态对象实体发生的变化。因此,如果您认为 this.setState({}) 会使 this.state = {} 成为空对象,那您就错了。它所做的是比较对象实体所做的更改,并且它只会更新那些更改。

2) 根据react docs :

切勿直接改变 this.state,因为之后调用 setState() 可能会替换您所做的改变。将 this.state 视为不可变的。

所以这意味着如果你有使用 set 函数的映射值,你可以改变状态,所以它不会给你错误,但是如果你尝试像这样初始化它 this.state.tasks = [] 那么它肯定会出错。所以你期望得到错误不会结果,因为它 this.state 是可变的,但我们不需要直接改变它。此外,有时它可能会在以后的 this.setState 调用中设置不正确的值。

3) 因此,如果您使用 Mapset 函数设置状态状态,那么状态将被操纵,但页面不会重新呈现 因为它应该在更新时重新呈现。所以你不应该像这样改变状态,而应该使用 this.setState 函数来避免不必要的事情发生。

4) 在 removeTasks 的情况下,您正在使用 this.setStateprevState 回调,所以 react 做的是它将使用 prevState 和如果您返回空白对象,那么它会将整个对象初始化为您定义的初始状态。所以,如果你想尝试,你可以将 initial state 设置为 this.state = {tasks: new Map().set(1, "awdawd")} 然后单击删除任务按钮时,您会看到意想不到的结果。因此,如果您返回一个空对象,React 会返回初始状态。

仅供引用,您可以在以下链接中阅读有关setState 的更多详细信息:faq-state

关于javascript - 调用 setState() 改变集合时,是否可以在 React 中返回一个空对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49395084/

相关文章:

javascript - 通过 jQuery UI 自动完成功能包装 Google Places 自动完成服务

reactjs - Typescript 警告 "Cannot find module"导入 AntDesign 组件

javascript - Apollo GraphQL 合并缓存数据

php - 在多部分表单提交上显示加载 gif

javascript - 如何检查 JavaScript 中用户浏览器是否不支持字符?

javascript - 在 React.js 组件中添加 props 作为 HTML 属性

javascript - 在后台从 React 组件制作 HTML 字符串,如何在另一个 React 组件中通过 dangerouslySetInnerHTML 使用该字符串

javascript - 在 es6 中,我需要 promise 在完成后返回 true 或 false

javascript - 我在使用 ES6 的导入和导出功能时遇到问题

javascript - 当第二个函数完成时,使用 Promise 在函数导出中返回一个值