chrome.devtools.network.onRequestFinished 事件踩坑指南
- 回调函数无法使用变更变量坑
- addListener removeListener 使用坑
回调函数无法使用变更变量坑
chrome.devtools.network.onRequestFinished.addListener 传入的回调处理函数发生变化后不生效,如下写法是有问题的
let listenering = false
const Component: React.FC = () => {
const [grabing, setGrabing] = useState<boolean>(false);
const [filterKeyList, setFilterKeyList] = useState<FilterKeyList[]>();
const activeFilter = useMemo(() => filterKeyList.filter(item => item.switch && item.value), [filterKeyList]);
const handleListener = useCallback((details: RequestFinished) => {
try {
const {
_resourceType,
request: { method },
} = details;
if (activeFilter?.length === 0 || !grabing || _resourceType !== 'xhr') return;
if (activeFilter?.some(item => method === item.method)) {
details.getContent(content => console.log('content=', content));
}
} catch (e) {
console.log('糟糕,出错了!!!');
}
}, [grabing, activeFilter]);
useEffect(() => {
if(!listenering){
chrome.devtools.network.onRequestFinished.addListener(handleListener);
listenering = true;
}
}, [handleListener]);
return (
<h1>demo</h1>
);
};
问题1:addListener 的回调处理函数 handleListener 不随着 grabing, activeFilter 变化
原因:回调触发时对应的值是当时 addListener 实际的值,不随着外部变量变化而变化
解决:当 activeFilter 和 grabing 改变时需要调用 addListener 重新监听
当需要重新监听时,就需要对之前的 addListener 进行 removeListener 处理,否则会产生多个监听进程,就有了下边的问题2
addListener removeListener 使用坑
问题2:调用 removeListener 无法取消监听
原因:chrome.devtools.network.onRequestFinished.removeListener() 需要一个参数,不是直接执行就取消监听了,且参数需要和当初 addListener 定义的同一个回调函数,因为 grabing, activeFilter 变化后,handleListener 就是一个新的函数了,所以无法取消监听
方案:将 addListener 使用的 handleListener 通过 useRef 存起来,每次需要重新监听的时候先把上一个移除,再次发起监听的时候将当时使用的 handleListener 再次存入 useRef 即可解决,代码如下:
const Component: React.FC = () => {
const [grabing, setGrabing] = useState<boolean>(false);
const [filterKeyList, setFilterKeyList] = useState<FilterKeyList[]>();
const handleListenerRef = useRef<(details: RequestFinished) => void>();
const activeFilter = useMemo(() => filterKeyList.filter(item => item.switch && item.value), [filterKeyList]);
const handleListener = useCallback((details: RequestFinished, grabing: boolean, activeFilter: FilterKeyList[]) => {
try {
const {
_resourceType,
request: { method },
} = details;
if (activeFilter?.length === 0 || !grabing || _resourceType !== 'xhr') return;
if (activeFilter?.some(item => method === item.method)) {
details.getContent(content => console.log('content=', content));
}
} catch (e) {
console.log('糟糕,出错了!!!');
}
}, []);
useEffect(() => {
if (handleListenerRef.current) {
chrome.devtools.network.onRequestFinished.removeListener(handleListenerRef.current);
}
if (activeFilter?.length === 0 || !grabing) return;
const listener = (datails: RequestFinished) => handleListener(datails, grabing, activeFilter);
handleListenerRef.current = listener;
chrome.devtools.network.onRequestFinished.addListener(listener);
}, [activeFilter, grabing, handleListener]);
return (
<h1>demo</h1>
);
};
总结:
问题:
- addListener 执行时回调函数 handleListener 是什么就是什么,即便后来 handleListener 变了监听事件触发时也是使用的定义时传入的
- removeListener 不是一个直接执行的函数,执行完就取消监听了,而是需要一个参数,且参数需要和当时 addListener 使用的一样,必须是同一个变量
方案: - 每次回调函数变化时重新进行监听
- 将监听函数存起来,用于 removeListener 的参数