-
Notifications
You must be signed in to change notification settings - Fork 686
Description
User Strike72 on discord encountered an issue where his react client doesn't correctly trigger their ClientDisconnected reducer: https://discord.com/channels/1037340874172014652/1424993383302041612
I guessed that this user was using the new react-hooks and took a look at the SpacetimeDBProvider. 🕵️
Right now the SpacetimeDBProvider builds the connection immediately, but never tears it down, so when the user refreshes or navigates away, the websocket stays open until it dies from inactivity or the browser closes. This leads to users not properly disconnecting from SpacetimeDB and frustration.
To clean up properly, the connection should be built inside a useEffect inside the provider itself, and call disconnect() in the cleanup function. Here is a drop-in replacement of the SpacetimeDBProvider.ts file that does exactly this:
import React from 'react';
import {
DbConnectionBuilder,
type DbConnectionImpl,
} from '../sdk/db_connection_impl';
import { SpacetimeDBContext } from './useSpacetimeDB';
export interface SpacetimeDBProviderProps<
DbConnection extends DbConnectionImpl,
ErrorContext,
SubscriptionEventContext,
> {
connectionBuilder: DbConnectionBuilder<
DbConnection,
ErrorContext,
SubscriptionEventContext
>;
children?: React.ReactNode;
}
export function SpacetimeDBProvider<
DbConnection extends DbConnectionImpl,
ErrorContext,
SubscriptionEventContext,
>({
connectionBuilder,
children,
}: SpacetimeDBProviderProps<
DbConnection,
ErrorContext,
SubscriptionEventContext
>): React.JSX.Element {
const [connection, setConnection] = React.useState<DbConnection | null>(null);
React.useEffect(() => {
const conn = connectionBuilder.build();
setConnection(conn);
return () => {
try {
conn.disconnect();
} catch (err) {
console.warn('[SpacetimeDBProvider] Error during disconnect:', err);
}
};
}, [connectionBuilder]);
if (!connection) return React.createElement(React.Fragment, null);
return React.createElement(
SpacetimeDBContext.Provider,
{ value: connection },
children
);
}We're building the connection lazily inside the useEffect, and we're .disconnect()ing on unmount to automatically clean up the websocket. While the connection is initializing, we're also dropping in a placeholder React.Fragment.
I've confirmed this fix in my react-hooks test repo, although the above change won't be included since it's a modification of the npm package.