react-nativescript
Version:
React renderer for NativeScript
128 lines • 6.47 kB
JavaScript
import { Application, } from "@nativescript/core";
import { __unstable__forwardNavOpts } from "./nativescript-vue-next/runtime/navigation";
export { __unstable__forwardNavOpts };
import { LegacyRoot } from "react-reconciler/constants";
import * as console from "./shared/Logger";
import { reactReconcilerInst } from "./client/HostConfig";
import { createPortal as _createPortal } from "./client/ReactPortal";
import { NSVRoot, NSVElement, NSVNode, NSVComment, NSVText, } from "./nativescript-vue-next/runtime/nodes";
import { markContainerAsRoot } from "./client/ComponentTree";
export { NSVRoot, NSVElement, NSVNode, NSVComment, NSVText };
const { version: ReactNativeScriptVersion } = require("../package.json");
export { registerElement } from "./nativescript-vue-next/runtime/registry";
export { ListView } from "./components/ListView";
export { StyleSheet } from "./client/StyleSheet";
// declare global {
// var __DEV__: boolean|undefined;
// }
// declare let __DEV__: boolean|undefined;
// https://blog.atulr.com/react-custom-renderer-1/
export function createPortal(children,
// ReactFabric passes in a containerTag rather than a container; hope it can figure out how to re-use a root when the container is null :/
container, key = null) {
// invariant(
// isValidContainer(container),
// 'Target container is not a DOM element.',
// );
// TODO (from Facebook): pass ReactDOM portal implementation as third argument
const portal = _createPortal(children, container, null, key);
// console.log(`Created portal:`, portal);
return portal;
}
const roots = new Map();
const defaultOnRecoverableError = typeof reportError === "function"
? // In modern browsers, reportError will dispatch an error event,
// emulating an uncaught JavaScript error.
reportError
: (error) => {
// In older browsers and test environments, fallback to console.error.
// eslint-disable-next-line react-internal/no-production-logging, react-internal/warning-args
console.error(error);
};
/**
* React NativeScript can render into any container that extends View,
* but it makes sense to use the Frame > Page model if your whole app
* (rather than a portion of it) will be described using React NativeScript.
*
* @param reactElement - Your <App/> component.
* @param domElement - Your root component; typically Page, but can be any View. Accepts null for a detached tree.
* @param callback - A callback to run after the component (typically <App/>) is rendered.
* @param containerTag - A unique key by which to keep track of the root (useful when the domElement is null).
* 'roots' with reference to: https://github.com/facebook/react/blob/ef4ac42f8893afd0240d2679db7438f1b599bbd4/packages/react-native-renderer/src/ReactFabric.js#L119
* @returns a ref to the container.
*/
export function render(reactElement, domElement, callback = () => undefined, containerTag = null, strictMode) {
const key = containerTag || domElement;
let root = roots.get(key);
if (!root) {
const hydrationCallbacks = null;
const identifierPrefix = "";
const concurrentUpdatesByDefaultOverride = null;
const onRecoverableError = defaultOnRecoverableError;
const transitionCallbacks = null;
root = reactReconcilerInst.createContainer(domElement,
// TODO: Update to ConcurrentRoot
LegacyRoot, hydrationCallbacks, !!strictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks);
markContainerAsRoot(root.current, domElement);
roots.set(key, root);
}
reactReconcilerInst.updateContainer(reactElement, root, null, callback);
return reactReconcilerInst.getPublicRootInstance(root);
}
// https://github.com/facebook/react/blob/61f62246c8cfb76a4a19d1661eeaa5822ec37b36/packages/react-native-renderer/src/ReactNativeRenderer.js#L139
/**
* Calls removeChildFromContainer() to make the container remove its immediate child.
* If said container is null (i.e. a detached tree), note that null.removeChild() doesn't exist, so it's a no-op.
* Either way, it'll delete our reference to the root and thus should remove the React association from it.
* @param containerTag - the key uniquely identifying this root (either the container itself, or a string).
*/
export function unmountComponentAtNode(containerTag) {
const root = roots.get(containerTag);
if (!root)
return;
// TODO (from FB): Is it safe to reset this now or should I wait since this unmount could be deferred?
reactReconcilerInst.updateContainer(null, root, null, () => {
roots.delete(containerTag);
});
}
/*
* https://github.com/reduxjs/react-redux/issues/1392
* https://github.com/facebook/react/blob/b15bf36750ca4c4a5a09f2de76c5315ded1258d0/packages/react-native-renderer/src/ReactNativeRenderer.js#L230
*/
export const unstable_batchedUpdates = reactReconcilerInst.batchedUpdates;
/**
* Convenience function to start your React NativeScript app.
* This should be placed as the final line of your app.ts file, as no
* code will run after it (at least on iOS).
*
* @param app - Your <App/> component.
*/
export function start(app) {
const existingRootView = Application.getRootView();
const _hasLaunched = Application.hasLaunched();
console.log(`[ReactNativeScript.ts] start(). hasLaunched(): ${_hasLaunched} existing rootView was: ${existingRootView}`);
if (_hasLaunched || existingRootView) {
console.log(`[ReactNativeScript.ts] start() called again - hot reload, so shall no-op`);
/* As typings say, indeed reloadPage() doesn't exist. Maybe it's just a Vue thing. */
// if(existingRootView instanceof Frame){
// console.log(`[renderIntoRootView] hot reload: calling reloadPage() on root frame`);
// if(existingRootView.currentPage){
// (existingRootView as any).reloadPage();
// }
// }
return;
}
reactReconcilerInst.injectIntoDevTools({
bundleType: __DEV__ ? 1 : 0,
rendererPackageName: "react-nativescript",
version: ReactNativeScriptVersion,
});
Application.run({
create: () => {
const root = new NSVRoot();
render(app, root, () => console.log(`Container updated!`), "__APP_ROOT__");
return root.baseRef.nativeView;
},
});
}
//# sourceMappingURL=index.js.map