Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 变异'this.state',然后立即调用'setState'怎么会中断呢?_Javascript_Reactjs - Fatal编程技术网

Javascript 变异'this.state',然后立即调用'setState'怎么会中断呢?

Javascript 变异'this.state',然后立即调用'setState'怎么会中断呢?,javascript,reactjs,Javascript,Reactjs,这是因为React组件的状态应该被视为是不可变的,即使您立即调用setState,改变this.state也很容易出错。就是 // #1: bad... this.state.items.push("New item"); this.setState({items: this.state.items}); // #2: good... this.setState({items: this.state.items.concat(["New item"])}); 有人能详细说明什么会导致上面的第

这是因为React组件的状态应该被视为是不可变的,即使您立即调用
setState
,改变
this.state
也很容易出错。就是

// #1: bad...
this.state.items.push("New item");
this.setState({items: this.state.items});

// #2: good...
this.setState({items: this.state.items.concat(["New item"])});

有人能详细说明什么会导致上面的第一个版本失败吗

使用新值调用
setState
时,React中的某些组件可以将新状态与以前的状态进行比较,以检测性能增强的更改(请参见此处:)。该方法被称为
shouldComponentUpdate
,并接收下一个道具和状态以进行比较。一些框架喜欢并使用这个

在第一个示例中,您已经改变了状态(对象和数组在JS中是通过引用的),因此调用setState可能是不可行的(因为状态已经相同)。您的组件可能不会自动重新渲染

下面是一个例子:

// Let's assume that `this.state === {numbers: [1]};` at the start
this.state.numbers.push(2);

// Oops - we just changed this.state directly,
// so now this.state === `{numbers: [1, 2]}`

// Now, react might compare the old this.state (which has been modified to [1, 2]) 
// to the object you're passing in (which is also [1, 2]).
// This might be a no-op.
this.setState({numbers: this.state.numbers});
在第二个示例中,MDN表示“concat()方法返回一个新的数组…”,也就是说,您不是在修改原始数组,而是完全返回一个新的数组。在第一个示例中,.push编辑现有数组


因为它是一个新数组,所以比较将始终按预期运行。

当您使用新值调用
setState
时,React中的一些组件可以将新状态与以前的状态进行比较,以检测性能增强的更改(请参见此处:)。该方法被称为
shouldComponentUpdate
,并接收下一个道具和状态以进行比较。一些框架喜欢并使用这个

在第一个示例中,您已经改变了状态(对象和数组在JS中是通过引用的),因此调用setState可能是不可行的(因为状态已经相同)。您的组件可能不会自动重新渲染

下面是一个例子:

// Let's assume that `this.state === {numbers: [1]};` at the start
this.state.numbers.push(2);

// Oops - we just changed this.state directly,
// so now this.state === `{numbers: [1, 2]}`

// Now, react might compare the old this.state (which has been modified to [1, 2]) 
// to the object you're passing in (which is also [1, 2]).
// This might be a no-op.
this.setState({numbers: this.state.numbers});
在第二个示例中,MDN表示“concat()方法返回一个新的数组…”,也就是说,您不是在修改原始数组,而是完全返回一个新的数组。在第一个示例中,.push编辑现有数组


因为它是一个新数组,所以比较将始终按预期运行。

请记住,
setState()
不一定是同步的。如果在同一执行线程中调用setState两次,它只会在下一次执行一次状态更新。如果需要,可以执行此操作。state.items.push,但直接在之后调用forceUpdate。顺便说一句,您对某些事情提出质疑真是太棒了。请记住,
setState()
不一定是同步的。请尝试使用forceUpdate代替。事实上,如果您在同一执行线程中调用setState两次,就像您一样,它只会执行一次状态更新,在下一个滴答声。如果你愿意,你可以这样做。state.items.push,但之后直接调用forceUpdate。顺便说一句,你质疑一些事情真是太棒了。我不确定这是不是问题所在。从我看到的情况来看,
render
总是在调用
setState
时调用,即使传入的所有属性都与其当前值相同(即,我可以反复调用
this.setState({a:2})
,它每次都会调用
render
),这就是问题所在,答案隐藏在这里:-如果您直接进行变异,然后调用setState()依赖于比较状态中断的东西。在始终调用render()这一点上,您是对的。我已经更新了答案以反映。好的,我可以理解,在某些
shouldComponentUpdate
实现中,我的“好”和“坏”版本的行为会有所不同。这是唯一的问题吗?据我所知,这是唯一的具体问题,尽管这是一个反模式,因为修改状态不是在函数式编程中完成的。在React中,使函数变得纯粹是一个很好的目标。Flux中纯存储的一个例子是框架——它非常优秀。好吧,我想我终于对这个答案感到满意了:)我不确定这是问题所在。从我看到的情况来看,
render
总是在调用
setState
时调用,即使传入的所有属性都与其当前值相同(即,我可以反复调用
this.setState({a:2})
,它每次都会调用
render
),这就是问题所在,答案隐藏在这里:-如果您直接进行变异,然后调用setState()依赖于比较状态中断的东西。在始终调用render()这一点上,您是对的。我已经更新了答案以反映。好的,我可以理解,在某些
shouldComponentUpdate
实现中,我的“好”和“坏”版本的行为会有所不同。这是唯一的问题吗?据我所知,这是唯一的具体问题,尽管这是一个反模式,因为修改状态不是在函数式编程中完成的。在React中,使函数变得纯粹是一个很好的目标。Flux中纯存储的一个例子是框架——它非常优秀。好吧,我想我终于对这个答案感到满意了:)