React - 从 DOM 元素获取组件以进行调试
React - getting a component from a DOM element for debugging
为了在控制台中进行调试,React 中是否有任何机制可以使用 DOM 元素实例来获取支持的 React 组件?
这个问题之前在生产代码中使用它的上下文中已经提出过。但是,我的重点是用于调试的开发版本。
我熟悉 React 的 Chrome 调试扩展,但这并非在所有浏览器中都可用。结合 DOM 资源管理器和控制台,很容易使用"$0"快捷方式来访问有关突出显示的 DOM 元素的信息。
我想在调试控制台中编写这样的代码:getComponentFromElement($0(.props
即使在 React 开发版本中,也没有机制可以使用元素的 ReactId 来获取组件?
使用的助手:(更新为适用于 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-element 的第一个组件祖先。
若要解决此问题,请增加 traverseUp
参数,直到找到所需的组件:
const target = document.getElementById("target");
const myComp = FindReact(target, 1); // provide traverse-up distance here
有关遍历 React 组件树的更多详细信息,请参见此处。
功能组件
函数组件不像类那样有"实例",所以你不能只修改FindReact
函数来返回一个对象,上面有forceUpdate
、setState
等。
也就是说,您至少可以获得该路径的 React-fiber 节点,其中包含其 props、状态等。为此,请将 FindReact
函数的最后一行修改为:return compFiber;
你去吧。这支持 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;
};
我刚刚通读了文档,并且没有一个外部公开的 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
我写了这个小技巧,以便能够从其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
如果有人像我一样努力从 chrome 扩展程序访问 React 组件/属性,上述所有解决方案都无法从 chrome 扩展程序内容脚本中工作。相反,您必须注入一个脚本标记并从那里运行代码。以下是完整的解释:https://stackoverflow.com/a/9517879/2037323
这是我目前正在使用的一个小片段。
它适用于 React 0.14.7。
代码要点
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'))
要运行它,请打开 Devtools,突出显示要检查的元素,然后在控制台中键入 : $r($0)
我已经用适合我需求的稍微调整的 ES6 版本改编了@Venryx的答案。此帮助程序函数返回当前元素,而不是 _owner._instance 属性。
getReactDomComponent(dom) {
const internalInstance = dom[Object.keys(dom).find(key =>
key.startsWith('__reactInternalInstance$'))];
if (!internalInstance) return null;
return internalInstance._currentElement;
}
React 16+ 版本:
如果你想要所选 DOM 元素所属的最近的 React 组件实例,以下是找到它的方法(根据 @Guan-Gui 的解决方案修改(:
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;
};
他们的诀窍是使用 _debugOwner
属性,该属性是对 DOM 元素所属的最近组件的FiberNode
的引用。
警告:只有在开发模式下运行,组件才会具有 _debugOwner
属性。这在生产模式下不起作用。
奖金
我创建了这个方便的代码片段,您可以在控制台中运行,以便您可以单击任何元素并获取它所属的 React 组件实例。
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;
}
}
});
安装 React devtools 并使用以下命令来访问相应 dom 节点的 react 元素($0(。
对于 0.14.8
var findReactNode = (node) =>Object.values(__REACT_DEVTOOLS_GLOBAL_HOOK__.helpers)[0]
.getReactElementFromNative(node)
._currentElement;
findReactNode($0);
当然,这只是一个黑客。
- React重新渲染但未显示正确的组件
- 不能从angular2中的子组件指定父组件中的数组
- 拨打'父亲'函数形式a'儿童'ReactJS中的组件
- 如何在vs2002中调试html页面
- React组件等待所需道具进行渲染
- 如何创建带有插槽的vue js组件预加载程序
- KnockoutJS-组件-多个实例
- 如何更改reactjs中外部/独立组件的状态或属性
- JS表单提交"无法使用Chrome数据保护程序加载此页面.尝试重新加载页面.调试信息:POST CISmtuK
- 如何在react js中将值从一个组件发送到另一个组件
- React Native通过Navigator将用户输入数据传递到选项卡栏IOS中的组件
- React组件-设置页面标题
- 我的shareService在angular 2中发送值工作正常,但当我渲染我的另一个组件时,会获得默认值
- 如何在salesforce aura闪电组件中使用jQuery.val()
- 为react组件传递道具的最佳方式
- [Vue warn]:未能解析组件
- 如何控制组件'的createContent函数被激发
- React - 从 DOM 元素获取组件以进行调试
- 如何调试附加组件main.js,而不仅仅是Firefox扩展的内容脚本
- 用reactjs调试服务器端渲染组件