Chrome扩展开发:如何从React页面获取reactInstance?
解决Chrome扩展中使用findReact函数抓取React页面数据的问题
我之前做Chrome扩展抓取React站点数据时,也踩过类似的坑,结合你的场景,咱们一步步拆解问题和可行的解决办法:
一、先排查核心问题:React内部属性的版本变化
你提到的__reactInternalInstance是React早期版本的内部属性,但从React 16开始,官方为了避免外部依赖内部实现,对这些属性做了混淆处理:
- 属性名会带上随机后缀,比如变成
__reactInternalInstance$abc123 - 后续版本甚至改用了
__reactFiber$xxx作为Fiber节点的标识
如果Steemit-More-Info扩展里的findReact函数是针对旧版React写的,自然会失效。
二、修改findReact函数适配新版本React
可以把原函数改成匹配带后缀的内部属性,同时兼容Fiber节点:
function findReact(domElement) { // 查找React内部实例或Fiber节点的属性 const reactKey = Object.keys(domElement).find(key => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$') ); return reactKey ? domElement[reactKey] : null; }
三、从Fiber节点中提取组件数据
拿到Fiber节点后,它可能只是DOM对应的叶子节点,需要向上遍历Fiber树找到包含业务数据的组件实例:
function getTargetComponent(fiberNode) { let currentFiber = fiberNode; // 向上遍历,直到找到包含props/state的组件节点 while (currentFiber) { if (currentFiber.stateNode && typeof currentFiber.stateNode === 'object') { return currentFiber.stateNode; } currentFiber = currentFiber.return; } return null; } // 使用示例 const walletDom = document.querySelector('.UserWallet'); const reactFiber = findReact(walletDom); const walletComponent = getTargetComponent(reactFiber); // 类组件可直接访问state/props if (walletComponent.state) { console.log('钱包状态:', walletComponent.state); } // 函数组件的状态存在memoizedState中,需根据实际结构解析 if (walletComponent.memoizedState) { console.log('函数组件状态:', walletComponent.memoizedState); }
四、解决Chrome扩展上下文隔离问题
如果你的扩展是在内容脚本上下文运行,直接访问DOM的React内部属性会有问题——内容脚本和主页面的JS对象是隔离的。这时候需要把查找代码注入到主页面上下文:
// 内容脚本中执行 chrome.scripting.executeScript({ target: { tabId: chrome.devtools.inspectedWindow.tabId }, func: () => { const walletDom = document.querySelector('.UserWallet'); const reactKey = Object.keys(walletDom).find(key => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$') ); const fiber = reactKey ? walletDom[reactKey] : null; let currentFiber = fiber; while (currentFiber) { if (currentFiber.stateNode?.props) { // 提取你需要的具体数据,比如余额、地址 return { balance: currentFiber.stateNode.props.balance, walletAddress: currentFiber.stateNode.props.address }; } currentFiber = currentFiber.return; } return null; } }, (results) => { if (results[0].result) { console.log('抓取到的钱包数据:', results[0].result); // 在这里处理拿到的数据 } });
最后提醒
依赖React内部属性是不稳定的方案,官方随时可能修改内部实现。如果目标网站有公开API,优先调用API获取数据;如果没有,再用这种方法,同时要做好不同React版本的兼容测试。
内容的提问来源于stack exchange,提问作者cedric_g
相关产品推荐
相关产品推荐

