React - 从 DOM 元素获取组件以进行调试

IT技术 javascript reactjs
2021-01-23 14:27:09

出于在控制台中调试的目的,React 中是否有任何可用的机制来使用 DOM 元素实例来获取支持的 React 组件?

之前在生产代码中使用它的上下文中已经问过这个问题。但是,我的重点是用于调试目的的开发构建。

我熟悉ReactChrome 调试扩展,但并非在所有浏览器中都可用。结合 DOM 资源管理器和控制台,可以轻松使用“$0”快捷方式来访问有关突出显示的 DOM 元素的信息。

我想在调试控制台中编写类似这样的代码:getComponentFromElement($0).props

即使在 React 开发构建中,也没有机制可以使用元素的 ReactId 来获取组件吗?

6个回答

这是我使用的助手:(更新为适用于 React <16 和 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;
}

用法:

const someElement = document.getElementById("someElement");
const myComp = FindReact(someElement);
myComp.setState({test1: test2});

注意:此版本比其他答案更长,因为它包含从直接包装 dom-node 的组件向上遍历的代码。(如果没有此代码,FindReact 函数将在某些常见情况下失败,如下所示)

绕过中间组件

假设您要查找的组件 ( MyComp) 如下所示:

class MyComp extends Component {
    render() {
        return (
            <InBetweenComp>
                <div id="target">Element actually rendered to dom-tree.</div>
            </InBetweenComp>
        );
    }
}

在这种情况下,调用FindReact(target)将(默认情况下)返回InBetweenComp实例,因为它是 dom 元素的第一个组件祖先。

要解决此问题,请增加traverseUp参数直到找到所需的组件:

const target = document.getElementById("target");
const myComp = FindReact(target, 1);   // provide traverse-up distance here

有关遍历 React 组件树的更多详细信息,请参见此处

功能组件

功能组件没有“实例”以同样的方式类的事情,所以你不能只修改FindReact函数返回一个对象forceUpdatesetState就可以了,等的功能部件。

也就是说,您至少可以获取该路径的 React-fiber 节点,包含其props、状态等。为此,将FindReact函数的最后一行修改为return compFiber;

很棒的解决方案,对我帮助很大
2021-03-19 14:27:09
惊人!实现别人说的不可能!
2021-03-21 14:27:09
(您可以FindReact($0)通过右键单击> Inspect 来选择元素
2021-03-23 14:27:09
它从控制台对我有用,但是当我尝试从我的 chrome 扩展中使用相同的扩展时,Object.keys对于同一个 htmlnode 是空的。有什么建议?
2021-03-26 14:27:09
当补丁render不是一个选项时,这是解决方案(例如通过脚本注入增强页面)。
2021-04-10 14:27:09

干得好。这支持 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;
};

对我来说 stateNode 还不够,但这有效: el._debugOwner.stateNode.constructor.name
2021-03-23 14:27:09
这只会{containerInfo: body, pendingChildren: null, implementation: null}为我返回此外,constructor.name 是Object
2021-03-30 14:27:09
这是最新的工作解决方案!一个警告 - 如果el不是组件的根元素,则不起作用
2021-04-01 14:27:09

我刚刚通读了文档,我相信没有任何一个对外公开的 API 会让你直接进入并通过 ID 找到一个 React 组件。但是,您可以更新初始React.render()调用并将返回值保留在某处,例如:

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

然后,您可以引用 searchRoot,并直接查看它,或使用React.addons.TestUtils. 例如,这将为您提供所有组件:

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

有几种内置的方法可以过滤这棵树,或者您可以编写自己的函数以仅根据您编写的某些检查返回组件。

更多关于 TestUtils 的信息:https ://facebook.github.io/react/docs/test-utils.html

完美的。TestUtils 机制正好提供了我正在寻找的东西。现在在我的调试版本中,我可以提供一个全局函数,我可以在控制台中使用该函数搜索返回的组件列表并将其与所选元素匹配。
2021-04-14 14:27:09

我写了这个小技巧来允许从它的 dom 节点访问任何react组件

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

然后您可以使用以下命令直接访问任何组件:

document.getElementById("lol").react

或使用 JQuery

$("#lol").get(0).react
这太棒了,谢谢!例如,假设我使用了这段代码,并想使用普通的 javascript 设置反应组件的道具,我将如何反应重绘组件?例如,假设我有 element.react.props.config.sunhat.enabled=false; 我怎么能得到那个元素来更新/渲染?我试过 element.react.render() 但这似乎没有用,有什么想法吗?
2021-03-17 14:27:09

如果有人像我一样努力从 chrome 扩展访问 React 组件/属性,上述所有解决方案都不适用于 chrome 扩展内容脚本。相反,您必须注入一个脚本标记并从那里运行您的代码。这里是完整的解释:https : //stackoverflow.com/a/9517879/2037323

非常喜欢站出来💟
2021-04-12 14:27:09