1- import { useEffect , useState } from "react" ;
2- import { loadOntology , findCell } from "../services/ontologyGridService" ;
1+ import { useEffect , useMemo , useState } from "react" ;
2+ import { loadOntology , peekOntology , findCell } from "../services/ontologyGridService" ;
33import { ONTOLOGY_CATALOG , DEFAULT_ONTOLOGY_SLUG } from "../config/gridConfig" ;
44
55/**
@@ -11,41 +11,64 @@ import { ONTOLOGY_CATALOG, DEFAULT_ONTOLOGY_SLUG } from "../config/gridConfig";
1111 * arriving from a grid tile costs no network and no reparse, while a cold deep-link still
1212 * works on its own.
1313 *
14+ * A parse already in that cache is resolved *during render* (`peekOntology`) rather than in the
15+ * effect. Going through the effect would report `loading` for one frame on every term change,
16+ * and that frame swaps the card for its skeleton — unmounting the widgets and losing their
17+ * state. The Ontology Hierarchy widget has to stay stationary while the rest of the card changes
18+ * around it (spec §3.2), which it cannot do if it is remounted on the way.
19+ *
1420 * The card's data never comes from the InterLex term API — Precision cells are npokb-only and
1521 * that endpoint 404s on them. `ontologySlug` is the *context* ontology (the `?ontology=` param
1622 * written by the grid), which is a different thing from `DataContext.activeOntology`: the
1723 * latter is an edit target, not a data source.
1824 */
1925const useCellTerm = ( termSlug , ontologySlug = DEFAULT_ONTOLOGY_SLUG ) => {
20- const [ state , setState ] = useState ( { cell : null , data : null , loading : true , error : null } ) ;
26+ const slug = ontologySlug && ONTOLOGY_CATALOG [ ontologySlug ] ? ontologySlug : DEFAULT_ONTOLOGY_SLUG ;
27+ // Carries the slug it was resolved against, so a switch of context ontology cannot be served
28+ // the previous ontology's cell for the render before the effect runs.
29+ const [ state , setState ] = useState ( { slug, cell : null , data : null , loading : true , error : null } ) ;
30+ const cached = peekOntology ( slug ) ;
2131
2232 useEffect ( ( ) => {
23- const slug = ontologySlug && ONTOLOGY_CATALOG [ ontologySlug ] ? ontologySlug : DEFAULT_ONTOLOGY_SLUG ;
2433 if ( ! termSlug ) {
25- setState ( { cell : null , data : null , loading : false , error : null } ) ;
34+ setState ( { slug , cell : null , data : null , loading : false , error : null } ) ;
2635 return undefined ;
2736 }
37+ // Already parsed: resolved synchronously below, so there is nothing to load or to flag.
38+ if ( peekOntology ( slug ) ) return undefined ;
2839
2940 let active = true ;
30- setState ( ( prev ) => ( { ... prev , loading : true , error : null } ) ) ;
41+ setState ( { slug , cell : null , data : null , loading : true , error : null } ) ;
3142
3243 loadOntology ( slug )
3344 . then ( ( data ) => {
3445 if ( ! active ) return ;
3546 // A term that is not in this ontology is not an error — the tab simply has nothing to
3647 // show, and the caller renders/hides accordingly.
37- setState ( { cell : findCell ( data , termSlug ) || null , data, loading : false , error : null } ) ;
48+ setState ( { slug , cell : findCell ( data , termSlug ) || null , data, loading : false , error : null } ) ;
3849 } )
3950 . catch ( ( error ) => {
40- if ( active ) setState ( { cell : null , data : null , loading : false , error } ) ;
51+ if ( active ) setState ( { slug , cell : null , data : null , loading : false , error } ) ;
4152 } ) ;
4253
4354 return ( ) => {
4455 active = false ;
4556 } ;
46- } , [ termSlug , ontologySlug ] ) ;
57+ } , [ termSlug , slug ] ) ;
4758
48- return state ;
59+ return useMemo ( ( ) => {
60+ if ( cached ) {
61+ return {
62+ cell : termSlug ? findCell ( cached , termSlug ) || null : null ,
63+ data : cached ,
64+ loading : false ,
65+ error : null ,
66+ } ;
67+ }
68+ // State left over from another ontology says nothing about this one; the effect is loading it.
69+ if ( state . slug !== slug ) return { cell : null , data : null , loading : true , error : null } ;
70+ return { cell : state . cell , data : state . data , loading : state . loading , error : state . error } ;
71+ } , [ cached , termSlug , slug , state ] ) ;
4972} ;
5073
5174export default useCellTerm ;
0 commit comments