UNPKG

react-find-dom-node

Version:

React 19 removed ReactDOM.findDOMNode so this fixes that

250 lines (213 loc) 5.65 kB
import type { Fiber } from "react-reconciler"; type WorkTag = | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31; const HostRoot = 3; // Root of a host tree. Could be nested inside another node. const HostComponent = 5; const HostText = 6; const HostHoistable = 26; const HostSingleton = 27; const NoFlags = /* */ 0b0000000000000000000000000000000; const Placement = /* */ 0b0000000000000000000000000000010; const Hydrating = /* */ 0b0000000000000000001000000000000; function getNearestMountedFiber(fiber: Fiber): null | Fiber { let node = fiber; let nearestMounted: null | Fiber = fiber; if (!fiber.alternate) { // If there is no alternate, this might be a new tree that isn't inserted // yet. If it is, then it will have a pending insertion effect on it. let nextNode: null | Fiber = node; do { node = nextNode; if ((node.flags & (Placement | Hydrating)) !== NoFlags) { // This is an insertion or in-progress hydration. The nearest possible // mounted fiber is the parent but we need to continue to figure out // if that one is still mounted. nearestMounted = node.return; } // $FlowFixMe[incompatible-type] we bail out when we get a null nextNode = node.return; } while (nextNode); } else { while (node.return) { node = node.return; } } if (node.tag === HostRoot) { // TODO: Check if this was a nested HostRoot when used with // renderContainerIntoSubtree. return nearestMounted; } // If we didn't hit the root, that means that we're in an disconnected tree // that has been unmounted. return null; } function assertIsMounted(fiber: Fiber) { if (getNearestMountedFiber(fiber) !== fiber) { throw new Error("Unable to find node on an unmounted component."); } } function findCurrentFiberUsingSlowPath(fiber: Fiber): Fiber | null { const alternate = fiber.alternate; if (!alternate) { const nearestMounted = getNearestMountedFiber(fiber); if (nearestMounted !== fiber) { return null; } return fiber; } let a: Fiber = fiber; let b: Fiber = alternate; for (;;) { const parentA = a.return; if (parentA === null) { break; } const parentB = parentA.alternate; if (parentB === null) { const nextParent = parentA.return; if (nextParent !== null) { a = b = nextParent; continue; } break; } if (parentA.child === parentB.child) { let child = parentA.child; while (child) { if (child === a) { assertIsMounted(parentA); return fiber; } if (child === b) { assertIsMounted(parentA); return alternate; } child = child.sibling; } throw new Error("Unable to find node on an unmounted component."); } if (a.return !== b.return) { a = parentA; b = parentB; } else { let didFindChild = false; let child = parentA.child; while (child) { if (child === a) { didFindChild = true; a = parentA; b = parentB; break; } if (child === b) { didFindChild = true; b = parentA; a = parentB; break; } child = child.sibling; } if (!didFindChild) { child = parentB.child; while (child) { if (child === a) { didFindChild = true; a = parentB; b = parentA; break; } if (child === b) { didFindChild = true; b = parentB; a = parentA; break; } child = child.sibling; } if (!didFindChild) { throw new Error("Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue."); } } } } if (a.tag !== HostRoot) { throw new Error("Unable to find node on an unmounted component."); } if (a.stateNode.current === a) { return fiber; } return alternate; } function findCurrentHostFiberImpl(node: Fiber): Fiber | null { // Next we'll drill down this component to find the first HostComponent/Text. const tag = node.tag as WorkTag; if ( tag === HostComponent || tag === HostHoistable || tag === HostSingleton || tag === HostText ) { return node; } let child = node.child; while (child !== null) { const match = findCurrentHostFiberImpl(child); if (match !== null) { return match; } child = child.sibling; } return null; } function findCurrentHostFiber(parent: Fiber): Fiber | null { const currentParent = findCurrentFiberUsingSlowPath(parent); return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null; } export function findDOMNode(component: React.Component | React.PureComponent) { const reactInternals = (component as unknown as { _reactInternals: Fiber | undefined })._reactInternals; if (reactInternals === undefined) { if (typeof component.render === "function") { throw new Error("Unable to find node on an unmounted component."); } throw new Error(`Argument appears to not be a ReactComponent. Keys: ${Object.keys(component).join(",")}`); } const hostFiber = findCurrentHostFiber(reactInternals); if (hostFiber === null) { return null; } return hostFiber.stateNode; }