【发布时间】:2021-09-27 17:57:19
【问题描述】:
我有一个功能组件,它应该在页面加载以及页面刷新时订阅事件,并在每次组件卸载时取消订阅。我想为此使用 useEffect ,不幸的是没有成功。第一次尝试移除事件监听器并在每次传递新事件时再次添加事件监听器:
import { useEffect } from 'react';
import { useSnackbar } from '../../context/SnackbarContext';
import { parseRigData } from '../data.utils';
import sse from '../../lib/sse';
export function useRig(config) {
const { openSnackbar } = useSnackbar();
useEffect(() => {
const createListeners = () => {
const newListeners = {};
config.forEach(instance => {
const { name, handleData, showMessage, type } = instance;
newListeners[name] = ({ data }) => {
// eslint-disable-next-line no-console
console.log('[RIG] received', JSON.parse(data, 0, 2));
const messageBody = parseRigData(data);
handleData(messageBody);
if (showMessage) {
const message = showMessage(messageBody);
if (message) openSnackbar(message, type);
}
};
});
return newListeners;
};
const initializeListeners = listeners => {
config.forEach(instance => {
const { events, name } = instance;
sse.listenForUserMessage(events, listeners[name]);
});
};
const removeListeners = listeners => {
config.forEach(instance => {
const { events, name } = instance;
sse.removeListener(events, listeners[name]);
});
};
const createConnection = async (events, listeners) => {
if (!events.length) return;
await sse.connect(events);
initializeListeners(listeners);
};
function getEvents() {
const result = [];
config.forEach(instance => {
const { events, config } = instance;
result.push({
eventTypes: events,
config
});
});
return result;
}
const events = getEvents();
const listeners = createListeners();
createConnection(events, listeners);
return () => {
removeListeners(listeners);
if (events.length) sse.disconnect(events);
};
}, [config, openSnackbar]);
}
我理解这种行为 - 每次组件更新时都会发生这种情况。这就是为什么我试图通过从 useEffect-array 中删除 config 和 openSnackbar 来解决这个问题,该数组定义了正在监视哪些更改以使 useEffect 发生:
export function useRig(config) {
const { openSnackbar } = useSnackbar();
useEffect(() => {
// ...same code
return () => {
removeListeners(listeners);
if (events.length) sse.disconnect(events);
};
}, []);
}
不幸的是,当我使用 f5 重新加载页面时,这不起作用。在这种情况下,事件不会被传递(“无法在未安装的组件上执行 React 状态更新),并且不会删除来自返回清理的侦听器。否则,在正常页面加载或离开页面时它工作得很好。
有什么方法可以包含页面重新加载(但不是 componentUpdate)来执行 useEffect?
【问题讨论】:
-
页面加载、重新加载和刷新本质上是同义词。具有依赖关系的
useEffect是componentDidMount和componentDidUpdate。您是否只想要componentDidMount行为? -
我猜这个案例需要的是类似于 componentDidMount 和 componentWillUnmount 的行为
-
那是
useEffect具有空依赖和返回的清理函数,这就是你所说的对你不起作用。events值会在组件的整个生命周期内发生变化吗? -
不,事件值 - 我订阅的事件,在组件的生命周期内不会改变。我不明白为什么刷新页面时它不起作用。或者应该做什么才能在页面重新加载时也能正常工作。当我通过例如导航栏到达同一页面时,它按预期工作。在第一次加载时,它按预期工作。但不是在页面重新加载时,当我按 F5 时
-
您确定
events值在组件的生命周期内不会改变吗?您提到“第一次尝试删除事件侦听器并在每次传递新事件时再次添加事件侦听器”。新事件来自哪里,config对象?还是config.events是要订阅的静态事件数组?据我所知,events在回调范围内被关闭,所以我不明白为什么清理函数没有events?正在更新什么状态?您的示例代码 sn-ps 中没有?你确定这个代码是问题吗?
标签: javascript reactjs use-effect