In React Native, what is the difference between a Turbo Module and a Fabric native component, and which does a signature-pad view need?
answer
- one has no UI at all
- host component in the React tree
- props in, events out, commands aside
- laid out by Yoga like View
- drawing needs a native view
basics
~20 sA Turbo Module is a set of native functions with no UI, called from JavaScript. A Fabric native component is a platform view in the React tree, configured by props, reporting through events, driven by commands. A signature pad draws on screen, so it needs a component.
solid answer
~40 sA **Turbo Module** exposes native functions — `getItem`, `unlock`, `getStepsSinceBoot` — obtained from `TurboModuleRegistry` and called like an API; it renders nothing. A **Fabric native component** is declared with `codegenNativeComponent<NativeProps>('SignaturePad')`, rendered as JSX like `<View>`, laid out by Yoga with the rest of the tree, and backed by a real platform view: a `SimpleViewManager`-managed Android `View`, or an `RCTViewComponentView` subclass on iOS. Data flows in through **typed props**, out through **events** (`DirectEventHandler` or `BubblingEventHandler`), and imperative calls such as `clear()` go through **commands** from `codegenNativeCommands`. A proof-of-delivery signature pad must sit in the layout and draw strokes natively as the finger moves, so it is a component; a module could only act on it from outside.
code
typescript · 18 lines// specs/SignaturePadNativeComponent.ts
import type {CodegenTypes, ColorValue, HostComponent, ViewProps} from 'react-native';
import {codegenNativeComponent} from 'react-native';
type StrokeEndEvent = {
pointCount: CodegenTypes.Int32;
};
export interface NativeProps extends ViewProps {
strokeColor?: ColorValue;
strokeWidth?: CodegenTypes.WithDefault<CodegenTypes.Float, 3>;
disabled?: CodegenTypes.WithDefault<boolean, false>;
onStrokeEnd?: CodegenTypes.DirectEventHandler<StrokeEndEvent> | null;
}
export default codegenNativeComponent<NativeProps>(
'SignaturePad',
) as HostComponent<NativeProps>;go deeper
Remember that modules are functions without UI and components are views in the React tree, with props, events and commands.
Map each capability to its mechanism, from codegenNativeComponent and ViewProps layout to event handler types, commands and the native base classes on each platform.
Decide between a component, a module, composition or an existing library for a real feature, and split responsibilities, such as a pad component plus an upload module.
Weigh owning native UI on two platforms against library adoption or a JavaScript implementation, considering upgrade cost, team skills and latency needs.
## Two ways to reach native code React Native's New Architecture offers two typed extension points, both described by a spec that **Codegen** turns into native glue: - A **Turbo Module** is a native object whose **methods** JavaScript calls. Its spec extends `TurboModule` and is loaded with `TurboModuleRegistry.getEnforcing`. It has no position on screen. - A **Fabric native component** is a **host component** — an element that React renders directly to a platform view, the way `View` and `Text` are. Its spec is a file ending in `NativeComponent.ts` that calls `codegenNativeComponent<NativeProps>('SignaturePad')`. ## What a component has that a module does not | Capability | Turbo Module | Fabric native component | |---|---|---| | Appears in the view hierarchy | No | Yes, one native view per rendered element | | Laid out by Yoga (flexbox, `style`) | No | Yes, `NativeProps` extends `ViewProps` | | Input from JavaScript | Method arguments | Typed **props** | | Output to JavaScript | Return values, promises, module events | Component **events** (`DirectEventHandler`, `BubblingEventHandler`) | | Imperative calls | Every method is one | **Commands** from `codegenNativeCommands` | | Lifetime | One instance for the React instance | One view per mounted element | | Native base on Android | Generated abstract spec class | `SimpleViewManager` with a generated delegate | | Native base on iOS | Class adopting the generated spec protocol | `RCTViewComponentView` subclass | ## Why a signature pad is a component A parcel-delivery app's proof-of-delivery screen shows a box where the customer signs with a finger. Consider what that box must do: 1. **Occupy layout space** next to the recipient's name and the confirm button — only a view laid out by Yoga can do that. 2. **Receive touches and draw strokes** as the finger moves, which is smoothest when the platform view handles its own touch stream and drawing. 3. **Be configured declaratively** — stroke colour, stroke width, a disabled state once the parcel is confirmed — which is exactly what props are for. 4. **Report back** when a stroke ends or the pad becomes non-empty, which is what component events are for. 5. **Accept occasional imperative requests** — `clear()` when the customer taps "Start again" — which is what commands are for. A Turbo Module fits none of the first three: it has no view to occupy space, receive touches or be styled. It is the right tool beside the component, for example a module that uploads the exported signature image, but not for the pad itself. ## When not to write either - **Composition may be enough.** If core components and a JavaScript drawing approach meet the latency and quality bar, there is no native code to maintain. - **An existing library may exist.** Adopting a maintained component is often cheaper than owning native code on two platforms. - **Expo projects have another route.** The Expo Modules API offers its own view definitions; that is a separate authoring model with its own contract. ## How the pieces are named For a spec `SignaturePadNativeComponent.ts` calling `codegenNativeComponent<NativeProps>('SignaturePad')`, the string `'SignaturePad'` is the component's name everywhere: the Android view manager's `getName()` returns it, the iOS registration in `codegenConfig.ios.componentProvider` maps it to a class, and Codegen derives the generated interface, delegate and props types from it. The file must end in `NativeComponent` — Codegen uses that suffix to detect component specs. Everything the spec imports — `codegenNativeComponent`, the `CodegenTypes` namespace, `HostComponent`, `ViewProps`, `ColorValue` — comes from the root `react-native` entry point; in React Native 0.87 deep imports such as `react-native/Libraries/Types/CodegenTypes`, which older guides show, are a type error under the default Strict TypeScript API. ## Mistakes interviewers listen for - Calling a native component a "native module with UI" and trying to return a view from a module method. - Believing a native component is a WebView or an image of native UI — it is the real platform view in the hierarchy. - Using a module to draw on a view it cannot own, instead of giving the drawing surface its own component. - Forgetting that each rendered element is a separate native view with its own state.
- Could a Turbo Module draw on an existing React Native View instead of writing a component?Not in a way React Native supports. A module has no view of its own, and the views React Native mounts belong to the renderer, which reapplies props and may recycle them. Drawing belongs in a component that owns its platform view. A module fits work beside it, such as uploading the exported signature.
- How does data get out of a signature pad component when the courier taps Confirm?Through the component's own channels: a command such as `exportSignature()` asks the native view to render its strokes, and an event such as `onSignatureExported` carries the result, for example a file path, back to JavaScript. Commands return nothing, so the answer arrives as an event.
A Turbo Module is a phone line to a back office: you call, ask for something and get an answer, but nothing appears in your shop window. A native component is a display case built into the window itself: it takes up space in the layout, customers see it and touch it, and you change what it shows by rearranging its contents (props).
saying these in an interview costs you the question
- A native component is a Turbo Module whose methods return views
- Native components render as images or web views of native UI
- A Turbo Module can be placed in JSX if it has a render method
- Props for a native component are passed as method arguments at mount time
- Each native component type has a single shared native view instance