Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使状态与快速发生的事件保持同步_Javascript_Reactjs_Typescript_Sockets_React Hooks - Fatal编程技术网

Javascript 使状态与快速发生的事件保持同步

Javascript 使状态与快速发生的事件保持同步,javascript,reactjs,typescript,sockets,react-hooks,Javascript,Reactjs,Typescript,Sockets,React Hooks,我制作了一个自定义钩子来跟踪一个状态变量,该状态变量基于收到的套接字事件的数量。 当我同时发送10个事件进行测试时,状态变量total的结果不是预期的10,而是6、7或8 const useSocketAmountReceivedState=(事件:字符串):number=>{ const[total,setTotal]=useState(0); useffect(()=>{ Socket.on(事件,()=>{ 控制台日志(总计); setTotal(总计+1); }); return():v

我制作了一个自定义钩子来跟踪一个状态变量,该状态变量基于收到的套接字事件的数量。 当我同时发送10个事件进行测试时,状态变量total的结果不是预期的10,而是6、7或8

const useSocketAmountReceivedState=(事件:字符串):number=>{
const[total,setTotal]=useState(0);
useffect(()=>{
Socket.on(事件,()=>{
控制台日志(总计);
setTotal(总计+1);
});
return():void=>{
插座关闭(事件);
};
});
返回总数;
}
运行日志看起来像

0
1
1
2
3
3
4
4
4
5
上述示例中的
Socket
是围绕websocket的实现


因此,我可以推断total的更新速度不够快,但处理这种行为的最佳模式是什么?

尝试将空数组作为钩子中的第二个参数。您不希望每次渲染组件时都注册一个事件

const useSocketAmountReceivedState = (event: string): number => {
    const [total, setTotal] = useState(0);

    useEffect(() => {
        Socket.on(event, () => {
            console.log(total);
            setTotal(total + 1);
        });

        return (): void => {
            Socket.off(event);
        };
    }, [total]);

    return total;
}
更新:

我更新了我的初始答案,并将Total添加到React钩子的依赖项数组中。

请注意,第二个参数,也称为依赖项数组。它是一个接受状态或属性的数组。每次依赖关系数组中的任何元素发生更改时,它都会指示React运行这个钩子

如果传递一个空数组,那么钩子将仅在组件挂载后的初始加载时运行

在您的示例中,如果传递一个空数组,它将创建一个闭包。因此,总值始终为初始值


因此,您可以将Total传递到依赖项数组中,该数组将调用useffect()以仅在Total值更改时运行。在您的示例中,如果没有将依赖项数组传递给第二个参数,那么useffect()将每次运行,这不是我们想要的。

Socket.on事件必须在useffect函数之外

const useSocketAmountReceivedState = (event: string): number => {
    const [total, setTotal] = useState(0);
    Socket.on(event, () => {
        console.log(total);
        setTotal(total + 1);
    });
    useEffect(() => {
        return (): void => {
            Socket.off(event);
        };
    }, []);

    return total;
}

一位同事提出了这个解决方案。 使用一个引用,因为它是一个引用,并不是封闭的

const useSocketAmountReceivedState = (event: string): number => {
    const count = useRef(0);
    const [state, setState] = useState(0);

    useEffect(() => {
        Socket.on(event, () => {
            count.current++;
            setState(count.current);
        });

        return (): void => {
            Socket.off(event);
        };
    }, []);

    return state;
}

我不确定这是否有帮助,但请尝试:
setTotal(prevTotal=>prevTotal+1)Socket.on事件必须在useEffect函数之外。请确保不要在每次渲染时运行useEffect()。为此,请为useffect()中的第二个参数添加一个空数组。感谢@EdsonMagombe的快速回复,您能解释一下原因吗?是否因为状态更改后,
useffect
只会再次“更新”
total
?否。很简单。您正在创建一个事件套接字。每次调用useEffect时都会打开。所以你有很多Socket.on printing通过查看这个问题,我想说有一种可能性,提问者并不确定依赖项是如何工作的,因此可能需要更新你的答案来解释这一点,并解释useEffect函数将在每次依赖项更改时执行,而且几乎一直都是这样(至少在我的经验中)不放置任何依赖项(即方括号)将导致useEffect无限期地反复执行自己。添加了更多细节:)我刚刚测试了这种方法。在这种情况下,我相信
0
total
的初始值包含在回调中。因此,这导致每次将总计更新为1。这与原来的问题相同,总计没有像应该的那样频繁地“更改”,而是滞后。虽然这种方式可以工作,但它也经常调用
on
函数。实际上,经常对其重新绑定太多了,这是一个巨大的性能打击,似乎没有必要。注意,您必须将其设置在一个只调用一次的位置。如果您多次使用useSocketAmountReceivedState。这将使事件成倍增加,因此您必须将其删除到某个位置,确保它只运行一次。如果您共享您的代码,我可能会帮助您``const Demo=():ReactElement=>{const topicUpdates=useSocketAmountReceivedState('topic-test');return({topicUpdates})};````你建议把它包起来吗?不,可以。你们有主课吗?在同一个文件中?