react-native
Version:
A framework for building native apps using React
140 lines (117 loc) • 4.22 kB
JavaScript
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactFiberHostContext
* @flow
*/
;
import type { Fiber } from 'ReactFiber';
import type { HostConfig } from 'ReactFiberReconciler';
import type { StackCursor } from 'ReactFiberStack';
const emptyObject = require('fbjs/lib/emptyObject');
const {
createCursor,
pop,
push,
} = require('ReactFiberStack');
const invariant = require('fbjs/lib/invariant');
export type HostContext<C, CX> = {
getHostContext() : CX,
getRootHostContainer() : C,
popHostContainer(fiber : Fiber) : void,
popHostContext(fiber : Fiber) : void,
pushHostContainer(fiber : Fiber, container : C) : void,
pushHostContext(fiber : Fiber) : void,
resetHostContainer() : void,
};
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
config : HostConfig<T, P, I, TI, PI, C, CX, PL>
) : HostContext<C, CX> {
const {
getChildHostContext,
getRootHostContext,
} = config;
let contextStackCursor : StackCursor<CX | null> = createCursor((null: ?CX));
let contextFiberStackCursor : StackCursor<Fiber | null> = createCursor((null: Fiber | null));
let rootInstanceStackCursor : StackCursor<C | null> = createCursor((null: ?C));
function getRootHostContainer() : C {
const rootInstance = rootInstanceStackCursor.current;
invariant(
rootInstance !== null,
'Expected root container to exist. This error is likely caused by a ' +
'bug in React. Please file an issue.'
);
return rootInstance;
}
function pushHostContainer(fiber : Fiber, nextRootInstance : C) {
// Push current root instance onto the stack;
// This allows us to reset root when portals are popped.
push(rootInstanceStackCursor, nextRootInstance, fiber);
const nextRootContext = getRootHostContext(nextRootInstance);
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextRootContext, fiber);
}
function popHostContainer(fiber : Fiber) {
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
pop(rootInstanceStackCursor, fiber);
}
function getHostContext() : CX {
const context = contextStackCursor.current;
invariant(
context != null,
'Expected host context to exist. This error is likely caused by a bug ' +
'in React. Please file an issue.'
);
return context;
}
function pushHostContext(fiber : Fiber) : void {
const rootInstance = rootInstanceStackCursor.current;
invariant(
rootInstance != null,
'Expected root host context to exist. This error is likely caused by ' +
'a bug in React. Please file an issue.'
);
const context = contextStackCursor.current !== null ?
contextStackCursor.current :
emptyObject;
const nextContext = getChildHostContext(context, fiber.type, rootInstance);
// Don't push this Fiber's context unless it's unique.
if (context === nextContext) {
return;
}
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextContext, fiber);
}
function popHostContext(fiber : Fiber) : void {
// Do not pop unless this Fiber provided the current context.
// pushHostContext() only pushes Fibers that provide unique contexts.
if (contextFiberStackCursor.current !== fiber) {
return;
}
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
}
function resetHostContainer() {
contextStackCursor.current = null;
rootInstanceStackCursor.current = null;
}
return {
getHostContext,
getRootHostContainer,
popHostContainer,
popHostContext,
pushHostContainer,
pushHostContext,
resetHostContainer,
};
};