From ab26fd5eb211ab8bc840dff234911ec196cada80 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 19 Jun 2018 13:41:42 +0100 Subject: [PATCH] Inline fbjs/lib/emptyObject (#13055) * Inline fbjs/lib/emptyObject * Explicit naming * Compare to undefined * Another approach for detecting whether we can mutate Each renderer would have its own local LegacyRefsObject function. While in general we don't want `instanceof`, here it lets us do a simple check: did *we* create the refs object? Then we can mutate it. If the check didn't pass, either we're attaching ref for the first time (so we know to use the constructor), or (unlikely) we're attaching a ref to a component owned by another renderer. In this case, to avoid "losing" refs, we assign them onto the new object. Even in that case it shouldn't "hop" between renderers anymore. * Clearer naming * Add test case for strings refs across renderers * Use a shared empty object for refs by reading it from React * Remove string refs from ReactART test It's not currently possible to resetModules() between several renderers without also resetting the `React` module. However, that leads to losing the referential identity of the empty ref object, and thus subsequent checks in the renderers for whether it is pooled fail (and cause assignments to a frozen object). This has always been the case, but we used to work around it by shimming fbjs/lib/emptyObject in tests and preserving its referential identity. This won't work anymore because we've inlined it. And preserving referential identity of React itself wouldn't be great because it could be confusing during testing (although we might want to revisit this in the future by moving its stateful parts into a separate package). For now, I'm removing string ref usage from this test because only this is the only place in our tests where we hit this problem, and it's only related to string refs, and not just ref mechanism in general. * Simplify the condition --- src/ReactShallowRenderer.js | 6 +++++- src/ReactTestHostConfig.js | 15 +++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/ReactShallowRenderer.js b/src/ReactShallowRenderer.js index 817e3dc..65020d4 100644 --- a/src/ReactShallowRenderer.js +++ b/src/ReactShallowRenderer.js @@ -11,10 +11,14 @@ import {isForwardRef} from 'react-is'; import describeComponentFrame from 'shared/describeComponentFrame'; import getComponentName from 'shared/getComponentName'; import shallowEqual from 'shared/shallowEqual'; -import emptyObject from 'fbjs/lib/emptyObject'; import invariant from 'fbjs/lib/invariant'; import checkPropTypes from 'prop-types/checkPropTypes'; +const emptyObject = {}; +if (__DEV__) { + Object.freeze(emptyObject); +} + class ReactShallowRenderer { static createRenderer = function() { return new ReactShallowRenderer(); diff --git a/src/ReactTestHostConfig.js b/src/ReactTestHostConfig.js index 560011a..1a1e74a 100644 --- a/src/ReactTestHostConfig.js +++ b/src/ReactTestHostConfig.js @@ -7,8 +7,6 @@ * @flow */ -import emptyObject from 'fbjs/lib/emptyObject'; - import * as TestRendererScheduling from './ReactTestRendererScheduling'; export type Type = string; @@ -35,11 +33,16 @@ export type HostContext = Object; export type UpdatePayload = Object; export type ChildSet = void; // Unused -const UPDATE_SIGNAL = {}; - export * from 'shared/HostConfigWithNoPersistence'; export * from 'shared/HostConfigWithNoHydration'; +const NO_CONTEXT = {}; +const UPDATE_SIGNAL = {}; +if (__DEV__) { + Object.freeze(NO_CONTEXT); + Object.freeze(UPDATE_SIGNAL); +} + export function getPublicInstance(inst: Instance | TextInstance): * { switch (inst.tag) { case 'INSTANCE': @@ -88,7 +91,7 @@ export function removeChild( export function getRootHostContext( rootContainerInstance: Container, ): HostContext { - return emptyObject; + return NO_CONTEXT; } export function getChildHostContext( @@ -96,7 +99,7 @@ export function getChildHostContext( type: string, rootContainerInstance: Container, ): HostContext { - return emptyObject; + return NO_CONTEXT; } export function prepareForCommit(containerInfo: Container): void {