11import {
22 BaseReactPyClient ,
3- type GenericReactPyClientProps ,
43 type ReactPyClientInterface ,
54 type ReactPyModule ,
6- type ReactPyUrls ,
75} from "@reactpy/client" ;
8- import { createReconnectingWebSocket } from "./websocket" ;
6+ import { PageClient } from "./pageClient" ;
7+ import type { ComponentConfig } from "./mount" ;
8+
9+ export type ReactPyDjangoClientProps = {
10+ rootId : string ;
11+ pageClient : PageClient ;
12+ mountElement : HTMLElement ;
13+ jsModulesPath : string ;
14+ componentConfig : ComponentConfig ;
15+ } ;
916
1017export class ReactPyDjangoClient
1118 extends BaseReactPyClient
1219 implements ReactPyClientInterface
1320{
14- urls : ReactPyUrls ;
15- socket : { current ?: WebSocket } ;
16- mountElement : HTMLElement ;
17- prerenderElement : HTMLElement | null = null ;
18- offlineElement : HTMLElement | null = null ;
19- private readonly messageQueue : any [ ] = [ ] ;
21+ readonly rootId : string ;
22+ readonly pageClient : PageClient ;
23+ readonly mountElement : HTMLElement ;
24+ readonly prerenderElement : HTMLElement | null = null ;
25+ readonly offlineElement : HTMLElement | null = null ;
26+ readonly jsModulesPath : string ;
27+ private readonly componentConfig : ComponentConfig ;
2028
21- constructor ( props : GenericReactPyClientProps ) {
29+ constructor ( props : ReactPyDjangoClientProps ) {
2230 super ( ) ;
2331
24- this . urls = props . urls ;
32+ this . rootId = props . rootId ;
33+ this . pageClient = props . pageClient ;
2534 this . mountElement = props . mountElement ;
35+ this . jsModulesPath = props . jsModulesPath ;
36+ this . componentConfig = props . componentConfig ;
37+
2638 this . prerenderElement = document . getElementById (
2739 props . mountElement . id + "-prerender" ,
2840 ) ;
2941 this . offlineElement = document . getElementById (
3042 props . mountElement . id + "-offline" ,
3143 ) ;
3244
33- this . socket = createReconnectingWebSocket ( {
34- url : this . urls . componentUrl ,
35- readyPromise : this . ready ,
36- ...props . reconnectOptions ,
37- // onMessage: Use standard ReactPy message routing
38- onMessage : async ( { data } ) => this . handleIncoming ( JSON . parse ( data ) ) ,
39- // onClose: If offlineElement exists, show it and hide the mountElement/prerenderElement
45+ // Register with the shared page client for message routing
46+ this . pageClient . registerComponent ( this . rootId , {
47+ handleIncoming : ( message : any ) => this . handleIncoming ( message ) ,
48+ onOpen : ( ) => {
49+ // Re-mount the component when the WebSocket reconnects
50+ this . sendMountMessage ( ) ;
51+ if ( this . offlineElement && this . mountElement ) {
52+ this . offlineElement . hidden = true ;
53+ this . mountElement . hidden = false ;
54+ }
55+ } ,
4056 onClose : ( ) => {
4157 if ( this . prerenderElement ) {
4258 this . prerenderElement . remove ( ) ;
@@ -47,28 +63,29 @@ export class ReactPyDjangoClient
4763 this . offlineElement . hidden = false ;
4864 }
4965 } ,
50- // onOpen: If offlineElement exists, hide it and show the mountElement
51- onOpen : ( ) => {
52- if ( this . offlineElement && this . mountElement ) {
53- this . offlineElement . hidden = true ;
54- this . mountElement . hidden = false ;
55- }
56- } ,
66+ } ) ;
67+ }
68+
69+ /** Send a mount-component message to the server so it constructs this component. */
70+ sendMountMessage ( ) : void {
71+ this . pageClient . sendMessage ( this . rootId , {
72+ type : "mount-component" ,
73+ rootId : this . rootId ,
74+ dottedPath : this . componentConfig . dottedPath ,
75+ componentUuid : this . componentConfig . componentUuid ,
76+ hasArgs : Boolean ( this . componentConfig . hasArgs ) ,
5777 } ) ;
5878 }
5979
6080 sendMessage ( message : any ) : void {
61- if (
62- this . socket . current &&
63- this . socket . current . readyState === WebSocket . OPEN
64- ) {
65- this . socket . current . send ( JSON . stringify ( message ) ) ;
66- } else {
67- this . messageQueue . push ( message ) ;
68- }
81+ this . pageClient . sendMessage ( this . rootId , message ) ;
6982 }
7083
7184 loadModule ( moduleName : string ) : Promise < ReactPyModule > {
72- return import ( `${ this . urls . jsModulesPath } ${ moduleName } ` ) ;
85+ return import ( `${ this . jsModulesPath } ${ moduleName } ` ) ;
86+ }
87+
88+ destroy ( ) : void {
89+ this . pageClient . unregisterComponent ( this . rootId ) ;
7390 }
7491}
0 commit comments