@samitouri / QOS-React-2 / commits / e57ad7f51e

Allow returning null as host context (#9278)

If your renderer doesn't use host context, you might prefer to return null. This used to give an error: > Invariant Violation: Expected host context to exist. This error is likely caused by a bug in React. Please file an issue. I use a sentinel value instead now. The code in ReactFiberHostContext is a little complicated now. We could probably also just remove the invariants.

Ben Alpert committed Mar 30, 2017 at 13:18 UTC e57ad7f51ebca844d3e86f43b39989fe95f4b6dd
3 files changed +90 -29
scripts/fiber/tests-passing.txt
+3
@@ -1596,6 +1596,9 @@ src/renderers/shared/fiber/__tests__/ReactCoroutine-test.js
1596 * should unmount a composite in a coroutine
1597 * should handle deep updates in coroutine
1598
1599 +src/renderers/shared/fiber/__tests__/ReactFiberHostContext-test.js
1600 +* works with null host context
1601 +
1602 src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
1603 * should render a simple component
1604 * should render a simple component, in steps if needed
src/renderers/shared/fiber/ReactFiberHostContext.js
+25 -29
@@ -16,8 +16,6 @@ import type {Fiber} from 'ReactFiber';
16 import type {HostConfig} from 'ReactFiberReconciler';
17 import type {StackCursor} from 'ReactFiberStack';
18
19 -const emptyObject = require('fbjs/lib/emptyObject');
20 -
19 const {
20 createCursor,
21 pop,
@@ -26,6 +24,9 @@ const {
24
25 const invariant = require('fbjs/lib/invariant');
26
27 +declare class NoContextT {}
28 +const NO_CONTEXT: NoContextT = ({}: any);
29 +
30 export type HostContext<C, CX> = {
31 getHostContext(): CX,
32 getRootHostContainer(): C,
@@ -44,19 +45,27 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
45 getRootHostContext,
46 } = config;
47
47 - let contextStackCursor: StackCursor<CX | null> = createCursor((null: ?CX));
48 - let contextFiberStackCursor: StackCursor<Fiber | null> = createCursor(
49 - (null: Fiber | null),
48 + let contextStackCursor: StackCursor<CX | NoContextT> = createCursor(
49 + NO_CONTEXT,
50 + );
51 + let contextFiberStackCursor: StackCursor<Fiber | NoContextT> = createCursor(
52 + NO_CONTEXT,
53 + );
54 + let rootInstanceStackCursor: StackCursor<C | NoContextT> = createCursor(
55 + NO_CONTEXT,
56 );
51 - let rootInstanceStackCursor: StackCursor<C | null> = createCursor((null: ?C));
57
53 - function getRootHostContainer(): C {
54 - const rootInstance = rootInstanceStackCursor.current;
58 + function requiredContext<Value>(c: Value | NoContextT): Value {
59 invariant(
56 - rootInstance !== null,
57 - 'Expected root container to exist. This error is likely caused by a ' +
58 - 'bug in React. Please file an issue.',
60 + c !== NO_CONTEXT,
61 + 'Expected host context to exist. This error is likely caused by a bug ' +
62 + 'in React. Please file an issue.',
63 );
64 + return (c: any);
65 + }
66 +
67 + function getRootHostContainer(): C {
68 + const rootInstance = requiredContext(rootInstanceStackCursor.current);
69 return rootInstance;
70 }
71
@@ -80,26 +89,13 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
89 }
90
91 function getHostContext(): CX {
83 - const context = contextStackCursor.current;
84 - invariant(
85 - context != null,
86 - 'Expected host context to exist. This error is likely caused by a bug ' +
87 - 'in React. Please file an issue.',
88 - );
92 + const context = requiredContext(contextStackCursor.current);
93 return context;
94 }
95
96 function pushHostContext(fiber: Fiber): void {
93 - const rootInstance = rootInstanceStackCursor.current;
94 - invariant(
95 - rootInstance != null,
96 - 'Expected root host context to exist. This error is likely caused by ' +
97 - 'a bug in React. Please file an issue.',
98 - );
99 -
100 - const context = contextStackCursor.current !== null
101 - ? contextStackCursor.current
102 - : emptyObject;
97 + const rootInstance = requiredContext(rootInstanceStackCursor.current);
98 + const context = requiredContext(contextStackCursor.current);
99 const nextContext = getChildHostContext(context, fiber.type, rootInstance);
100
101 // Don't push this Fiber's context unless it's unique.
@@ -125,8 +121,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
121 }
122
123 function resetHostContainer() {
128 - contextStackCursor.current = null;
129 - rootInstanceStackCursor.current = null;
124 + contextStackCursor.current = NO_CONTEXT;
125 + rootInstanceStackCursor.current = NO_CONTEXT;
126 }
127
128 return {
src/renderers/shared/fiber/__tests__/ReactFiberHostContext-test.js new
+62
@@ -0,0 +1,62 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +'use strict';
13 +
14 +var React;
15 +var ReactFiberReconciler;
16 +
17 +describe('ReactFiberHostContext', () => {
18 + beforeEach(() => {
19 + jest.resetModules();
20 + React = require('React');
21 + ReactFiberReconciler = require('ReactFiberReconciler');
22 + });
23 +
24 + it('works with null host context', () => {
25 + var creates = 0;
26 + var Renderer = ReactFiberReconciler({
27 + prepareForCommit: function() {},
28 + resetAfterCommit: function() {},
29 + getRootHostContext: function() {
30 + return null;
31 + },
32 + getChildHostContext: function() {
33 + return null;
34 + },
35 + shouldSetTextContent: function() {
36 + return false;
37 + },
38 + createInstance: function() {
39 + creates++;
40 + },
41 + finalizeInitialChildren: function() {
42 + return null;
43 + },
44 + appendInitialChild: function() {
45 + return null;
46 + },
47 + appendChild: function() {
48 + return null;
49 + },
50 + useSyncScheduling: true,
51 + });
52 +
53 + const container = Renderer.createContainer(/* root: */ null);
54 + Renderer.updateContainer(
55 + <a><b /></a>,
56 + container,
57 + /* parentComponent: */ null,
58 + /* callback: */ null,
59 + );
60 + expect(creates).toBe(2);
61 + });
62 +});