Reactソースを読む:Controlled Input
5268 ワード
みんなが
too young、Reactは全然そうではありません.私は彼がデフォルトの行為を阻止した証拠を探すのに多くの時間を費やしました.結局、道が曲がっていることに気づきました.余談はここまで、Reactでどのように実現するかを見てみましょう
これを読む前にReactのイベントシステムを知っておいたほうがいいです.関連内容はもう準備しましたが、まだ文章に整理されていません.皆さんはまず自分で理解して、私が更新してからここにリンクを置くので、私が最新の内容を取得することにも注目してください.
まず
では次は詳細を見てみましょう
ここでは2つの共通変数:
同じファイル
では、この方法はいつ呼び出されますか?答えは
ここで具体的にどういう意味なのかは気にしないで、
方法
イベントシステムの実行が完了した後、
後で具体的に更新する細部は分析しないで、みんながすべて理解していることを信じます(いくつかの重要でない関数を無視することができます)
Controlled Input
の概念は好奇心がなくて、私は最初にReactを使った时からそれにとても兴味を持っていましたが、どうしてその时は能力が足りなくて、ソースコードを见る时間もありませんでした.だから、ずっと推測して证明しなかった段阶です.後にVueを使って開発した時、私は自分で似たようなコンポーネントを実現したことがあります.その時、私はpreventDefault keyDown
イベントで自動更新を阻止し、大まかな機能を実現したので、それもReactのやり方かもしれないと思っていました.今ソースを見て、自分がまだtoo young、Reactは全然そうではありません.私は彼がデフォルトの行為を阻止した証拠を探すのに多くの時間を費やしました.結局、道が曲がっていることに気づきました.余談はここまで、Reactでどのように実現するかを見てみましょう
Controlled Input
これを読む前にReactのイベントシステムを知っておいたほうがいいです.関連内容はもう準備しましたが、まだ文章に整理されていません.皆さんはまず自分で理解して、私が更新してからここにリンクを置くので、私が最新の内容を取得することにも注目してください.
まず
batchedUpdates
のコードを見てみましょう.function batchedUpdates(fn, bookkeeping) {
if (isBatching) {
return fn(bookkeeping);
}
isBatching = true;
try {
return _batchedUpdates(fn, bookkeeping);
} finally {
isBatching = false;
var controlledComponentsHavePendingUpdates = needsStateRestore();
if (controlledComponentsHavePendingUpdates) {
_flushInteractiveUpdates();
restoreStateIfNeeded();
}
}
}
finally
ではrestoreStateIfNeeded
という方法が実行されています.コードデバッグでdebugger
を置く前に、state
を更新しないdemoを書くと、この方法を実行する前にinput
の内容が実際に変わってから戻ってくることがわかります.ははは、今あなたは大体推測できるでしょう.はい、Reactのやり方はevent
に関心を持っていません.彼は内容が実行されたら、ロールバックしてロールバックする必要があるかどうかを見てからロールバックします.では次は詳細を見てみましょう
function restoreStateIfNeeded() {
if (!restoreTarget) {
return;
}
var target = restoreTarget;
var queuedTargets = restoreQueue;
restoreTarget = null;
restoreQueue = null;
restoreStateOfTarget(target);
if (queuedTargets) {
for (var i = 0; i < queuedTargets.length; i++) {
restoreStateOfTarget(queuedTargets[i]);
}
}
}
ここでは2つの共通変数:
restoreTarget
とrestoreQueue
に関連していますが、この2つの変数はどのような状況で変化しますか?同じファイル
ReactControlledComponent
には、このような方法があります.export function enqueueStateRestore(target) {
if (restoreTarget) {
if (restoreQueue) {
restoreQueue.push(target);
} else {
restoreQueue = [target];
}
} else {
restoreTarget = target;
}
}
では、この方法はいつ呼び出されますか?答えは
ChangeEventPlugin
ですChangeEventPlugin = {
extractEvents() {
// ...
const event = createAndAccumulateChangeEvent(
inst,
nativeEvent,
nativeEventTarget,
);
}
}
function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
const event = SyntheticEvent.getPooled(
eventTypes.change,
inst,
nativeEvent,
target,
);
event.type = 'change';
// Flag this event loop as needing state restore.
enqueueStateRestore(target); //
accumulateTwoPhaseDispatches(event);
return event;
}
ここで具体的にどういう意味なのかは気にしないで、
change event
だけがコンテンツをロールバックする必要があることを知る必要があるので、change
イベントを生成するときに対応するノードを使用します.イベントが生成された時間はbatchUpdates
と一緒で、全体が直列に接続されています.inpute content -> trigger change event -> create event object -> enqueueStateRestore -> events trigger finsihed -> restoreStateIfNeeded
方法
function restoreStateOfTarget(target) {
var internalInstance = getInstanceFromNode(target);
if (!internalInstance) {
// Unmounted
return;
}
var props = getFiberCurrentPropsFromNode(internalInstance.stateNode);
fiberHostComponent.restoreControlledState(internalInstance.stateNode, internalInstance.type, props);
}
イベントシステムの実行が完了した後、
input
ノードに対応するFiber
オブジェクトを取得し、新しいprops
を読み取ります.ここで、props
はバインドイベントの実行が完了した後の最新のprops
です.これはcontrolled component
が本当に表示すべきprops
に対応し、props
の内容と入力ボックス内の実際の内容を比較します.返品が必要な場合は実行します.function restoreControlledState(domElement, tag, props) {
switch (tag) {
case 'input':
restoreControlledState(domElement, props);
return;
case 'textarea':
restoreControlledState$3(domElement, props);
return;
case 'select':
restoreControlledState$2(domElement, props);
return;
}
}
function restoreControlledState(element, props) {
var node = element;
updateWrapper(node, props);
updateNamedCousins(node, props);
}
function updateWrapper(element, props) {
var node = element;
updateChecked(element, props);
var value = getSafeValue(props.value);
//
if (value != null) {
if (props.type === 'number') {
if (value === 0 && node.value === '' ||
// eslint-disable-next-line
node.value != value) {
node.value = '' + value;
}
} else if (node.value !== '' + value) {
node.value = '' + value;
}
}
if (props.hasOwnProperty('value')) {
setDefaultValue(node, props.type, value);
} else if (props.hasOwnProperty('defaultValue')) {
setDefaultValue(node, props.type, getSafeValue(props.defaultValue));
}
if (props.checked == null && props.defaultChecked != null) {
node.defaultChecked = !!props.defaultChecked;
}
}
後で具体的に更新する細部は分析しないで、みんながすべて理解していることを信じます(いくつかの重要でない関数を無視することができます)