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:
- It reads React-specific
ExtensionParamsProviderfunctions fromNrgyControllerExtension. - It creates a
ViewProxyfor the current props by callingcreateViewProxy(). - It appends
provideView(view)to the provider list and creates the controller instance withnew declaration(providers). - It stores the controller instance and its
ViewProxyinuseRef()to avoid recreating them on every render. - In a separate
useEffect(), it forwards updated props intoview.update(props). - In the lifecycle effect, it calls
view.mount()on mount and thenview.destroy()together withcontroller.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 theViewProxy.- 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>;
}