Is it possible to retrieve a component's instance from a React Fiber?
Asked Answered
T

2

4

Before v16 of React -- that is, before the introduction of React fibers -- it was possible to take a DOM element and retrieve the React component instance as follows:

const getReactComponent = dom => {
  let found = false;
  const keys = Object.keys(dom);

  keys.forEach(key => {
    if (key.startsWith('__reactInternalInstance$')) {
      const compInternals = dom[key]._currentElement;
      const compWrapper = compInternals._owner;
      const comp = compWrapper._instance;
      found = comp;
    }
  });

  return found || null;
};

This no longer works for React v16, which uses the new Fiber implementation. Specifically, the above code throws an error at the line const comparWrapper = compInternals._owner because there is no _owner property anymore. Thus you cannot also access the _instance.

My question here is how would we retrieve the instance from a DOM element in v16's Fiber implementation?

Triste answered 7/11, 2017 at 19:35 Comment(7)
Why not React devtools?Rizika
Possible duplicate of reactjs object doesn't have key __reactInternalInstanceGarrote
@AbdennourTOUMI: that isn't a duplicate as that person isn't dealing with the difference between React pre v16.Triste
@OriDrori: Do you care to elaborate?Triste
React devtools allow gives you the ability to inspect react elements in the chrome console.Rizika
@OriDrori: That's true, but that's not what I need to do. I need to retrieve the component object programmatically from a DOM element that contains a component.Triste
"In some rare cases I need to inspect a React component that has been rendered into the DOM" :) Anyway - they do it grammatically, and the code of the tool might have what you're looking for.Rizika
B
3

You may try the function below (updated to work for React <16 and 16+):

window.FindReact = function(dom) {
    let key = Object.keys(dom).find(key=>key.startsWith("__reactInternalInstance$"));
    let internalInstance = dom[key];
    if (internalInstance == null) return null;

    if (internalInstance.return) { // react 16+
        return internalInstance._debugOwner
            ? internalInstance._debugOwner.stateNode
            : internalInstance.return.stateNode;
    } else { // react <16
        return internalInstance._currentElement._owner._instance;
    }
}

Usage:

var someElement = document.getElementById("someElement");
FindReact(someElement).setState({test1: test2});
Basaltware answered 21/11, 2019 at 6:42 Comment(1)
It can not work when env is productionMurillo
J
0

React 17 is slightly different:

function findReact(dom) {
    let key = Object.keys(dom).find(key => key.startsWith("__reactFiber$"));
    let internalInstance = dom[key];
    if (internalInstance == null) return "internalInstance is null: " + key;

    if (internalInstance.return) { // react 16+
        return internalInstance._debugOwner
            ? internalInstance._debugOwner.stateNode
           : internalInstance.return.stateNode;
    } else { // react <16
        return internalInstance._currentElement._owner._instance;
   }
}

the domElement in this is the tr with the data-param-name of the field you are trying to change:

var domElement = ?.querySelectorAll('tr[data-param-name="<my field name>"]')
Jenn answered 22/7, 2022 at 12:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.