我能改变传给setState函数的状态吗?

15

我知道在React中不应该直接改变状态(state),但是如果我使用函数呢?

onSocialClick = e => {
    const id = e.target.value;
    this.setState((prevState, props) => {
        prevState[id] = !(prevState[id]);
        return prevState;
    });
};

修改传递的对象是一个错误吗?

编辑:

事实证明,我们大多数人都错了。React 文档现在明确指出:

状态是对组件状态在应用更改时的引用。它不应该被直接改变。相反,应该通过基于状态和属性输入构建新对象来表示更改。

感谢@Tomáš Hübelbauer在评论中指出这一点。


3
这不是错误 :) 不要直接修改状态意味着你应该使用 setState 而不是 this.state =...。如果你这样做的话 - 无论你使用什么作为传入参数,一切都会正常。 - elmeister
@Tomasz 我提出了一个后续问题,因为我对你的代码片段有疑问。你可能会发现这很有趣:https://dev59.com/lFYN5IYBdhLWcg3wfoRj - Tomáš Hübelbauer
1
@TomášHübelbauer 谢谢!我已经进行了编辑。 - Tomasz Mularczyk
我试图在文档中找到确切的语句,但看起来他们已经将变量prevState重命名为state - Andrew Nessin
4个回答

3
更简洁的方法是直接引用您要编辑的属性:
doIt = () => this.setState(({ [id]: prevValue }) => ({
  [id]: !prevValue,
}));

如果 [id] 不是 state 的直接子级,而是下一级,是否可以这样做?在我的情况下,我有一个 [id] 数组,所有其他的 Q/As 和文章都建议制作副本,但我发现您的解决方案更清晰。 - Al.G.
@Al.G. 你可能需要使用 find 函数来获取正确的索引,以访问正确的数组元素。 - Fez Vrasta

0
不,你不应该在setState的更新函数中改变prevState。
更新函数必须是一个纯函数。


更新程序函数被调用了两次。请参见讨论

检查以下codesandbox并打开codesandbox的控制台以查看其运行情况。

0
你的做法并没有错。修改参数然后返回它是完全可以的。但是,当你根据prevState的值修改状态时,使用带有prevState参数的setState更加适合你的情况,并且更加清晰的处理方式是:
onSocialClick = e => {
    const id = e.target.value;
    this.setState((prevState, props) => {
        return {[id] : !(prevState[id])};
    });
};

-1

强烈不建议直接改变状态。此外,您正在改变先前的状态,然后返回它,这没有太多意义。如果您想要的只是在state[id]处切换状态,则应将代码更改为:

onSocialClick = e => {
    const id = e.target.value;
    this.setState({this.state[id]: !this.state[id});
};

这是不鼓励的,你应该使用 OP 使用的函数式方法(但也许直接使用感兴趣的属性)。 - Fez Vrasta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接