我试图理解一些我无法完全解释的"神奇"行为的根本原因,而这在阅读ReactJS源代码时并不明显.
当同步调用setState
方法以响应输入上的onChange
事件时,一切正常.输入的"新"值已经存在,因此DOM实际上没有更新.这是非常可取的,因为这意味着光标不会跳到输入框的末尾.
然而,当运行一个 struct 完全相同但调用setState
asynchronously的组件时,输入的"新"值似乎不存在,导致ReactJS实际接触DOM,从而导致光标跳到输入的末尾.
显然,在异步情况下,有什么东西正在干预将输入"重置"到之前的value
,而在同步情况下则没有这样做.这是什么机修工?
Synchronous Example
var synchronouslyUpdatingComponent =
React.createFactory(React.createClass({
getInitialState: function () {
return {value: "Hello"};
},
changeHandler: function (e) {
this.setState({value: e.target.value});
},
render: function () {
var valueToSet = this.state.value;
console.log("Rendering...");
console.log("Setting value:" + valueToSet);
if(this.isMounted()) {
console.log("Current value:" + this.getDOMNode().value);
}
return React.DOM.input({value: valueToSet,
onChange: this.changeHandler});
}
}));
注意,代码将登录render
方法,打印出实际DOM node 的当前value
.
在"Hello"的两个L之间键入"X"时,我们会看到以下控制台输出,光标停留在预期的位置:
Rendering...
Setting value:HelXlo
Current value:HelXlo
Asynchronous Example
var asynchronouslyUpdatingComponent =
React.createFactory(React.createClass({
getInitialState: function () {
return {value: "Hello"};
},
changeHandler: function (e) {
var component = this;
var value = e.target.value;
window.setTimeout(function() {
component.setState({value: value});
});
},
render: function () {
var valueToSet = this.state.value;
console.log("Rendering...");
console.log("Setting value:" + valueToSet);
if(this.isMounted()) {
console.log("Current value:" + this.getDOMNode().value);
}
return React.DOM.input({value: valueToSet,
onChange: this.changeHandler});
}
}));
这与上面完全相同,只是对setState
的调用是在setTimeout
回调中.
在这种情况下,在两个Ls之间键入X会产生以下控制台输出,光标会跳到输入的末尾:
Rendering...
Setting value:HelXlo
Current value:Hello
Why is this?
我理解React的Controlled Component的概念,因此忽略用户对value
的更改是有道理的.但看起来value
实际上已经更改,然后显式重置.
显然,同步调用setState
可以确保重置生效,而在任何其他时间调用setState
都会发生重置,从而强制重新渲染.
事实上是这样吗?
JS Bin Example