Skip to content

Commit 64bd41f

Browse files
committed
fix remount issue
1 parent cfdff41 commit 64bd41f

5 files changed

Lines changed: 50 additions & 43 deletions

File tree

tsunami/app/tsunamiapp.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,12 @@ func (c *clientImpl) fullRender() (*rpctypes.VDomBackendUpdate, error) {
264264
renderedVDom = makeNullVDom()
265265
}
266266
return &rpctypes.VDomBackendUpdate{
267-
Type: "backendupdate",
268-
Ts: time.Now().UnixMilli(),
269-
ServerId: c.ServerId,
270-
HasWork: len(c.Root.EffectWorkQueue) > 0,
271-
Opts: c.makeBackendOpts(),
267+
Type: "backendupdate",
268+
Ts: time.Now().UnixMilli(),
269+
ServerId: c.ServerId,
270+
HasWork: len(c.Root.EffectWorkQueue) > 0,
271+
FullUpdate: true,
272+
Opts: c.makeBackendOpts(),
272273
RenderUpdates: []rpctypes.VDomRenderUpdate{
273274
{UpdateType: "root", VDom: renderedVDom},
274275
},
@@ -285,10 +286,11 @@ func (c *clientImpl) incrementalRender() (*rpctypes.VDomBackendUpdate, error) {
285286
renderedVDom = makeNullVDom()
286287
}
287288
return &rpctypes.VDomBackendUpdate{
288-
Type: "backendupdate",
289-
Ts: time.Now().UnixMilli(),
290-
ServerId: c.ServerId,
291-
Opts: c.makeBackendOpts(),
289+
Type: "backendupdate",
290+
Ts: time.Now().UnixMilli(),
291+
ServerId: c.ServerId,
292+
FullUpdate: false,
293+
Opts: c.makeBackendOpts(),
292294
RenderUpdates: []rpctypes.VDomRenderUpdate{
293295
{UpdateType: "root", VDom: renderedVDom},
294296
},

tsunami/frontend/src/app.tsx

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,16 @@
11
// Copyright 2025, Command Line Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { useState, useEffect } from "react";
54
import { TsunamiModel } from "@/model/tsunami-model";
65
import { VDomView } from "./vdom";
76

8-
function App() {
9-
const [remountKey, setRemountKey] = useState(0);
10-
const [model, setModel] = useState(() => {
11-
const newModel = new TsunamiModel();
12-
newModel.remountCallback = () => {
13-
setRemountKey(prev => prev + 1);
14-
};
15-
return newModel;
16-
});
17-
18-
useEffect(() => {
19-
// Create a new model when remount key changes
20-
if (remountKey > 0) {
21-
const newModel = new TsunamiModel();
22-
newModel.remountCallback = () => {
23-
setRemountKey(prev => prev + 1);
24-
};
25-
setModel(newModel);
26-
}
27-
}, [remountKey]);
7+
// Global model instance
8+
const globalModel = new TsunamiModel();
289

10+
function App() {
2911
return (
3012
<div className="min-h-screen bg-background text-foreground">
31-
<VDomView key={remountKey} model={model} />
13+
<VDomView model={globalModel} />
3214
</div>
3315
);
3416
}

tsunami/frontend/src/model/tsunami-model.tsx

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ export class TsunamiModel {
8585
clientId: string;
8686
serverId: string;
8787
viewRef: React.RefObject<HTMLDivElement> = { current: null };
88-
remountCallback: (() => void) | null = null;
8988
vdomRoot: jotai.PrimitiveAtom<VDomElem> = jotai.atom();
9089
atoms: Map<string, AtomContainer> = new Map(); // key is atomname
9190
refs: Map<string, RefContainer> = new Map(); // key is refid
@@ -486,11 +485,35 @@ export class TsunamiModel {
486485
}
487486

488487
handleStateSync(update: VDomBackendUpdate, idMap: Map<string, VDomElem>) {
489-
if (update.statesync == null) {
490-
return;
491-
}
492-
for (let sync of update.statesync) {
493-
this.setAtomValue(sync.atom, sync.value, true, idMap);
488+
if (update.fullupdate) {
489+
if (update.statesync == null) {
490+
this.atoms.clear();
491+
return;
492+
}
493+
494+
const sentAtoms = new Set<string>();
495+
for (let sync of update.statesync) {
496+
sentAtoms.add(sync.atom);
497+
this.setAtomValue(sync.atom, sync.value, true, idMap);
498+
}
499+
500+
const atomsToRemove: string[] = [];
501+
for (let atomName of this.atoms.keys()) {
502+
if (!sentAtoms.has(atomName)) {
503+
atomsToRemove.push(atomName);
504+
}
505+
}
506+
507+
for (let atomName of atomsToRemove) {
508+
this.atoms.delete(atomName);
509+
}
510+
} else {
511+
if (update.statesync == null) {
512+
return;
513+
}
514+
for (let sync of update.statesync) {
515+
this.setAtomValue(sync.atom, sync.value, true, idMap);
516+
}
494517
}
495518
}
496519

@@ -562,13 +585,11 @@ export class TsunamiModel {
562585
return;
563586
}
564587

565-
// Check if serverId is changing and trigger remount if needed
588+
// Check if serverId is changing and reset if needed
566589
if (this.serverId != null && this.serverId !== update.serverid) {
567-
// Server ID changed - need to remount the entire app
568-
if (this.remountCallback) {
569-
this.remountCallback();
570-
}
571-
return;
590+
// Server ID changed - reset the model state
591+
this.reset();
592+
this.setupServerEventSource();
572593
}
573594

574595
this.serverId = update.serverid;

tsunami/frontend/src/types/vdom.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type VDomBackendUpdate = {
2222
serverid: string;
2323
opts?: VDomBackendOpts;
2424
haswork?: boolean;
25+
fullupdate?: boolean;
2526
renderupdates?: VDomRenderUpdate[];
2627
transferelems?: VDomTransferElem[];
2728
statesync?: VDomStateSync[];

tsunami/rpctypes/protocoltypes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type VDomBackendUpdate struct {
5151
ServerId string `json:"serverid"`
5252
Opts *VDomBackendOpts `json:"opts,omitempty"`
5353
HasWork bool `json:"haswork,omitempty"`
54+
FullUpdate bool `json:"fullupdate,omitempty"`
5455
RenderUpdates []VDomRenderUpdate `json:"renderupdates,omitempty"`
5556
TransferElems []VDomTransferElem `json:"transferelems,omitempty"`
5657
StateSync []VDomStateSync `json:"statesync,omitempty"`

0 commit comments

Comments
 (0)