lib/reactUtils.js
/** @ignore */
const __ReactProps = {
rootContainer: '_reactRootContainer',
internalRoot: '_internalRoot',
onDomNode: '__reactInternalInstance',
rootHostElemId: 'react-root',
mProps: 'memoizedProps',
};
/**
* Returns the root host element of an react application (id = react-root)
* @param {string} [alternativeId] - An alternative id to use rather than the default
* @return {?HTMLElement}
*/
export function getReactRootHostElem(alternativeId) {
return document.getElementById(
alternativeId != null ? alternativeId : __ReactProps.rootHostElemId
);
}
/**
* Returns the internal root object added by react on the supplied element.
* Property `_internalRoot`
* @param {HTMLElement|Element|Node} elem
* @return {Object}
*/
export function getInternalRootOnElem(elem) {
return elem[__ReactProps.internalRoot];
}
/**
* Returns the root container object added by react
* @param {HTMLElement|Element|Node} elem
* @return {?Object}
*/
export function getReactRootContainer(elem) {
if (!elem) return null;
const hostContainer = elem[__ReactProps.rootContainer];
if (hostContainer) {
return hostContainer[__ReactProps.internalRoot];
}
return null;
}
/**
* Returns the react instance object that lives on the live element
* @param {HTMLElement|Element|Node} elem - The element to have its
* react instance extracted from
* @return {?Object}
*/
export function reactInstanceFromDOMElem(elem) {
const keys = Object.keys(elem);
let len = keys.length;
let internalKey;
for (var i = 0; i < len; ++i) {
if (keys[i].startsWith(__ReactProps.onDomNode)) {
internalKey = keys[i];
break;
}
}
if (!internalKey) return null;
return elem[internalKey];
}
/**
* Converts the supplied array of elements into an array of objects
* each with property node (the live dom element) and reactInstance (the live
* react component). An optional selection function can be supplied that
* receives the rendered components key and returns T/F to indicate if the
* component and element is to be selected
* @param {Array<Node|HTMLElement|Element>} elems - The array of elements to
* get their react instances
* @param {function(key: string): boolean} [selectingFn] - Optional selection
* function that takes a components key and returns T/F indicating if the
* component is selected
* @return {Array<{node: HTMLElement|Element|Node, reactInstance: Object}>}
*/
export function reactInstancesFromElements(elems, selectingFn) {
const renderedNodes = [];
const length = elems.length;
let node;
let reactInstance;
for (var i = 0; i < length; ++i) {
node = elems[i];
reactInstance = reactInstanceFromDOMElem(node);
if (selectingFn && selectingFn(reactInstance.key)) {
renderedNodes.push({ node, reactInstance });
} else {
renderedNodes.push({ node, reactInstance });
}
}
return renderedNodes;
}
/**
* Walks the children of a react component to
* find the one that has the supplied key
* @param {Object} reactInstance - The react instance who's children are
* to be descended looking for the one with key
* @param {string} key - The key of the child to retrieve
* @return {?Object} - The found child if found
*/
export function findChildWithKey(reactInstance, key) {
let child = reactInstance.child;
while (child) {
if (child.key && child.key === key) {
return child;
}
child = child.child;
}
return null;
}
/**
* Attempts the find the redux store from the supplied component
* @param {Object} startingComponent
* @return {?Object}
*/
export function findReduxStore(startingComponent) {
if (!startingComponent) return null;
let component;
const q = [startingComponent];
while (q.length) {
component = q.shift();
if (component.memoizedProps && component.memoizedProps.store) {
return component.memoizedProps.store;
}
if (component.child) {
q.push(component.child);
}
if (component.sibling) {
q.push(component.sibling);
}
}
return null;
}