`useWebSocket` is not available in React 18 Strict Mode
useWebSocket is not available in React 18 Strict Mode
Environment
- React: v18.2.0
- React Dom: v18.2.0
Description
The hook useWebSocket is not available in React 18 Strict Mode:
- The
onOpenand other callback functions provided in parameteroptionsare not invoked; - The
latestMessageandreadyStatereturned byuseWebSockethook are not updated.
In React 17 Strict Mode, none of the above problems occurred.
Demos
useWebSocket in React 18 Strict Mode - not works
useWebSocket in React 17 Strict Mode - works
Root Cause
In React 18, the concept of reusable states was introduced. (ref link)
Therefore, in the React 18 Strict Mode, all components will execute unmount and then mount again, preserving every state at the very first render to check if there's any component assuming it's only mounted or destroyed once. (official docs link)
In the source code of useWebSocket, many internal states are stored using the useRef hook. These states are initialized by the first parameter of the useRef function, which could be a problem in React 18 Strict Mode and later versions of React. Internal states like reconnectTimesRef, unmountedRef etc. will preserve the values from the last call of useWebSocket, which is not what it's expected to be.
For example, In the React 18 Strict Mode, at the very first render, the useWebSocket is called and triggered the mounting stage. Then the useWebSocket is unmounted immediately and then mounted again. At the first unmount process, the state unmountedRef is set to true, but it is not set to false again on the second mount process due to the feature of ensuring-reusable-state. So, when the real WebSocket instance connects, the state unmountedRef is true, which prevents the callback executions like onOpen and state updates like readyState.
The key is all internal states should be explicitly initialized at the mount process.
To fix this problem, I add the explicit initialization procedure of internal states in the useWebSocket at the onMount hook. Furthermore, I notice there's a hook useUnmountedRef in ahooks which handles the initialization of state unmountedRef at the mount stage. So, the state unmountedRef is created by the hook useUnmountedRef rather than explicitly handled by useMount.
All of my modifications have been tested and run correctly now in React 18 Strict Mode. The new code behaves as same as the old one in former React versions. Please review this pull request.
我遇到了同样的问题, 关闭严格模式后能够正常使用
same issue here