Я пытаюсь понять основную причину какого-то несколько "магического" поведения, которое я вижу, что я не могу полностью объяснить и что не видно из чтения исходного кода ReactJS.
При вызове метода setState
синхронно в ответ на событие onChange
на входе все работает так, как ожидалось. "Новое" значение ввода уже присутствует, поэтому DOM фактически не обновляется. Это очень желательно, потому что это означает, что курсор не переместится в конец поля ввода.
Однако при запуске компонента с точно такой же структурой, но с асинхронным вызовом setState
, "новое" значение ввода, по-видимому, не присутствует, заставляя ReactJS фактически касаться DOM, что приводит к тому, что курсор перейдите в конец ввода.
По-видимому, что-то вмешивается в "reset" вход обратно к предыдущему value
в асинхронном случае, чего он не делает в синхронном случае. Что это за механик?
Синхронный пример
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
, распечатывая текущий value
фактического DOM node.
При вводе "X" между двумя Ls "Hello" мы видим следующий вывод консоли, и курсор остается там, где ожидалось:
Rendering...
Setting value:HelXlo
Current value:HelXlo
Асинхронный пример
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
.
В этом случае, набрав X между двумя Ls, вы получите следующий вывод консоли, и курсор переместится в конец ввода:
Rendering...
Setting value:HelXlo
Current value:Hello
Почему это?
Я понимаю концепцию React Контролируемого компонента, и поэтому имеет смысл, что пользователь переходит к value
, игнорируется. Но похоже, что value
фактически изменен, а затем явно reset.
По-видимому, вызов setState
синхронно гарантирует, что он вступает в силу до reset, а вызов setState
в любое другое время происходит после reset, заставляя повторную визуализацию.
Это на самом деле то, что происходит?
Пример JS Bin