@tarojs/react 3.7.0-alpha.2 → 3.7.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +407 -10
- package/dist/index.js.map +1 -1
- package/dist/react.esm.js +406 -13
- package/dist/react.esm.js.map +1 -1
- package/package.json +3 -3
package/dist/react.esm.js
CHANGED
|
@@ -1,12 +1,289 @@
|
|
|
1
1
|
import { isString, isObject, isFunction, capitalize, toCamelCase, internalComponents, isNumber, noop, isUndefined, isBoolean, ensure } from '@tarojs/shared';
|
|
2
|
-
import { FormElement, document } from '@tarojs/runtime';
|
|
2
|
+
import { FormElement, document, hooks } from '@tarojs/runtime';
|
|
3
3
|
import Reconciler from 'react-reconciler';
|
|
4
|
-
import { DefaultEventPriority } from 'react-reconciler/constants';
|
|
4
|
+
import { DefaultEventPriority as DefaultEventPriority$1 } from 'react-reconciler/constants';
|
|
5
|
+
|
|
6
|
+
const supportedInputTypes = {
|
|
7
|
+
color: true,
|
|
8
|
+
date: true,
|
|
9
|
+
datetime: true,
|
|
10
|
+
'datetime-local': true,
|
|
11
|
+
email: true,
|
|
12
|
+
month: true,
|
|
13
|
+
number: true,
|
|
14
|
+
password: true,
|
|
15
|
+
range: true,
|
|
16
|
+
search: true,
|
|
17
|
+
tel: true,
|
|
18
|
+
text: true,
|
|
19
|
+
time: true,
|
|
20
|
+
url: true,
|
|
21
|
+
week: true,
|
|
22
|
+
};
|
|
23
|
+
const SyncLane = 1;
|
|
24
|
+
const InputContinuousLane = 4;
|
|
25
|
+
const DefaultLane = 16;
|
|
26
|
+
const DiscreteEventPriority = SyncLane;
|
|
27
|
+
const ContinuousEventPriority = InputContinuousLane;
|
|
28
|
+
const DefaultEventPriority = DefaultLane;
|
|
29
|
+
function getEventPriority(domEventName) {
|
|
30
|
+
switch (domEventName) {
|
|
31
|
+
case 'cancel':
|
|
32
|
+
case 'click':
|
|
33
|
+
case 'close':
|
|
34
|
+
case 'contextmenu':
|
|
35
|
+
case 'copy':
|
|
36
|
+
case 'cut':
|
|
37
|
+
case 'dragend':
|
|
38
|
+
case 'dragstart':
|
|
39
|
+
case 'drop':
|
|
40
|
+
case 'input':
|
|
41
|
+
case 'paste':
|
|
42
|
+
case 'pause':
|
|
43
|
+
case 'play':
|
|
44
|
+
case 'pointercancel':
|
|
45
|
+
case 'pointerdown':
|
|
46
|
+
case 'pointerup':
|
|
47
|
+
case 'reset':
|
|
48
|
+
case 'resize':
|
|
49
|
+
case 'submit':
|
|
50
|
+
case 'touchcancel':
|
|
51
|
+
case 'touchend':
|
|
52
|
+
case 'touchstart':
|
|
53
|
+
case 'change':
|
|
54
|
+
case 'blur':
|
|
55
|
+
case 'focus':
|
|
56
|
+
case 'select':
|
|
57
|
+
case 'selectstart':
|
|
58
|
+
return DiscreteEventPriority;
|
|
59
|
+
case 'drag':
|
|
60
|
+
case 'dragenter':
|
|
61
|
+
case 'dragexit':
|
|
62
|
+
case 'dragleave':
|
|
63
|
+
case 'dragover':
|
|
64
|
+
case 'pointermove':
|
|
65
|
+
case 'pointerout':
|
|
66
|
+
case 'pointerover':
|
|
67
|
+
case 'scroll':
|
|
68
|
+
case 'toggle':
|
|
69
|
+
case 'touchmove':
|
|
70
|
+
case 'pointerenter':
|
|
71
|
+
case 'pointerleave':
|
|
72
|
+
return ContinuousEventPriority;
|
|
73
|
+
default:
|
|
74
|
+
return DefaultEventPriority;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const randomKey = Math.random()
|
|
78
|
+
.toString(36)
|
|
79
|
+
.slice(2);
|
|
80
|
+
const internalPropsKey = '__reactProps$' + randomKey;
|
|
81
|
+
const internalInstanceKey = '__reactFiber$' + randomKey;
|
|
82
|
+
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
|
|
83
|
+
// const internalEventHandlersKey = '__reactEvents$' + randomKey
|
|
84
|
+
// const internalEventHandlerListenersKey = '__reactListeners$' + randomKey
|
|
85
|
+
// const internalEventHandlesSetKey = '__reactHandles$' + randomKey
|
|
86
|
+
|
|
87
|
+
const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
|
|
88
|
+
const HostComponent = 5;
|
|
89
|
+
const HostText = 6;
|
|
90
|
+
const SuspenseComponent = 13;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 给 TaroElement 绑定 react fiber、react props 等属性
|
|
94
|
+
* 提供 fiber -> element、element -> fiber、element -> props 的方法
|
|
95
|
+
*/
|
|
96
|
+
function precacheFiberNode(hostInst, node) {
|
|
97
|
+
node[internalInstanceKey] = hostInst;
|
|
98
|
+
}
|
|
99
|
+
function markContainerAsRoot(hostRoot, node) {
|
|
100
|
+
node[internalContainerInstanceKey] = hostRoot;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent
|
|
104
|
+
* instance, or null if the node was not rendered by this React.
|
|
105
|
+
*/
|
|
106
|
+
function getInstanceFromNode(node) {
|
|
107
|
+
const inst = node[internalInstanceKey] || node[internalContainerInstanceKey];
|
|
108
|
+
if (inst) {
|
|
109
|
+
if (inst.tag === HostComponent ||
|
|
110
|
+
inst.tag === HostText ||
|
|
111
|
+
inst.tag === SuspenseComponent ||
|
|
112
|
+
inst.tag === HostRoot) {
|
|
113
|
+
return inst;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding
|
|
123
|
+
* DOM node.
|
|
124
|
+
*/
|
|
125
|
+
function getNodeFromInstance(inst) {
|
|
126
|
+
if (inst.tag === HostComponent || inst.tag === HostText) {
|
|
127
|
+
// In Fiber this, is just the state node right now. We assume it will be
|
|
128
|
+
// a host component or host text.
|
|
129
|
+
return inst.stateNode;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function getFiberCurrentPropsFromNode(node) {
|
|
133
|
+
return node[internalPropsKey] || null;
|
|
134
|
+
}
|
|
135
|
+
function updateFiberProps(node, props) {
|
|
136
|
+
node[internalPropsKey] = props;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 从 props 中,更新 input 组件的 value 值
|
|
140
|
+
function updateInputWrapper(element, oldValue, props) {
|
|
141
|
+
const node = element;
|
|
142
|
+
const checked = props.checked;
|
|
143
|
+
if (checked != null) {
|
|
144
|
+
console.warn('updateCheck 未实现', node);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
updateWrapper(element, oldValue, props);
|
|
148
|
+
updateNamedCousins(element, props);
|
|
149
|
+
}
|
|
150
|
+
// react 中原本处理 type=radio 的逻辑,这里留个空,暂时不处理
|
|
151
|
+
function updateNamedCousins(rootNode, props) {
|
|
152
|
+
const name = props.name;
|
|
153
|
+
if (props.type === 'radio' && name != null) {
|
|
154
|
+
console.warn('radio updateNamedCousins 未实现', rootNode, props);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function getToStringValue(value) {
|
|
158
|
+
const isEmptyType = typeof value === 'function' || typeof value === 'symbol';
|
|
159
|
+
return isEmptyType ? '' : value;
|
|
160
|
+
}
|
|
161
|
+
function toString(value) {
|
|
162
|
+
return '' + value;
|
|
163
|
+
}
|
|
164
|
+
function updateWrapper(element, oldValue, props) {
|
|
165
|
+
const node = element;
|
|
166
|
+
const value = getToStringValue(props.value);
|
|
167
|
+
const type = props.type;
|
|
168
|
+
setNodeValue(node, oldValue, value, type);
|
|
169
|
+
}
|
|
170
|
+
// oldValue 为 event.detail.value,value 为 fiber.props.value
|
|
171
|
+
// 如果 oldValue 和 value 不相等,代表受控组件需要更新
|
|
172
|
+
// 更新的原则为,fiber.props.value 永远为用户所需要的值,因此 node.value = toString(value)
|
|
173
|
+
function setNodeValue(node, oldValue, value, type = 'string') {
|
|
174
|
+
if (value != null) {
|
|
175
|
+
if (type === 'number') {
|
|
176
|
+
if ((value === 0 && node.value === '') ||
|
|
177
|
+
// We explicitly want to coerce to number here if possible.
|
|
178
|
+
// eslint-disable-next-line
|
|
179
|
+
oldValue != value) {
|
|
180
|
+
node.value = toString(value);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (oldValue !== toString(value)) {
|
|
184
|
+
node.value = toString(value);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else if (type === 'submit' || type === 'reset') {
|
|
188
|
+
// Submit/reset inputs need the attribute removed completely to avoid
|
|
189
|
+
// blank-text buttons.
|
|
190
|
+
node.removeAttribute('value');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// 判断当前 TaroElement 是否为 supportedInputTypes input 或 textarea
|
|
194
|
+
function isTextInputElement(elem) {
|
|
195
|
+
const nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();
|
|
196
|
+
if (nodeName === 'input') {
|
|
197
|
+
const type = elem.type;
|
|
198
|
+
return !type || !!supportedInputTypes[type];
|
|
199
|
+
}
|
|
200
|
+
if (nodeName === 'textarea') {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
const ReactDOMTextareaRestoreControlledState = updateWrapper;
|
|
206
|
+
const ReactDOMInputRestoreControlledState = updateInputWrapper;
|
|
207
|
+
|
|
208
|
+
function isCheckable(elem) {
|
|
209
|
+
const type = elem.type;
|
|
210
|
+
const nodeName = elem.nodeName;
|
|
211
|
+
return (nodeName &&
|
|
212
|
+
nodeName.toLowerCase() === 'input' &&
|
|
213
|
+
(type === 'checkbox' || type === 'radio'));
|
|
214
|
+
}
|
|
215
|
+
function getTracker(node) {
|
|
216
|
+
return node._valueTracker;
|
|
217
|
+
}
|
|
218
|
+
function detachTracker(node) {
|
|
219
|
+
node._valueTracker = null;
|
|
220
|
+
}
|
|
221
|
+
// 之所以单独创建一个 tacker,是为了统一监听不同 type 的 input 值
|
|
222
|
+
// 比如 type=checkbox 或者 type=radio,就需要监听 checked,而不是 value
|
|
223
|
+
// 虽然目前还未实现 checkbox 和 radio 的 finishEventHandle,但后续不好说,所以先统一和 react 一样的写法
|
|
224
|
+
// 需要特别注意的是,tracker 初始化时的值为 node 的初始值,但后续会变更为事件的 detail.value 值
|
|
225
|
+
function trackValueOnNode(node) {
|
|
226
|
+
const valueField = isCheckable(node) ? 'checked' : 'value';
|
|
227
|
+
const descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField);
|
|
228
|
+
let currentValue = '' + node[valueField];
|
|
229
|
+
if (node.hasOwnProperty(valueField) ||
|
|
230
|
+
typeof descriptor === 'undefined' ||
|
|
231
|
+
typeof descriptor.get !== 'function' ||
|
|
232
|
+
typeof descriptor.set !== 'function') {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const { get, set } = descriptor;
|
|
236
|
+
Object.defineProperty(node, valueField, {
|
|
237
|
+
configurable: true,
|
|
238
|
+
enumerable: descriptor.enumerable,
|
|
239
|
+
get: function () {
|
|
240
|
+
return get.call(this);
|
|
241
|
+
},
|
|
242
|
+
set: function (value) {
|
|
243
|
+
currentValue = '' + value;
|
|
244
|
+
set.call(this, value);
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
const tracker = {
|
|
248
|
+
getValue() {
|
|
249
|
+
return currentValue;
|
|
250
|
+
},
|
|
251
|
+
setValue(value) {
|
|
252
|
+
currentValue = '' + value;
|
|
253
|
+
},
|
|
254
|
+
stopTracking() {
|
|
255
|
+
detachTracker(node);
|
|
256
|
+
delete node[valueField];
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
return tracker;
|
|
260
|
+
}
|
|
261
|
+
function track(node) {
|
|
262
|
+
if (getTracker(node)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
node._valueTracker = trackValueOnNode(node);
|
|
266
|
+
}
|
|
267
|
+
function updateValueIfChanged(node, nextValue) {
|
|
268
|
+
if (!node) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const tracker = getTracker(node);
|
|
272
|
+
if (!tracker) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
const lastValue = tracker.getValue();
|
|
276
|
+
if (nextValue !== lastValue) {
|
|
277
|
+
tracker.setValue(nextValue);
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
5
282
|
|
|
6
283
|
function isEventName(s) {
|
|
7
284
|
return s[0] === 'o' && s[1] === 'n';
|
|
8
285
|
}
|
|
9
|
-
const IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
|
|
286
|
+
const IS_NON_DIMENSIONAL = /aspect|acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
|
|
10
287
|
function updateProps(dom, oldProps, newProps) {
|
|
11
288
|
const updatePayload = getUpdatePayload(dom, oldProps, newProps);
|
|
12
289
|
if (updatePayload) {
|
|
@@ -151,14 +428,20 @@ const hostConfig = {
|
|
|
151
428
|
return null;
|
|
152
429
|
},
|
|
153
430
|
resetAfterCommit: noop,
|
|
154
|
-
createInstance(type) {
|
|
155
|
-
|
|
431
|
+
createInstance(type, props, _rootContainerInstance, _hostContext, internalInstanceHandle) {
|
|
432
|
+
const element = document.createElement(type);
|
|
433
|
+
precacheFiberNode(internalInstanceHandle, element);
|
|
434
|
+
updateFiberProps(element, props);
|
|
435
|
+
return element;
|
|
156
436
|
},
|
|
157
437
|
appendInitialChild(parent, child) {
|
|
158
438
|
parent.appendChild(child);
|
|
159
439
|
},
|
|
160
|
-
finalizeInitialChildren(dom,
|
|
440
|
+
finalizeInitialChildren(dom, type, props) {
|
|
161
441
|
updateProps(dom, {}, props); // 提前执行更新属性操作,Taro 在 Page 初始化后会立即从 dom 读取必要信息
|
|
442
|
+
if (type === 'input' || type === 'textarea') {
|
|
443
|
+
track(dom);
|
|
444
|
+
}
|
|
162
445
|
return false;
|
|
163
446
|
},
|
|
164
447
|
prepareUpdate(instance, _, oldProps, newProps) {
|
|
@@ -167,8 +450,10 @@ const hostConfig = {
|
|
|
167
450
|
shouldSetTextContent() {
|
|
168
451
|
return false;
|
|
169
452
|
},
|
|
170
|
-
createTextInstance(text) {
|
|
171
|
-
|
|
453
|
+
createTextInstance(text, _rootContainerInstance, _hostContext, internalInstanceHandle) {
|
|
454
|
+
const textNode = document.createTextNode(text);
|
|
455
|
+
precacheFiberNode(internalInstanceHandle, textNode);
|
|
456
|
+
return textNode;
|
|
172
457
|
},
|
|
173
458
|
scheduleTimeout: setTimeout,
|
|
174
459
|
cancelTimeout: clearTimeout,
|
|
@@ -185,7 +470,7 @@ const hostConfig = {
|
|
|
185
470
|
prepareScopeUpdate: noop,
|
|
186
471
|
getInstanceFromScope: () => null,
|
|
187
472
|
getCurrentEventPriority() {
|
|
188
|
-
return DefaultEventPriority;
|
|
473
|
+
return DefaultEventPriority$1;
|
|
189
474
|
},
|
|
190
475
|
detachDeletedInstance: noop,
|
|
191
476
|
// -------------------
|
|
@@ -216,8 +501,9 @@ const hostConfig = {
|
|
|
216
501
|
textInst.nodeValue = newText;
|
|
217
502
|
},
|
|
218
503
|
commitMount: noop,
|
|
219
|
-
commitUpdate(dom, updatePayload, _, oldProps) {
|
|
504
|
+
commitUpdate(dom, updatePayload, _, oldProps, newProps) {
|
|
220
505
|
updatePropsByPayload(dom, oldProps, updatePayload);
|
|
506
|
+
updateFiberProps(dom, newProps);
|
|
221
507
|
},
|
|
222
508
|
insertBefore(parent, child, refChild) {
|
|
223
509
|
parent.insertBefore(child, refChild);
|
|
@@ -253,14 +539,14 @@ const hostConfig = {
|
|
|
253
539
|
if (element.childNodes.length > 0) {
|
|
254
540
|
element.textContent = '';
|
|
255
541
|
}
|
|
256
|
-
}
|
|
542
|
+
}
|
|
257
543
|
};
|
|
258
544
|
const TaroReconciler = Reconciler(hostConfig);
|
|
259
545
|
if (process.env.NODE_ENV !== 'production') {
|
|
260
546
|
const foundDevTools = TaroReconciler.injectIntoDevTools({
|
|
261
547
|
bundleType: 1,
|
|
262
548
|
version: '18.0.0',
|
|
263
|
-
rendererPackageName: 'taro-react'
|
|
549
|
+
rendererPackageName: 'taro-react'
|
|
264
550
|
});
|
|
265
551
|
if (!foundDevTools) {
|
|
266
552
|
// eslint-disable-next-line no-console
|
|
@@ -270,6 +556,79 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
270
556
|
}
|
|
271
557
|
}
|
|
272
558
|
|
|
559
|
+
let restoreQueue = null;
|
|
560
|
+
// 对比 TaroElement tracker 下的 value 和事件下的 value,判断 element 的值是否存在更改
|
|
561
|
+
function getTargetInstForInputOrChangeEvent(e, node) {
|
|
562
|
+
var _a, _b;
|
|
563
|
+
const targetInst = getInstanceFromNode(node);
|
|
564
|
+
const domEventName = e.type;
|
|
565
|
+
if (!targetInst || !isTextInputElement(node))
|
|
566
|
+
return;
|
|
567
|
+
if (domEventName === 'input' || domEventName === 'change') {
|
|
568
|
+
const nextValue = toString((_b = (_a = e.mpEvent) === null || _a === void 0 ? void 0 : _a.detail) === null || _b === void 0 ? void 0 : _b.value);
|
|
569
|
+
return getInstIfValueChanged(targetInst, nextValue);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function getInstIfValueChanged(targetInst, nextValue) {
|
|
573
|
+
const targetNode = getNodeFromInstance(targetInst);
|
|
574
|
+
if (!targetNode)
|
|
575
|
+
return false;
|
|
576
|
+
if (updateValueIfChanged(targetNode, nextValue)) {
|
|
577
|
+
return targetInst;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// 把 target 塞入更新队列中
|
|
581
|
+
function enqueueStateRestore(target) {
|
|
582
|
+
if (restoreQueue) {
|
|
583
|
+
restoreQueue.push(target);
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
restoreQueue = [target];
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// 判断是否需要恢复 target(input、textarea) 的状态
|
|
590
|
+
function needsStateRestore() {
|
|
591
|
+
return restoreQueue !== null;
|
|
592
|
+
}
|
|
593
|
+
function finishEventHandler() {
|
|
594
|
+
const controlledComponentsHavePendingUpdates = needsStateRestore();
|
|
595
|
+
if (controlledComponentsHavePendingUpdates) {
|
|
596
|
+
TaroReconciler.flushSync();
|
|
597
|
+
restoreStateIfNeeded();
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
// 遍历 restoreQueue、restoreTarget,恢复其状态
|
|
601
|
+
function restoreStateIfNeeded() {
|
|
602
|
+
if (!restoreQueue) {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const queuedTargets = restoreQueue;
|
|
606
|
+
restoreQueue = null;
|
|
607
|
+
for (let i = 0; i < queuedTargets.length; i++) {
|
|
608
|
+
restoreStateOfTarget(queuedTargets[i]);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function restoreImpl(domElement, tag, oldValue, props) {
|
|
612
|
+
switch (tag) {
|
|
613
|
+
case 'input':
|
|
614
|
+
ReactDOMInputRestoreControlledState(domElement, oldValue, props);
|
|
615
|
+
break;
|
|
616
|
+
case 'textarea':
|
|
617
|
+
ReactDOMTextareaRestoreControlledState(domElement, oldValue, props);
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
function restoreStateOfTarget(item) {
|
|
622
|
+
const internalInstance = getInstanceFromNode(item.target);
|
|
623
|
+
if (!internalInstance)
|
|
624
|
+
return;
|
|
625
|
+
const { stateNode, type } = internalInstance;
|
|
626
|
+
if (stateNode) {
|
|
627
|
+
const props = getFiberCurrentPropsFromNode(stateNode);
|
|
628
|
+
restoreImpl(stateNode, type, item.value, props);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
273
632
|
const ContainerMap = new WeakMap();
|
|
274
633
|
class Root {
|
|
275
634
|
constructor(renderer, domContainer, options) {
|
|
@@ -332,6 +691,7 @@ function render(element, domContainer, cb) {
|
|
|
332
691
|
return root.render(element, cb);
|
|
333
692
|
}
|
|
334
693
|
function createRoot(domContainer, options = {}) {
|
|
694
|
+
var _a;
|
|
335
695
|
const oldRoot = ContainerMap.get(domContainer);
|
|
336
696
|
if (oldRoot != null) {
|
|
337
697
|
return oldRoot;
|
|
@@ -339,10 +699,43 @@ function createRoot(domContainer, options = {}) {
|
|
|
339
699
|
// options should be an object
|
|
340
700
|
const root = new Root(TaroReconciler, domContainer, options);
|
|
341
701
|
ContainerMap.set(domContainer, root);
|
|
702
|
+
markContainerAsRoot((_a = root === null || root === void 0 ? void 0 : root.internalRoot) === null || _a === void 0 ? void 0 : _a.current, domContainer);
|
|
703
|
+
hooks.tap('dispatchTaroEvent', (e, node) => {
|
|
704
|
+
const eventPriority = getEventPriority(e.type);
|
|
705
|
+
TaroReconciler.runWithPriority(eventPriority, () => {
|
|
706
|
+
node.dispatchEvent(e);
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
// 对比 event.detail.value 和 node.tracker.value,判断 value 值是否有变动,存在变动则塞入队列中
|
|
710
|
+
hooks.tap('modifyTaroEvent', (e, node) => {
|
|
711
|
+
var _a, _b;
|
|
712
|
+
const inst = getTargetInstForInputOrChangeEvent(e, node);
|
|
713
|
+
if (!inst)
|
|
714
|
+
return;
|
|
715
|
+
// 这里塞入的是 event.detail.value,也就是事件的值,在受控组件中,你可以理解为需要被变更的值
|
|
716
|
+
// 后续会在 finishEventHandler 中,使用最新的 fiber.props.value 来与其比较
|
|
717
|
+
// 如果不一致,则表示需要更新,会执行 node.value = fiber.props.value 的更新操作
|
|
718
|
+
const nextValue = (_b = (_a = e.mpEvent) === null || _a === void 0 ? void 0 : _a.detail) === null || _b === void 0 ? void 0 : _b.value;
|
|
719
|
+
enqueueStateRestore({ target: node, value: nextValue });
|
|
720
|
+
});
|
|
342
721
|
return root;
|
|
343
722
|
}
|
|
344
723
|
|
|
345
|
-
|
|
724
|
+
let isInsideEventHandler = false;
|
|
725
|
+
// 重新包裹 batchedUpdates,使其可以在触发事件后执行 finishEventHandler
|
|
726
|
+
const unstable_batchedUpdates = (fn, a) => {
|
|
727
|
+
if (isInsideEventHandler) {
|
|
728
|
+
return fn(a);
|
|
729
|
+
}
|
|
730
|
+
isInsideEventHandler = true;
|
|
731
|
+
try {
|
|
732
|
+
return TaroReconciler.batchedUpdates(fn, a);
|
|
733
|
+
}
|
|
734
|
+
finally {
|
|
735
|
+
isInsideEventHandler = false;
|
|
736
|
+
finishEventHandler();
|
|
737
|
+
}
|
|
738
|
+
};
|
|
346
739
|
function unmountComponentAtNode(dom) {
|
|
347
740
|
ensure(dom && [1, 8, 9, 11].includes(dom.nodeType), 'unmountComponentAtNode(...): Target container is not a DOM element.');
|
|
348
741
|
const root = ContainerMap.get(dom);
|