Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitac0cf35

Browse files
authored
fix: silence One-Way WebSocket error messages in React Strict Mode (#17204)
## Changes made- Updated `OneWayWebSocket` class to prevent errors from beingdispatched after a connection has been manually closed.- Renamed one of the class properties for less ambiguity- Made error messages for the class constructor more specific
1 parentc418e86 commitac0cf35

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

‎site/src/utils/OneWayWebSocket.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ export class OneWayWebSocket<TData = unknown>
8282
implementsOneWayWebSocketApi<TData>
8383
{
8484
readonly #socket:WebSocket;
85-
readonly #messageCallbackWrappers=newMap<
85+
readonly #errorListeners=newSet<(e:Event)=>void>();
86+
readonly #messageListenerWrappers=newMap<
8687
OneWayEventCallback<TData,"message">,
8788
WebSocketMessageCallback
8889
>();
@@ -98,7 +99,7 @@ export class OneWayWebSocket<TData = unknown>
9899
}=init;
99100

100101
if(!apiRoute.startsWith("/api/v2/")){
101-
thrownewError(`API route '${apiRoute}' does not begin witha slash`);
102+
thrownewError(`API route '${apiRoute}' does not begin with'/api/v2/'`);
102103
}
103104

104105
constformattedParams=
@@ -122,6 +123,10 @@ export class OneWayWebSocket<TData = unknown>
122123
event:TEvent,
123124
callback:OneWayEventCallback<TData,TEvent>,
124125
):void{
126+
if(this.#socket.readyState===WebSocket.CLOSED){
127+
return;
128+
}
129+
125130
// Not happy about all the type assertions, but there are some nasty
126131
// type contravariance issues if you try to resolve the function types
127132
// properly. This is actually the lesser of two evils
@@ -130,11 +135,16 @@ export class OneWayWebSocket<TData = unknown>
130135
WebSocketEventType
131136
>;
132137

133-
if(this.#messageCallbackWrappers.has(looseCallback)){
138+
// WebSockets automatically handle de-duping callbacks, but we have to
139+
// do a separate check for the wrappers
140+
if(this.#messageListenerWrappers.has(looseCallback)){
134141
return;
135142
}
136143
if(event!=="message"){
137144
this.#socket.addEventListener(event,looseCallback);
145+
if(event==="error"){
146+
this.#errorListeners.add(looseCallback);
147+
}
138148
return;
139149
}
140150

@@ -161,7 +171,7 @@ export class OneWayWebSocket<TData = unknown>
161171
};
162172

163173
this.#socket.addEventListener(eventas"message",wrapped);
164-
this.#messageCallbackWrappers.set(looseCallback,wrapped);
174+
this.#messageListenerWrappers.set(looseCallback,wrapped);
165175
}
166176

167177
removeEventListener<TEventextendsWebSocketEventType>(
@@ -175,24 +185,37 @@ export class OneWayWebSocket<TData = unknown>
175185

176186
if(event!=="message"){
177187
this.#socket.removeEventListener(event,looseCallback);
188+
if(event==="error"){
189+
this.#errorListeners.delete(looseCallback);
190+
}
178191
return;
179192
}
180-
if(!this.#messageCallbackWrappers.has(looseCallback)){
193+
if(!this.#messageListenerWrappers.has(looseCallback)){
181194
return;
182195
}
183196

184-
constwrapper=this.#messageCallbackWrappers.get(looseCallback);
197+
constwrapper=this.#messageListenerWrappers.get(looseCallback);
185198
if(wrapper===undefined){
186199
thrownewError(
187200
`Cannot unregister callback for event${event}. This is likely an issue with the browser itself.`,
188201
);
189202
}
190203

191204
this.#socket.removeEventListener(eventas"message",wrapper);
192-
this.#messageCallbackWrappers.delete(looseCallback);
205+
this.#messageListenerWrappers.delete(looseCallback);
193206
}
194207

195208
close(closeCode?:number,reason?:string):void{
209+
// Eject all error event listeners, mainly for ergonomics in React dev
210+
// mode. React's StrictMode will create additional connections to ensure
211+
// there aren't any render bugs, but manually closing a connection via a
212+
// cleanup function sometimes causes error events to get dispatched for
213+
// a connection that is no longer wired up to the UI
214+
for(constcbofthis.#errorListeners){
215+
this.#socket.removeEventListener("error",cb);
216+
this.#errorListeners.delete(cb);
217+
}
218+
196219
this.#socket.close(closeCode,reason);
197220
}
198221
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp