Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - getting a component from a DOM element for debugging

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 question has been asked previously in the context of using it in production code. However, my focus is on development builds for the purpose of debugging.

I'm familiar with the Chrome debugging extension for React, however this isn't available in all browsers. Combining the DOM explorer and console it is easy to use the '$0' shortcut to access information about the highlighted DOM element.

I would like to write code something like this in the debugging console: getComponentFromElement($0).props

Even in a the React development build is there no mechanism to use maybe the element's ReactId to get at the component?

like image 715
LodeRunner28 Avatar asked Mar 28 '15 19:03

LodeRunner28


People also ask

How do you get the DOM React component?

Access a DOM Element Using ReactDOM.findDOMNode() . findDOMNode() is used to find a specific node from the DOM tree and access its various properties, such as its inner HTML, child elements, type of element, etc. In short, it can return all the supported DOM measurements related to the kind of element.

How do you inspect the component of a React?

Open the console by either right-clicking and inspecting an element or by opening the toolbar by clicking View > Developer > JavaScript console. The Components tab will show the current React component tree, along with any props, state, or context.

How do you call a component on render?

Calling render method programmatically not possible. You have to do state update of that particular component if you want to call render method of that component. Say,if you want to call render method of Dashboard Component,you must call setState on this component. You can do some dummy state lifting for that.


2 Answers

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;

like image 146
Venryx Avatar answered Oct 18 '22 16:10

Venryx


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;  };
like image 36
Guan Gui Avatar answered Oct 18 '22 15:10

Guan Gui