Here's the helper I use: (updated to work for React <16 and 16+)
function FindReact(dom, traverseUp = 0) {
const key = Object.keys(dom).find(key=>{
return key.startsWith("__reactFiber$") // react 17+
|| key.startsWith("__reactInternalInstance$"); // react <17
});
const domFiber = dom[key];
if (domFiber == null) return null;
// react <16
if (domFiber._currentElement) {
let compFiber = domFiber._currentElement._owner;
for (let i = 0; i < traverseUp; i++) {
compFiber = compFiber._currentElement._owner;
}
return compFiber._instance;
}
// react 16+
const GetCompFiber = fiber=>{
//return fiber._debugOwner; // this also works, but is __DEV__ only
let parentFiber = fiber.return;
while (typeof parentFiber.type == "string") {
parentFiber = parentFiber.return;
}
return parentFiber;
};
let compFiber = GetCompFiber(domFiber);
for (let i = 0; i < traverseUp; i++) {
compFiber = GetCompFiber(compFiber);
}
return compFiber.stateNode;
}
Usage:
const someElement = document.getElementById("someElement");
const myComp = FindReact(someElement);
myComp.setState({test1: test2});
Note: This version is longer than the other answers, because it contains code to traverse-up from the component directly wrapping the dom-node. (without this code, the FindReact function would fail for some common cases, as seen below)
Bypassing in-between components
Let's say the component you want to find (MyComp
) looks like this:
class MyComp extends Component {
render() {
return (
<InBetweenComp>
<div id="target">Element actually rendered to dom-tree.</div>
</InBetweenComp>
);
}
}
In this case, calling FindReact(target)
will (by default) return the InBetweenComp
instance instead, since it's the first component ancestor of the dom-element.
To resolve this, increase the traverseUp
argument until you find the component you wanted:
const target = document.getElementById("target");
const myComp = FindReact(target, 1); // provide traverse-up distance here
For more details on traversing the React component tree, see here.
Function components
Function components don't have "instances" in the same way classes do, so you can't just modify the FindReact
function to return an object with forceUpdate
, setState
, etc. on it for function components.
That said, you can at least obtain the React-fiber node for that path, containing its props, state, and such. To do so, modify the last line of the FindReact
function to just: return compFiber;