React - getting a component from a DOM element for debugging

前端 未结 10 1031
广开言路
广开言路 2020-11-28 19:02

For the purposes of debugging in the console, is there any mechanism available in React to use a DOM element instance to get the backing React component?

This questi

相关标签:
10条回答
  • 2020-11-28 19:54

    i wrote this small hack to enable access any react component from its dom node

    var ReactDOM = require('react-dom');
    (function () {
        var _render = ReactDOM.render;
        ReactDOM.render = function () {
            return arguments[1].react = _render.apply(this, arguments);
        };
    })();
    

    then you can access any component directly using:

    document.getElementById("lol").react
    

    or using JQuery

    $("#lol").get(0).react
    
    0 讨论(0)
  • 2020-11-28 19:56

    Install React devtools and use following, to access react element of corresponding dom node ($0).

    for 0.14.8

        var findReactNode = (node) =>Object.values(__REACT_DEVTOOLS_GLOBAL_HOOK__.helpers)[0]
    .getReactElementFromNative(node)
    ._currentElement;
           findReactNode($0);
    

    Ofcourse, its a hack only..

    0 讨论(0)
  • 2020-11-28 19:59

    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=>key.startsWith("__reactInternalInstance$"));
        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;

    0 讨论(0)
  • 2020-11-28 19:59

    React 16+ version:

    If you want the nearest React component instance that the selected DOM element belongs to, here's how you can find it (modified from @Guan-Gui's solution):

    window.getComponentFromElement = function(el) {
      for (const key in el) {
        if (key.startsWith('__reactInternalInstance$')) {
          const fiberNode = el[key];
          return fiberNode && fiberNode._debugOwner && fiberNode._debugOwner.stateNode;
        }
      }
      return null;
    };
    

    They trick here is to use the _debugOwner property, which is a reference to the FiberNode of the nearest component that the DOM element is part of.

    Caveat: Only running in dev mode will the components have the _debugOwner property. This would not work in production mode.

    Bonus

    I created this handy snippet that you can run in your console so that you can click on any element and get the React component instance it belongs to.

    document.addEventListener('click', function(event) {
      const el = event.target;
      for (const key in el) {
        if (key.startsWith('__reactInternalInstance$')) {
          const fiberNode = el[key];
          const component = fiberNode && fiberNode._debugOwner;
          if (component) {
            console.log(component.type.displayName || component.type.name);
            window.$r = component.stateNode;
          }
          return;
        }
      }
    });
    
    0 讨论(0)
提交回复
热议问题