fix: prevent TLDraw topOffset crash — decouple store init from editor ready
Three changes to singlePlayerPage:
1. Store creation no longer waits for isEditorReady. The editor ref
is already passed as optional to NavigationSnapshotService and
loadNodeSnapshotFromDatabase, so we can create and populate the
store without needing the editor to be mounted first.
2. <Tldraw> only renders when store is defined: {store && <Tldraw>}.
Previously it rendered immediately with store={undefined}, which
caused TLDraw to initialize with no backing store and crash
reading topOffset on an unresolved internal object.
3. Loading guard also checks !user so the component never renders
with a null profile before the redirect effect fires.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b1681d86fb
commit
e27d1f5c8d
@ -85,23 +85,13 @@ export default function SinglePlayerPage() {
|
|||||||
setUserPreferences: setTldrawPreferences
|
setUserPreferences: setTldrawPreferences
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize store
|
// Initialize store — runs as soon as user is ready, no editor needed for store creation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isEditorReady) {
|
|
||||||
logger.debug('single-player-page', '⏳ Waiting for editor to be ready');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
logger.debug('single-player-page', '⏳ Waiting for user data');
|
logger.debug('single-player-page', '⏳ Waiting for user data');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!editorRef.current) {
|
|
||||||
logger.debug('single-player-page', '⏳ Waiting for editor ref');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info('single-player-page', '🔄 Starting store initialization', {
|
logger.info('single-player-page', '🔄 Starting store initialization', {
|
||||||
isEditorReady,
|
isEditorReady,
|
||||||
hasUser: !!user,
|
hasUser: !!user,
|
||||||
@ -221,7 +211,7 @@ export default function SinglePlayerPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
initializeStoreAndSnapshot();
|
initializeStoreAndSnapshot();
|
||||||
}, [isEditorReady, user, context.node]);
|
}, [user, context.node]);
|
||||||
|
|
||||||
// Handle initial node placement
|
// Handle initial node placement
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -451,7 +441,7 @@ export default function SinglePlayerPage() {
|
|||||||
const uiComponents = getUiComponents(presentationMode);
|
const uiComponents = getUiComponents(presentationMode);
|
||||||
|
|
||||||
// Show loading state if user context is still loading
|
// Show loading state if user context is still loading
|
||||||
if (userLoading) {
|
if (userLoading || !user) {
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
@ -505,7 +495,7 @@ export default function SinglePlayerPage() {
|
|||||||
</Alert>
|
</Alert>
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
|
|
||||||
<Tldraw
|
{store && <Tldraw
|
||||||
user={tldrawUser}
|
user={tldrawUser}
|
||||||
store={store}
|
store={store}
|
||||||
tools={singlePlayerTools}
|
tools={singlePlayerTools}
|
||||||
@ -549,7 +539,7 @@ export default function SinglePlayerPage() {
|
|||||||
logger.error('single-player-page', '❌ Error in onMount', error);
|
logger.error('single-player-page', '❌ Error in onMount', error);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user