mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Allocate unique reactTags for RN and Fabric (#12587)
Took this opportunity to remove some abstract overhead. In Fabric it is extra simple since they no longer overlap with root tags.
This commit is contained in:
+11
-3
@@ -20,7 +20,6 @@ import * as ReactNativeAttributePayload from './ReactNativeAttributePayload';
|
||||
import * as ReactNativeFrameScheduling from './ReactNativeFrameScheduling';
|
||||
import * as ReactNativeViewConfigRegistry from './ReactNativeViewConfigRegistry';
|
||||
import ReactFiberReconciler from 'react-reconciler';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
import deepFreezeAndThrowOnMutationInDev from 'deepFreezeAndThrowOnMutationInDev';
|
||||
import emptyObject from 'fbjs/lib/emptyObject';
|
||||
@@ -30,6 +29,12 @@ import TextInputState from 'TextInputState';
|
||||
import FabricUIManager from 'FabricUIManager';
|
||||
import UIManager from 'UIManager';
|
||||
|
||||
// Counter for uniquely identifying views.
|
||||
// % 10 === 1 means it is a rootTag.
|
||||
// % 2 === 0 means it is a Fabric tag.
|
||||
// This means that they never overlap.
|
||||
let nextReactTag = 2;
|
||||
|
||||
/**
|
||||
* This is used for refs on host components.
|
||||
*/
|
||||
@@ -133,7 +138,9 @@ const ReactFabricRenderer = ReactFiberReconciler({
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): Instance {
|
||||
const tag = ReactNativeTagHandles.allocateTag();
|
||||
const tag = nextReactTag;
|
||||
nextReactTag += 2;
|
||||
|
||||
const viewConfig = ReactNativeViewConfigRegistry.get(type);
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -171,7 +178,8 @@ const ReactFabricRenderer = ReactFiberReconciler({
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): TextInstance {
|
||||
const tag = ReactNativeTagHandles.allocateTag();
|
||||
const tag = nextReactTag;
|
||||
nextReactTag += 2;
|
||||
|
||||
const node = FabricUIManager.createNode(
|
||||
tag, // reactTag
|
||||
|
||||
@@ -13,7 +13,6 @@ import {batchedUpdates} from 'events/ReactGenericBatching';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import {getInstanceFromNode} from './ReactNativeComponentTree';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
import type {AnyNativeEvent} from 'events/PluginModuleType';
|
||||
|
||||
@@ -166,7 +165,7 @@ export function receiveTouches(
|
||||
let rootNodeID = null;
|
||||
const target = nativeEvent.target;
|
||||
if (target !== null && target !== undefined) {
|
||||
if (target < ReactNativeTagHandles.tagsStartAt) {
|
||||
if (target < 1) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
} from './ReactNativeComponentTree';
|
||||
import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';
|
||||
import * as ReactNativeFrameScheduling from './ReactNativeFrameScheduling';
|
||||
import ReactNativeTagHandles from './ReactNativeTagHandles';
|
||||
|
||||
type Container = number;
|
||||
export type Instance = {
|
||||
@@ -36,6 +35,19 @@ export type Instance = {
|
||||
type Props = Object;
|
||||
type TextInstance = number;
|
||||
|
||||
// Counter for uniquely identifying views.
|
||||
// % 10 === 1 means it is a rootTag.
|
||||
// % 2 === 0 means it is a Fabric tag.
|
||||
let nextReactTag = 3;
|
||||
function allocateTag() {
|
||||
let tag = nextReactTag;
|
||||
if (tag % 10 === 1) {
|
||||
tag += 2;
|
||||
}
|
||||
nextReactTag = tag + 2;
|
||||
return tag;
|
||||
}
|
||||
|
||||
function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
|
||||
if (typeof node === 'number') {
|
||||
// Leaf node (eg text)
|
||||
@@ -62,7 +74,7 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): Instance {
|
||||
const tag = ReactNativeTagHandles.allocateTag();
|
||||
const tag = allocateTag();
|
||||
const viewConfig = ReactNativeViewConfigRegistry.get(type);
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -101,7 +113,7 @@ const NativeRenderer = ReactFiberReconciler({
|
||||
hostContext: {},
|
||||
internalInstanceHandle: Object,
|
||||
): TextInstance {
|
||||
const tag = ReactNativeTagHandles.allocateTag();
|
||||
const tag = allocateTag();
|
||||
|
||||
UIManager.createView(
|
||||
tag, // reactTag
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
/**
|
||||
* Keeps track of allocating and associating native "tags" which are numeric,
|
||||
* unique view IDs. All the native tags are negative numbers, to avoid
|
||||
* collisions, but in the JS we keep track of them as positive integers to store
|
||||
* them effectively in Arrays. So we must refer to them as "inverses" of the
|
||||
* native tags (that are * normally negative).
|
||||
*
|
||||
* It *must* be the case that every `rootNodeID` always maps to the exact same
|
||||
* `tag` forever. The easiest way to accomplish this is to never delete
|
||||
* anything from this table.
|
||||
* Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to
|
||||
* unmount a component with a `rootNodeID`, then mount a new one in its place,
|
||||
*/
|
||||
const INITIAL_TAG_COUNT = 1;
|
||||
const ReactNativeTagHandles = {
|
||||
tagsStartAt: INITIAL_TAG_COUNT,
|
||||
tagCount: INITIAL_TAG_COUNT,
|
||||
|
||||
allocateTag: function(): number {
|
||||
// Skip over root IDs as those are reserved for native
|
||||
while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) {
|
||||
ReactNativeTagHandles.tagCount++;
|
||||
}
|
||||
const tag = ReactNativeTagHandles.tagCount;
|
||||
ReactNativeTagHandles.tagCount++;
|
||||
return tag;
|
||||
},
|
||||
|
||||
assertRootTag: function(tag: number): void {
|
||||
invariant(
|
||||
this.reactTagIsNativeTopRootID(tag),
|
||||
'Expect a native root tag, instead got %s',
|
||||
tag,
|
||||
);
|
||||
},
|
||||
|
||||
reactTagIsNativeTopRootID: function(reactTag: number): boolean {
|
||||
// We reserve all tags that are 1 mod 10 for native root views
|
||||
return reactTag % 10 === 1;
|
||||
},
|
||||
};
|
||||
|
||||
export default ReactNativeTagHandles;
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
// Mock of the Native Hooks
|
||||
|
||||
const ReactNativeTagHandles = require('../ReactNativeTagHandles').default;
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
// Map of viewTag -> {children: [childTag], parent: ?parentTag}
|
||||
@@ -18,7 +17,7 @@ let views = new Map();
|
||||
|
||||
function autoCreateRoot(tag) {
|
||||
// Seriously, this is how we distinguish roots in RN.
|
||||
if (!views.has(tag) && ReactNativeTagHandles.reactTagIsNativeTopRootID(tag)) {
|
||||
if (!views.has(tag) && tag % 10 === 1) {
|
||||
roots.push(tag);
|
||||
views.set(tag, {
|
||||
children: [],
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('ReactNative', () => {
|
||||
expect(UIManager.createView.mock.calls.length).toBe(1);
|
||||
expect(UIManager.setChildren.mock.calls.length).toBe(1);
|
||||
expect(UIManager.manageChildren).not.toBeCalled();
|
||||
expect(UIManager.updateView).toBeCalledWith(2, 'View', {foo: 'bar'});
|
||||
expect(UIManager.updateView).toBeCalledWith(3, 'View', {foo: 'bar'});
|
||||
});
|
||||
|
||||
it('should not call UIManager.updateView after render for properties that have not changed', () => {
|
||||
|
||||
Reference in New Issue
Block a user