13
'use strict';
14
15
const ReactFiberErrorLogger = require('ReactFiberErrorLogger');
16
-const ReactFiberReconciler = require('ReactFiberReconciler');
16
const ReactGenericBatching = require('ReactGenericBatching');
18
-const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
19
-const ReactNativeComponentTree = require('ReactNativeComponentTree');
17
const ReactNativeFiberErrorDialog = require('ReactNativeFiberErrorDialog');
21
-const ReactNativeFiberHostComponent = require('ReactNativeFiberHostComponent');
18
const ReactNativeInjection = require('ReactNativeInjection');
23
-const ReactNativeTagHandles = require('ReactNativeTagHandles');
24
-const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
19
const ReactPortal = require('ReactPortal');
20
+const ReactNativeComponentTree = require('ReactNativeComponentTree');
21
+const ReactNativeFiberRenderer = require('ReactNativeFiberRenderer');
22
const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
23
const ReactVersion = require('ReactVersion');
24
const UIManager = require('UIManager');
25
30
-const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
31
-const emptyObject = require('fbjs/lib/emptyObject');
32
-const findNodeHandle = require('findNodeHandle');
33
-const invariant = require('fbjs/lib/invariant');
26
+const findNumericNodeHandle = require('findNumericNodeHandleFiber');
27
28
const {injectInternals} = require('ReactFiberDevToolsHook');
29
30
import type {Element} from 'React';
38
-import type {Fiber} from 'ReactFiber';
39
-import type {
40
- ReactNativeBaseComponentViewConfig,
41
-} from 'ReactNativeViewConfigRegistry';
31
+import type {ReactNativeType} from 'ReactNativeTypes';
32
import type {ReactNodeList} from 'ReactTypes';
43
-const {
44
- precacheFiberNode,
45
- uncacheFiberNode,
46
- updateFiberProps,
47
-} = ReactNativeComponentTree;
33
34
ReactNativeInjection.inject();
35
51
-type Container = number;
52
-export type Instance = {
53
- _children: Array<Instance | number>,
54
- _nativeTag: number,
55
- viewConfig: ReactNativeBaseComponentViewConfig,
56
-};
57
-type Props = Object;
58
-type TextInstance = number;
59
-
60
-function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
61
- if (typeof node === 'number') {
62
- // Leaf node (eg text)
63
- uncacheFiberNode(node);
64
- } else {
65
- uncacheFiberNode((node: any)._nativeTag);
66
-
67
- (node: any)._children.forEach(recursivelyUncacheFiberNode);
68
- }
69
-}
70
-
71
-const NativeRenderer = ReactFiberReconciler({
72
- appendChild(
73
- parentInstance: Instance | Container,
74
- child: Instance | TextInstance,
75
- ): void {
76
- const childTag = typeof child === 'number' ? child : child._nativeTag;
77
-
78
- if (typeof parentInstance === 'number') {
79
- // Root container
80
- UIManager.setChildren(
81
- parentInstance, // containerTag
82
- [childTag], // reactTags
83
- );
84
- } else {
85
- const children = parentInstance._children;
86
-
87
- const index = children.indexOf(child);
88
-
89
- if (index >= 0) {
90
- children.splice(index, 1);
91
- children.push(child);
92
-
93
- UIManager.manageChildren(
94
- parentInstance._nativeTag, // containerTag
95
- [index], // moveFromIndices
96
- [children.length - 1], // moveToIndices
97
- [], // addChildReactTags
98
- [], // addAtIndices
99
- [], // removeAtIndices
100
- );
101
- } else {
102
- children.push(child);
103
-
104
- UIManager.manageChildren(
105
- parentInstance._nativeTag, // containerTag
106
- [], // moveFromIndices
107
- [], // moveToIndices
108
- [childTag], // addChildReactTags
109
- [children.length - 1], // addAtIndices
110
- [], // removeAtIndices
111
- );
112
- }
113
- }
114
- },
115
-
116
- appendInitialChild(
117
- parentInstance: Instance,
118
- child: Instance | TextInstance,
119
- ): void {
120
- parentInstance._children.push(child);
121
- },
122
-
123
- commitTextUpdate(
124
- textInstance: TextInstance,
125
- oldText: string,
126
- newText: string,
127
- ): void {
128
- UIManager.updateView(
129
- textInstance, // reactTag
130
- 'RCTRawText', // viewName
131
- {text: newText}, // props
132
- );
133
- },
134
-
135
- commitMount(
136
- instance: Instance,
137
- type: string,
138
- newProps: Props,
139
- internalInstanceHandle: Object,
140
- ): void {
141
- // Noop
142
- },
143
-
144
- commitUpdate(
145
- instance: Instance,
146
- updatePayloadTODO: Object,
147
- type: string,
148
- oldProps: Props,
149
- newProps: Props,
150
- internalInstanceHandle: Object,
151
- ): void {
152
- const viewConfig = instance.viewConfig;
153
-
154
- updateFiberProps(instance._nativeTag, newProps);
155
-
156
- const updatePayload = ReactNativeAttributePayload.diff(
157
- oldProps,
158
- newProps,
159
- viewConfig.validAttributes,
160
- );
161
-
162
- UIManager.updateView(
163
- instance._nativeTag, // reactTag
164
- viewConfig.uiViewClassName, // viewName
165
- updatePayload, // props
166
- );
167
- },
168
-
169
- createInstance(
170
- type: string,
171
- props: Props,
172
- rootContainerInstance: Container,
173
- hostContext: {},
174
- internalInstanceHandle: Object,
175
- ): Instance {
176
- const tag = ReactNativeTagHandles.allocateTag();
177
- const viewConfig = ReactNativeViewConfigRegistry.get(type);
178
-
179
- if (__DEV__) {
180
- for (const key in viewConfig.validAttributes) {
181
- if (props.hasOwnProperty(key)) {
182
- deepFreezeAndThrowOnMutationInDev(props[key]);
183
- }
184
- }
185
- }
186
-
187
- const updatePayload = ReactNativeAttributePayload.create(
188
- props,
189
- viewConfig.validAttributes,
190
- );
191
-
192
- UIManager.createView(
193
- tag, // reactTag
194
- viewConfig.uiViewClassName, // viewName
195
- rootContainerInstance, // rootTag
196
- updatePayload, // props
197
- );
198
-
199
- const component = new ReactNativeFiberHostComponent(tag, viewConfig);
200
-
201
- precacheFiberNode(internalInstanceHandle, tag);
202
- updateFiberProps(tag, props);
203
-
204
- // Not sure how to avoid this cast. Flow is okay if the component is defined
205
- // in the same file but if it's external it can't see the types.
206
- return ((component: any): Instance);
207
- },
208
-
209
- createTextInstance(
210
- text: string,
211
- rootContainerInstance: Container,
212
- hostContext: {},
213
- internalInstanceHandle: Object,
214
- ): TextInstance {
215
- const tag = ReactNativeTagHandles.allocateTag();
216
-
217
- UIManager.createView(
218
- tag, // reactTag
219
- 'RCTRawText', // viewName
220
- rootContainerInstance, // rootTag
221
- {text: text}, // props
222
- );
223
-
224
- precacheFiberNode(internalInstanceHandle, tag);
225
-
226
- return tag;
227
- },
228
-
229
- finalizeInitialChildren(
230
- parentInstance: Instance,
231
- type: string,
232
- props: Props,
233
- rootContainerInstance: Container,
234
- ): boolean {
235
- // Don't send a no-op message over the bridge.
236
- if (parentInstance._children.length === 0) {
237
- return false;
238
- }
239
-
240
- // Map from child objects to native tags.
241
- // Either way we need to pass a copy of the Array to prevent it from being frozen.
242
- const nativeTags = parentInstance._children.map(
243
- child =>
244
- (typeof child === 'number'
245
- ? child // Leaf node (eg text)
246
- : child._nativeTag),
247
- );
248
-
249
- UIManager.setChildren(
250
- parentInstance._nativeTag, // containerTag
251
- nativeTags, // reactTags
252
- );
253
-
254
- return false;
255
- },
256
-
257
- getRootHostContext(): {} {
258
- return emptyObject;
259
- },
260
-
261
- getChildHostContext(): {} {
262
- return emptyObject;
263
- },
264
-
265
- getPublicInstance(instance) {
266
- return instance;
267
- },
268
-
269
- insertBefore(
270
- parentInstance: Instance | Container,
271
- child: Instance | TextInstance,
272
- beforeChild: Instance | TextInstance,
273
- ): void {
274
- // TODO (bvaughn): Remove this check when...
275
- // We create a wrapper object for the container in ReactNative render()
276
- // Or we refactor to remove wrapper objects entirely.
277
- // For more info on pros/cons see PR #8560 description.
278
- invariant(
279
- typeof parentInstance !== 'number',
280
- 'Container does not support insertBefore operation',
281
- );
282
-
283
- const children = (parentInstance: any)._children;
284
-
285
- const index = children.indexOf(child);
286
-
287
- // Move existing child or add new child?
288
- if (index >= 0) {
289
- children.splice(index, 1);
290
- const beforeChildIndex = children.indexOf(beforeChild);
291
- children.splice(beforeChildIndex, 0, child);
292
-
293
- UIManager.manageChildren(
294
- (parentInstance: any)._nativeTag, // containerID
295
- [index], // moveFromIndices
296
- [beforeChildIndex], // moveToIndices
297
- [], // addChildReactTags
298
- [], // addAtIndices
299
- [], // removeAtIndices
300
- );
301
- } else {
302
- const beforeChildIndex = children.indexOf(beforeChild);
303
- children.splice(beforeChildIndex, 0, child);
304
-
305
- const childTag = typeof child === 'number' ? child : child._nativeTag;
306
-
307
- UIManager.manageChildren(
308
- (parentInstance: any)._nativeTag, // containerID
309
- [], // moveFromIndices
310
- [], // moveToIndices
311
- [childTag], // addChildReactTags
312
- [beforeChildIndex], // addAtIndices
313
- [], // removeAtIndices
314
- );
315
- }
316
- },
317
-
318
- prepareForCommit(): void {
319
- // Noop
320
- },
321
-
322
- prepareUpdate(
323
- instance: Instance,
324
- type: string,
325
- oldProps: Props,
326
- newProps: Props,
327
- rootContainerInstance: Container,
328
- hostContext: {},
329
- ): null | Object {
330
- return emptyObject;
331
- },
332
-
333
- removeChild(
334
- parentInstance: Instance | Container,
335
- child: Instance | TextInstance,
336
- ): void {
337
- recursivelyUncacheFiberNode(child);
338
-
339
- if (typeof parentInstance === 'number') {
340
- UIManager.manageChildren(
341
- parentInstance, // containerID
342
- [], // moveFromIndices
343
- [], // moveToIndices
344
- [], // addChildReactTags
345
- [], // addAtIndices
346
- [0], // removeAtIndices
347
- );
348
- } else {
349
- const children = parentInstance._children;
350
- const index = children.indexOf(child);
351
-
352
- children.splice(index, 1);
353
-
354
- UIManager.manageChildren(
355
- parentInstance._nativeTag, // containerID
356
- [], // moveFromIndices
357
- [], // moveToIndices
358
- [], // addChildReactTags
359
- [], // addAtIndices
360
- [index], // removeAtIndices
361
- );
362
- }
363
- },
364
-
365
- resetAfterCommit(): void {
366
- // Noop
367
- },
368
-
369
- resetTextContent(instance: Instance): void {
370
- // Noop
371
- },
372
-
373
- shouldDeprioritizeSubtree(type: string, props: Props): boolean {
374
- return false;
375
- },
376
-
377
- scheduleAnimationCallback: global.requestAnimationFrame,
378
-
379
- scheduleDeferredCallback: global.requestIdleCallback,
380
-
381
- shouldSetTextContent(props: Props): boolean {
382
- // TODO (bvaughn) Revisit this decision.
383
- // Always returning false simplifies the createInstance() implementation,
384
- // But creates an additional child Fiber for raw text children.
385
- // No additional native views are created though.
386
- // It's not clear to me which is better so I'm deferring for now.
387
- // More context @ github.com/facebook/react/pull/8560#discussion_r92111303
388
- return false;
389
- },
390
-
391
- useSyncScheduling: true,
392
-});
393
-
36
ReactGenericBatching.injection.injectFiberBatchedUpdates(
395
- NativeRenderer.batchedUpdates,
37
+ ReactNativeFiberRenderer.batchedUpdates,
38
);
39
40
const roots = new Map();
41
400
-findNodeHandle.injection.injectFindNode((fiber: Fiber) =>
401
- NativeRenderer.findHostInstance(fiber),
402
-);
403
-findNodeHandle.injection.injectFindRootNodeID(instance => instance);
404
-
42
// Intercept lifecycle errors and ensure they are shown with the correct stack
43
// trace within the native redbox component.
44
ReactFiberErrorLogger.injection.injectDialog(
45
ReactNativeFiberErrorDialog.showDialog,
46
);
47
411
-const ReactNative = {
412
- // External users of findNodeHandle() expect the host tag number return type.
413
- // The injected findNodeHandle() strategy returns the instance wrapper though.
414
- // See NativeMethodsMixin#setNativeProps for more info on why this is done.
415
- findNodeHandle(componentOrHandle: any): ?number {
416
- const instance: any = findNodeHandle(componentOrHandle);
417
- if (instance == null || typeof instance === 'number') {
418
- return instance;
419
- }
420
- return instance._nativeTag;
421
- },
48
+var ReactNative: ReactNativeType = {
49
+ findNodeHandle: findNumericNodeHandle,
50
51
render(element: Element<any>, containerTag: any, callback: ?Function) {
52
let root = roots.get(containerTag);
54
if (!root) {
55
// TODO (bvaughn): If we decide to keep the wrapper component,
56
// We could create a wrapper for containerTag as well to reduce special casing.
429
- root = NativeRenderer.createContainer(containerTag);
57
+ root = ReactNativeFiberRenderer.createContainer(containerTag);
58
roots.set(containerTag, root);
59
}
432
- NativeRenderer.updateContainer(element, root, null, callback);
60
+ ReactNativeFiberRenderer.updateContainer(element, root, null, callback);
61
434
- return NativeRenderer.getPublicRootInstance(root);
62
+ return ReactNativeFiberRenderer.getPublicRootInstance(root);
63
},
64
65
unmountComponentAtNode(containerTag: number) {
66
const root = roots.get(containerTag);
67
if (root) {
68
// TODO: Is it safe to reset this now or should I wait since this unmount could be deferred?
441
- NativeRenderer.updateContainer(null, root, null, () => {
69
+ ReactNativeFiberRenderer.updateContainer(null, root, null, () => {
70
roots.delete(containerTag);
71
});
72
}
88
},
89
90
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
91
+
92
+ __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
93
+ // Used as a mixin in many createClass-based components
94
+ NativeMethodsMixin: require('NativeMethodsMixin'),
95
+
96
+ // Used by react-native-github/Libraries/ components
97
+ ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
98
+ ReactNativeComponentTree: require('ReactNativeComponentTree'), // InspectorUtils, ScrollResponder
99
+ ReactNativePropRegistry: require('ReactNativePropRegistry'), // flattenStyle, Stylesheet
100
+ TouchHistoryMath: require('TouchHistoryMath'), // PanResponder
101
+ createReactNativeComponentClass: require('createReactNativeComponentClass'), // eg Text
102
+ takeSnapshot: require('takeSnapshot'), // react-native-implementation
103
+ },
104
};
105
106
+if (__DEV__) {
107
+ // $FlowFixMe
108
+ Object.assign(
109
+ ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
110
+ {
111
+ ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace
112
+ ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf
113
+ },
114
+ );
115
+}
116
+
117
if (typeof injectInternals === 'function') {
118
injectInternals({
119
findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
468
- findHostInstanceByFiber: NativeRenderer.findHostInstance,
120
+ findHostInstanceByFiber: ReactNativeFiberRenderer.findHostInstance,
121
getInspectorDataForViewTag: ReactNativeFiberInspector.getInspectorDataForViewTag,
122
// This is an enum because we may add more (e.g. profiler build)
123
bundleType: __DEV__ ? 1 : 0,