这是我使用的助手:(更新为适用于 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
函数返回一个对象forceUpdate
,setState
就可以了,等的功能部件。
也就是说,您至少可以获取该路径的 React-fiber 节点,包含其props、状态等。为此,将FindReact
函数的最后一行修改为:return compFiber;