react-on-rails
Version:
react-on-rails JavaScript for react_on_rails Ruby gem
175 lines (174 loc) • 6.17 kB
TypeScript
import type { ReactElement, ReactNode, Component, ComponentType } from 'react';
import type { Readable } from 'stream';
type Store = unknown;
type ReactComponent = ComponentType<any> | string;
export interface RailsContext {
railsEnv: string;
inMailer: boolean;
i18nLocale: string;
i18nDefaultLocale: string;
rorVersion: string;
rorPro: boolean;
rorProVersion?: string;
serverSide: boolean;
href: string;
location: string;
scheme: string;
host: string;
port: number | null;
pathname: string;
search: string | null;
httpAcceptLanguage: string;
}
type AuthenticityHeaders = {
[id: string]: string;
} & {
'X-CSRF-Token': string | null;
'X-Requested-With': string;
};
type StoreGenerator = (props: Record<string, unknown>, railsContext: RailsContext) => Store;
interface ServerRenderResult {
renderedHtml?: string | {
componentHtml: string;
[key: string]: string;
};
redirectLocation?: {
pathname: string;
search: string;
};
routeError?: Error;
error?: Error;
}
type CreateReactOutputResult = ServerRenderResult | ReactElement | Promise<string>;
type RenderFunctionResult = ReactComponent | ServerRenderResult | Promise<string>;
/**
* Render functions are used to create dynamic React components or server-rendered HTML with side effects.
* They receive two arguments: props and railsContext.
*
* @param props - The component props passed to the render function
* @param railsContext - The Rails context object containing environment information
* @returns A string, React component, React element, or a Promise resolving to a string
*
* @remarks
* To distinguish a render function from a React Function Component:
* 1. Ensure it accepts two parameters (props and railsContext), even if railsContext is unused, or
* 2. Set the `renderFunction` property to `true` on the function object.
*
* If neither condition is met, it will be treated as a React Function Component,
* and ReactDOMServer will attempt to render it.
*
* @example
* // Option 1: Two-parameter function
* const renderFunction = (props, railsContext) => { ... };
*
* // Option 2: Using renderFunction property
* const anotherRenderFunction = (props) => { ... };
* anotherRenderFunction.renderFunction = true;
*/
interface RenderFunction {
(props?: any, railsContext?: RailsContext, domNodeId?: string): RenderFunctionResult;
renderFunction?: true;
}
type ReactComponentOrRenderFunction = ReactComponent | RenderFunction;
export type { // eslint-disable-line import/prefer-default-export
ReactComponentOrRenderFunction, ReactComponent, AuthenticityHeaders, RenderFunction, RenderFunctionResult, Store, StoreGenerator, CreateReactOutputResult, ServerRenderResult, };
export interface RegisteredComponent {
name: string;
component: ReactComponentOrRenderFunction;
/**
* Indicates if the registered component is a RenderFunction
* @see RenderFunction for more details on its behavior and usage.
*/
renderFunction: boolean;
isRenderer: boolean;
}
interface Params {
props?: Record<string, unknown>;
railsContext?: RailsContext;
domNodeId?: string;
trace?: boolean;
}
export interface RenderParams extends Params {
name: string;
throwJsErrors: boolean;
renderingReturnsPromises: boolean;
}
export interface CreateParams extends Params {
componentObj: RegisteredComponent;
shouldHydrate?: boolean;
}
export interface ErrorOptions {
e: Error & {
fileName?: string;
lineNumber?: string;
};
name?: string;
jsCode?: string;
serverSide: boolean;
}
export type RenderingError = Pick<Error, 'message' | 'stack'>;
export interface RenderResult {
html: string | null;
consoleReplayScript: string;
hasErrors: boolean;
renderingError?: RenderingError;
isShellReady?: boolean;
}
export interface Root {
render(children: ReactNode): void;
unmount(): void;
}
export type RenderReturnType = void | Element | Component | Root;
export interface ReactOnRails {
register(components: {
[id: string]: ReactComponentOrRenderFunction;
}): void;
/** @deprecated Use registerStoreGenerators instead */
registerStore(stores: {
[id: string]: StoreGenerator;
}): void;
registerStoreGenerators(storeGenerators: {
[id: string]: StoreGenerator;
}): void;
getStore(name: string, throwIfMissing?: boolean): Store | undefined;
setOptions(newOptions: {
traceTurbolinks: boolean;
}): void;
reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
reactOnRailsPageLoaded(): void;
reactOnRailsComponentLoaded(domId: string): void;
authenticityToken(): string | null;
authenticityHeaders(otherHeaders: {
[id: string]: string;
}): AuthenticityHeaders;
option(key: string): string | number | boolean | undefined;
getStoreGenerator(name: string): StoreGenerator;
setStore(name: string, store: Store): void;
clearHydratedStores(): void;
render(name: string, props: Record<string, string>, domNodeId: string, hydrate: boolean): RenderReturnType;
getComponent(name: string): RegisteredComponent;
serverRenderReactComponent(options: RenderParams): null | string | Promise<RenderResult>;
streamServerRenderedReactComponent(options: RenderParams): Readable;
handleError(options: ErrorOptions): string | undefined;
buildConsoleReplay(): string;
registeredComponents(): Map<string, RegisteredComponent>;
storeGenerators(): Map<string, StoreGenerator>;
stores(): Map<string, Store>;
resetOptions(): void;
options: Record<string, string | number | boolean>;
}
export type RenderState = {
result: null | string | Promise<string>;
hasErrors: boolean;
error?: RenderingError;
};
export type StreamRenderState = Omit<RenderState, 'result'> & {
result: null | Readable;
isShellReady: boolean;
};
export type RenderOptions = {
componentName: string;
domNodeId?: string;
trace?: boolean;
renderingReturnsPromises: boolean;
};