我正在使用socket.io和react.js。我需要为套接字声明一些事件处理程序,而且由于我正在使用某些模块,所以我不能使用经典的类组件,因此我将函数与挂钩一起使用。问题是使用useEffect钩子初始化事件处理程序会导致每次发生新的渲染时都要重新声明套接字事件处理程序,因此,每个事件都与一堆事件处理程序(而不是一个事件处理程序)连接在一起,这导致需要多次调用事件发生时的事件处理程序。有一种方法可以使useEffect只运行一次;将空数组作为第二个参数传递给它(这种方法使它像类组件中的构造函数一样)。这样可以防止对事件处理程序的多次调用,但是,这也可以防止事件处理程序访问组件的最新状态。有办法实现两者吗?
var socket = io('http://localhost:10000');
const [var, setvar] = useState(0);
useEffect(() => {
socket.on('event', function(data) { //event handler function
console.log(var);
});
}, []);
为进一步说明,上面的代码每个事件仅调用事件处理程序函数一次,但始终输出var的初始状态,该状态为0。另一方面,如果删除了[]参数,则处理程序将输出var的当前值,但会多次输出,因为对于每个渲染,一个新的事件处理程序都已连接到套接字,因此输出数量取决于该事件之前发生的渲染数量。
答案 0 :(得分:0)
您可以输入[dependency]而不是方括号,例如[isInit]。仅当isInit的值更改时,效果才会运行。您应该使用useState声明isInit并将其默认设置为false,即const [isInit,setIsInit] = useState(false)。然后,当您第一次运行useEffect时,请设置setIsInit(true)。然后在useEffect中检查是否(!isInit)...这样可以很好地控制它。
答案 1 :(得分:0)
您可以尝试将自己的物品与useRef
结合使用,例如:
var socket = io('http://localhost:10000');
const [var, setvar] = useState(0);
const ref = useRef({current: var});
const alteredSetvar = useCallback((var) => {
setvar(var);
ref.current = var;
}, [setvar, ref]);
useEffect(() => {
socket.on('event', function(data) { //event handler function
console.log(ref.current);
});
}, []);
我认为可以(调用alteredSetvar
而不是setvar
。
useRef
通常用于保存对DOM节点的引用,但实际上,它仅包含不可变的引用,您可以根据需要更改其内部值