Skip to content

useController.ts ​

Purpose ​

This module contains the useController() hook, which creates and manages a controller or view model instance inside a React component.

Overview ​

useController() is the main integration point between React and @nrgyjs/core. It accepts a controller or view-model declaration, optionally passes view props into it, and synchronizes the created instance with the React component lifecycle.

Conceptual Architecture ​

The hook works as follows:

  1. It reads React-specific ExtensionParamsProvider functions from NrgyControllerExtension.
  2. It creates a ViewProxy for the current props by calling createViewProxy().
  3. It appends provideView(view) to the provider list and creates the controller instance with new declaration(providers).
  4. It stores the controller instance and its ViewProxy in useRef() to avoid recreating them on every render.
  5. In a separate useEffect(), it forwards updated props into view.update(props).
  6. In the lifecycle effect, it calls view.mount() on mount and then view.destroy() together with controller.destroy() on unmount or when the declaration changes.

The hook also re-invokes extension providers on later renders so React hooks inside extensions keep their execution order intact.

Public API Description ​

useController<TContext, TService>(declaration): TService ​

  • declaration: controller or view-model declaration with no required view props.
  • Returns the created service instance of type TService.

useController<TContext, TService, TProps>(declaration, props): TService ​

  • declaration: controller or view-model declaration that depends on view props.
  • props: props object passed into the ViewProxy.
  • Returns the created service instance of type TService.

Usage Examples ​

tsx
import React from 'react';
import { declareController, withView } from '@nrgyjs/core';
import { useController } from '@nrgyjs/react';

const GreetingController = declareController()
  .extend(withView<{ name: string }>())
  .apply(({ view }) => ({
    title: () => `Hello, ${view.props.name()}!`,
  }));

export function Greeting(props: { name: string }) {
  const controller = useController(GreetingController, props);

  return <h1>{controller.title()}</h1>;
}