diff --git a/src/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.tsx b/src/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.tsx index 60b9b475..e88cc310 100644 --- a/src/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.tsx +++ b/src/lib/unstable/core/SchemaRendererNode/SchemaRendererNode.tsx @@ -11,7 +11,7 @@ import {SCHEMA_RENDERER_SERVICE_FIELD} from '../useSchemaRenderer'; import {useSchemaRendererState} from '../useSchemaRendererState'; import {getParentName, getServiceFieldName, getStrictModeChecker} from '../utils'; -import {SchemaRendererNodeContext} from './context'; +import {SchemaRendererNodeContext, createSchemaRendererNodeContextRuler} from './context'; import type {SchemaRendererNodeState} from './types'; import {coerceToJsonSchemaType, getAccumulatedSchema, getRenderKit, scheduleFlush} from './utils'; @@ -257,6 +257,16 @@ const SchemaRendererNodeComponent: React.FC = ({ [headName, input, meta, mode, name, parentValueEmpty, schema, schemaPath, settings], ); + const [nodeContextRuler] = React.useState(() => + createSchemaRendererNodeContextRuler(nodeContext), + ); + + nodeContextRuler.set(nodeContext); + + React.useEffect(() => { + nodeContextRuler.notify(); + }, [nodeContext, nodeContextRuler]); + React.useEffect(() => { const unsubscribe = form.subscribe( (state) => { @@ -350,7 +360,7 @@ const SchemaRendererNodeComponent: React.FC = ({ if (content) { content = ( - + {content} ); diff --git a/src/lib/unstable/core/SchemaRendererNode/context.ts b/src/lib/unstable/core/SchemaRendererNode/context.ts index 713f4c7a..a736274c 100644 --- a/src/lib/unstable/core/SchemaRendererNode/context.ts +++ b/src/lib/unstable/core/SchemaRendererNode/context.ts @@ -16,8 +16,62 @@ export interface SchemaRendererNodeContextValue extends FieldRenderProps( - {} as unknown as SchemaRendererNodeContextValue, +export interface SchemaRendererNodeContextRuler { + getSnapshot: () => SchemaRendererNodeContextValue; + notify: () => void; + set: (value: SchemaRendererNodeContextValue) => void; + subscribe: (listener: () => void) => () => void; +} + +export const createSchemaRendererNodeContextRuler = ( + initialValue: SchemaRendererNodeContextValue, +): SchemaRendererNodeContextRuler => { + let value = initialValue; + const listeners = new Set<() => void>(); + + return { + getSnapshot: () => value, + notify: () => { + listeners.forEach((listener) => listener()); + }, + set: (nextValue) => { + value = nextValue; + }, + subscribe: (listener) => { + listeners.add(listener); + + return () => { + listeners.delete(listener); + }; + }, + }; +}; + +export const SchemaRendererNodeContext = React.createContext( + null as unknown as SchemaRendererNodeContextRuler, ); -export const useSchemaRendererNodeContext = () => React.useContext(SchemaRendererNodeContext); +export const useSchemaRendererNodeContext = (): SchemaRendererNodeContextValue => { + const store = React.useContext(SchemaRendererNodeContext); + + const value = store.getSnapshot(); + const [, forceRender] = React.useReducer((x: number) => x + 1, 0); + const valueRef = React.useRef(value); + + valueRef.current = value; + + React.useLayoutEffect(() => { + const check = () => { + if (store.getSnapshot() !== valueRef.current) { + forceRender(); + } + }; + const unsubscribe = store.subscribe(check); + + check(); + + return unsubscribe; + }, [store]); + + return value; +}; diff --git a/src/lib/unstable/core/SchemaRendererNode/index.ts b/src/lib/unstable/core/SchemaRendererNode/index.ts index c706a422..8c7f3acb 100644 --- a/src/lib/unstable/core/SchemaRendererNode/index.ts +++ b/src/lib/unstable/core/SchemaRendererNode/index.ts @@ -2,6 +2,7 @@ export {SchemaRendererNode, type SchemaRendererNodeProps} from './SchemaRenderer export { SchemaRendererNodeContext, type SchemaRendererNodeContextValue, + createSchemaRendererNodeContextRuler, useSchemaRendererNodeContext, } from './context'; export type {SchemaRendererNodeState} from './types'; diff --git a/src/lib/unstable/core/index.ts b/src/lib/unstable/core/index.ts index 354e4262..d5a17bff 100644 --- a/src/lib/unstable/core/index.ts +++ b/src/lib/unstable/core/index.ts @@ -5,6 +5,7 @@ export { type SchemaRendererNodeProps, type SchemaRendererNodeState, getRenderKit, + createSchemaRendererNodeContextRuler, useSchemaRendererNodeContext, } from './SchemaRendererNode'; export {SchemaRenderer, type SchemaRendererProps} from './SchemaRenderer'; diff --git a/src/lib/unstable/kit/entities/FewOfNested/FewOfNested.tsx b/src/lib/unstable/kit/entities/FewOfNested/FewOfNested.tsx index e03f1c60..f0e985ca 100644 --- a/src/lib/unstable/kit/entities/FewOfNested/FewOfNested.tsx +++ b/src/lib/unstable/kit/entities/FewOfNested/FewOfNested.tsx @@ -11,6 +11,7 @@ import { SchemaRendererMode, SchemaRendererNode, SchemaRendererNodeContext, + createSchemaRendererNodeContextRuler, getRenderKit, useSchemaRendererState, } from '../../../core'; @@ -129,7 +130,7 @@ export const FewOfNested: NodeEntity = ({ } } - const nodeContext = { + const nodeContextRuler = createSchemaRendererNodeContextRuler({ headName, input: togglerInput, meta: togglerMeta, @@ -139,10 +140,10 @@ export const FewOfNested: NodeEntity = ({ schema: togglerSchema, schemaPath: togglerSchemaPath, settings, - }; + }); return ( - + {result} ); diff --git a/src/lib/unstable/kit/entities/OneOfNested/OneOfNested.tsx b/src/lib/unstable/kit/entities/OneOfNested/OneOfNested.tsx index bd6f3982..9b5d0239 100644 --- a/src/lib/unstable/kit/entities/OneOfNested/OneOfNested.tsx +++ b/src/lib/unstable/kit/entities/OneOfNested/OneOfNested.tsx @@ -9,6 +9,7 @@ import { SchemaRendererMode, SchemaRendererNode, SchemaRendererNodeContext, + createSchemaRendererNodeContextRuler, getRenderKit, useSchemaRendererState, } from '../../../core'; @@ -124,7 +125,7 @@ export const OneOfNested: NodeEntity = ({ } } - const nodeContext = { + const nodeContextRuler = createSchemaRendererNodeContextRuler({ headName, input: togglerInput, meta: togglerMeta, @@ -134,10 +135,10 @@ export const OneOfNested: NodeEntity = ({ schema: togglerSchema, schemaPath: togglerSchemaPath, settings, - }; + }); return ( - + {result} );