Technical Documentation

Internals: Component Rendering & Registry

This document explains the internal mechanics of how FieldRenderer dispatches JSON definitions to React components. For the getting-started guide on building and registering your own components, see Basic Usage → ComponentRegistry.

1. The Dispatcher Layer

The FieldRenderer acts as the dispatcher. It receives a field definition and decides which React component to render.

The Resolution Process:

  1. Extract State: Calculates computedState (visible, disabled, required).
  2. Lookup: Retrieves the component from ComponentRegistryContext using field.type as the key.
  3. Validate: If the type is not mapped, it renders a fallback UI to inform the developer.

2. Dependency Watching (Performance)

To ensure high performance in forms with hundreds of fields, FieldRenderer uses Selective Watching.

const dependencies = useMemo(() => extractFieldDependencies(field), [field]); const dependencyValues = useWatch({ control, name: dependencies.length > 0 ? dependencies : ["__ROOT_WATCH__"], });
  • Benefit: Re-renders only happen when a field that this specific field actually depends on changes.
  • Complexity: Reducing global re-renders from O(N) to O(1) for the vast majority of user interactions.

3. The Adapter Interface

Every component in the registry must follow the Adapter Interface. The engine passes the following props:

  • field: The final field definition (including computed labels and required status).
  • computedState: The raw result from the rule engine.
  • apiOptions: Normalised options if the field has a dataSource.
  • isApiLoading: Loading state for async data sources.

4. Infinite Loop Protection

The dispatcher implements a safeguard against circular computed value dependencies.

  • Threshold: The engine checks if a field's value has been updated 6 or more times in a single execution tick.
  • Action: If the threshold is exceeded, the engine halts the update and logs a console error to prevent browser freezing.

5. Memoization Strategy

FieldRenderer is wrapped in React.memo using the default shallow comparison. Since it depends on useWatch, the component itself only re-renders when the specific dependencies change, keeping the Virtual DOM lean.


6. Setting Up the ComponentRegistry

For a step-by-step guide on creating adapter components, building the registry object, and injecting it into your app, see:

šŸ‘‰ Basic Usage → Section 4: ComponentRegistry

This section is intentionally kept in the Getting Started guide because the registry is a required part of any DFBE integration — not an advanced concern.


7. Step Component Registry (StepComponentRegistry)

Similar to how FieldRenderer dispatches fields, the form engine supports a StepComponentRegistry for CustomStep types.

  • Lookup: When currentStep.type === "custom", the host application is responsible for looking up the component in the StepRegistryContext.
  • Interface: Custom step components receive step: CustomStep as props.
  • Navigation Control: Unlike standard fields, custom steps use setStepGuard to control navigation flow.

For more details on implementing custom steps, see Custom Steps Guide.