React - getting a component from a DOM element for debugging

前端 未结 10 1030
广开言路
广开言路 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:36

    I've adapted @Venryx's answer with a slightly adapted ES6 version that fit my needs. This helper function returns the current element instead of the _owner._instance property.

    getReactDomComponent(dom) {
      const internalInstance = dom[Object.keys(dom).find(key =>
        key.startsWith('__reactInternalInstance$'))];
      if (!internalInstance) return null;
      return internalInstance._currentElement;
    }
    
    0 讨论(0)
  • 2020-11-28 19:37

    I've just read through the docs, and afaik none of the externally-exposed APIs will let you directly go in and find a React component by ID. However, you can update your initial React.render() call and keep the return value somewhere, e.g.:

    window.searchRoot = React.render(React.createElement......
    

    You can then reference searchRoot, and look through that directly, or traverse it using the React.addons.TestUtils. e.g. this will give you all the components:

    var componentsArray = React.addons.TestUtils.findAllInRenderedTree(window.searchRoot, function() { return true; });
    

    There are several built-in methods for filtering this tree, or you can write your own function to only return components based on some check you write.

    More about TestUtils here: https://facebook.github.io/react/docs/test-utils.html

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

    Here is a small snippet i'm currently using.

    It works with React 0.14.7.

    Gist with the code

    let searchRoot = ReactDom.render(ROOT, document.getElementById('main'));
    
    var getComponent = (comp) => comp._renderedComponent ? getComponent(comp._renderedComponent) : comp;
    
    var getComponentById = (id)=> {
      var comp = searchRoot._reactInternalInstance;
      var path = id.substr(1).split('.').map(a=> '.' + a);
      if (comp._rootNodeID !== path.shift()) throw 'Unknown root';
      while (path.length > 0) {
        comp = getComponent(comp)._renderedChildren[path.shift()];
      }
      return comp._instance;
    };
    
    window.$r = (node)=> getComponentById(node.getAttribute('data-reactid'))

    to run it, open Devtools, highlight an element you want to examine, and in the console type : $r($0)

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

    v15 and v16 compatible with svg, html, comment, text nodes

    /* Node extends text, svg, html
     usage for node $0:
        $0.reactive // returns [node, parentNode, rootNode]
        $0.react.props // {any:'prop'}
        $0.react.setState(...) // update
     */
    Object.defineProperties(Node.prototype, {
        _react: {writable:true, value:''}
        ,reactKey: {
            get: function(){
                let symbol = this._react;
                if(symbol){ return symbol; }
                // v15, v16 use a string as key, probably a real symbol in the future
                symbol = Object.keys(this).find(key => key.startsWith('__reactInternalInstance$'));
                return Node.prototype._react = symbol || '';
            }
        }
        // try to find the props/state/React-instance
        ,react: {
            get: function(){
                let react = this[ this.reactKey ] || null;
                let $0;
                if(react){
                    $0 = react._currentElement;
                    if($0){ // v15
                        if($0._owner){
                            return $0._owner._instance;
                        }else{
                            return $0;
                        };
                    }
                    $0 = react.return;
                    if($0){ // v16
                        // develop mode only: return react._debugOwner.stateNode
                        // both develop and prod modes:
                        return $0.stateNode
                    }
                }else if(this._reactRootContainer){
                    // v16 _internalRoot === _internalRoot.current.stateNode
                    return this._reactRootContainer._internalRoot;
                }
                return react;
            }
        }
        // make a list of self, ancestors that make up this branch of the tree
        ,reactive: {
            get: function(list=[]){
                let $0 = this;
                while($0 && !$0[ $0.reactKey ] && !$0._reactRootContainer ){
                    $0 = $0.previousSibling;
                };
                if($0 && ($0[$0.reactKey] || $0._reactRootContainer)){
                    list.push($0);
                };
                $0 = this;
                while($0 = $0.parentNode){
                    if($0[ $0.reactKey ] || $0._reactRootContainer){
                        list.push($0);
                    }
                };
                return list;
            }
        }
    });
    
    0 讨论(0)
  • 2020-11-28 19:44

    In case someone is struggling like me to access React component/properties from a chrome extension, all of the above solutions are not going to work from chrome extension content-script. Rather, you'll have to inject a script tag and run your code from there. Here is complete explanation: https://stackoverflow.com/a/9517879/2037323

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

    Here you go. This supports React 16+

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

    0 讨论(0)
提交回复
热议问题