Components

The SDK provides two main components for rendering dynamic content: DynamicComponent for individual components and MiniappComponent for collections of components.

DynamicComponent

Renders a server-driven component by name. This is the primary way to display dynamic content in your app.

Basic Usage

TSX
import { DynamicComponent } from '@dpage-ai/react-native-dpage';

// Simple usage
<DynamicComponent name="ProductCard" />

// With data props
<DynamicComponent
  name="ProductCard"
  data={{ productId: '123', showPrice: true }}
/>

// With custom project (overrides global config)
<DynamicComponent
  name="ProductCard"
  projectId="different-project"
/>

Per-render Runtime Overrides

In advanced cases (like edit mode), you can override runtime deps for a specific render. Overrides are merged on top of the default + registered deps, and override existing keys if they collide.

Keep overrides object identity stable

Passing a new object on every render bypasses caching and recompiles the component. Hoist the object outside the component or create it with useMemo.
TSX
import React, { useMemo } from 'react';
import { DynamicComponent } from '@dpage-ai/react-native-dpage';

function Screen() {
  // ✅ Stable identity
  const editModeDeps = useMemo(
    () => ({
      View: EditableView,
      Text: EditableText,
    }),
    []
  );

  return (
    <DynamicComponent
      name="ProductCard"
      runtimeDepsOverrides={editModeDeps}
    />
  );
}

Custom Loading & Error States

TSX
<DynamicComponent
  name="ProductCard"
  data={{ productId: '123' }}
  renderLoading={() => (
    <View style={styles.loading}>
      <ActivityIndicator size="large" color="#3B82F6" />
      <Text>Loading product...</Text>
    </View>
  )}
  renderError={(error) => (
    <View style={styles.error}>
      <Text style={styles.errorText}>Failed to load</Text>
      <Text>{error.message}</Text>
      <Button title="Retry" onPress={() => {/* retry logic */}} />
    </View>
  )}
/>

Props

PropTypeDefaultDescription
name*string-Component name/key to load
dataobject-Props to pass to the dynamic component
projectIdstring-Override global project ID
miniappIdstring-Miniapp ID for error reporting and cache scoping. When provided, runtime errors are automatically reported.
miniappVersionstring-Miniapp version included in error reports for debugging
renderLoading() => ReactNode-Custom loading state renderer
renderError(error) => ReactNode-Custom error state renderer
runtimeDepsOverridesRecord<string, unknown>-Per-render runtime deps overrides (merged on top of default + registered deps). Keep object identity stable to avoid recompilation.

MiniappComponent

Renders a miniapp (collection of components) by ID. Useful for loading complete flows or screens with multiple components.

Basic Usage

TSX
import { MiniappComponent } from '@dpage-ai/react-native-dpage';

<MiniappComponent
  miniappId="checkout-flow"
  renderLoading={() => <LoadingView />}
  renderError={(error) => <ErrorView error={error} />}
  onLoaded={(result) => console.log('Miniapp loaded:', result)}
/>

Per-render Runtime Overrides

Apply overrides to all components inside a miniapp (useful for edit mode):

TSX
import React, { useMemo } from 'react';
import { MiniappComponent } from '@dpage-ai/react-native-dpage';

function MiniappPreview({ miniappId }: { miniappId: string }) {
  const editModeDeps = useMemo(
    () => ({
      Modal: InlineModal,
    }),
    []
  );

  return (
    <MiniappComponent
      miniappId={miniappId}
      runtimeDepsOverrides={editModeDeps}
    />
  );
}

Props

PropTypeDefaultDescription
miniappId*string-Miniapp identifier to load
renderLoading() => ReactNode-Custom loading state renderer
renderError(error) => ReactNode-Custom error state renderer
onLoaded(result) => void-Callback when miniapp finishes loading
runtimeDepsOverridesRecord<string, unknown>-Per-render runtime deps overrides (merged on top of default + registered deps). Keep object identity stable to avoid recompilation.

ErrorBoundary

A React error boundary component for catching runtime errors in miniapps. Both MiniappComponent and DynamicComponent automatically include an ErrorBoundary with proper miniapp context for error reporting, so you typically don't need to use this directly.

When to use ErrorBoundary directly

Use ErrorBoundary directly only when you need:
  • Custom retry/go-back handlers with the default error UI
  • To wrap custom content outside of MiniappComponent/DynamicComponent

Basic Usage

TSX
import { ErrorBoundary } from '@dpage-ai/react-native-dpage';

// With custom retry/go-back handlers (shows default error UI with buttons)
<ErrorBoundary
  miniappId="checkout-flow"
  miniappVersion="1.0.0"
  onRetry={() => setRetryKey(k => k + 1)}
  onGoBack={() => navigation.goBack()}
>
  <MyCustomContent />
</ErrorBoundary>

// With custom fallback UI
<ErrorBoundary
  miniappId="checkout-flow"
  fallback={(error, reset) => (
    <View>
      <Text>Error: {error.message}</Text>
      <Button onPress={reset} title="Try Again" />
    </View>
  )}
>
  <MyCustomContent />
</ErrorBoundary>

Props

PropTypeDefaultDescription
children*ReactNode-Content to render
miniappIdstring-Miniapp ID for automatic error reporting. When provided, errors are sent to the DPage server.
miniappVersionstring-Miniapp version included in error reports
fallback(error, reset) => ReactNode-Custom error UI. Receives the error and a reset function to retry.
onError(error, componentStack) => void-Callback when an error is caught. Called in addition to automatic reporting.
onRetry() => void-Called when "Try Again" is pressed. Shows the button when provided.
onGoBack() => void-Called when "Go Back" is pressed. Shows the button when provided.
reportErrorsboolean-Enable/disable error reporting for this boundary. Defaults to true when miniappId is set.

Automatic Error Reporting

Both MiniappComponent and DynamicComponent include built-in error boundaries that automatically report runtime errors to the DPage server when a miniappId is provided. This helps you monitor miniapp health in production.

TSX
// MiniappComponent - error reporting enabled automatically
<MiniappComponent
  miniappId="checkout-flow"
  renderError={(error) => <MyErrorUI error={error} />}
/>

// DynamicComponent within a miniapp context
const { rootComponentKey, version } = await loadMiniappComponents(miniappId);
<DynamicComponent
  name={rootComponentKey}
  miniappId={miniappId}
  miniappVersion={version}
  renderError={(error) => <MyErrorUI error={error} />}
/>

To disable error reporting globally, set errorReporting: false in your initDPage config:

TSX
initDPage({
  projectId: 'my-project',
  apiToken: 'dpage_live_xxx',
  errorReporting: false,  // Disable all automatic error reporting
});

Pro Tip

Always provide custom renderLoading and renderError props to match your app's design language.

Loading States

Components show a default loading spinner when fetching. Customize this with renderLoading to match your app's design:

TSX
import { View, ActivityIndicator, Text, StyleSheet } from 'react-native';

const CustomLoader = () => (
  <View style={styles.container}>
    <ActivityIndicator size="large" color="#3B82F6" />
    <Text style={styles.text}>Loading component...</Text>
  </View>
);

<DynamicComponent
  name="MyComponent"
  renderLoading={() => <CustomLoader />}
/>

Composing Components

Combine multiple dynamic components in your layouts:

TSX
function ProductScreen({ productId }: { productId: string }) {
  return (
    <ScrollView>
      <DynamicComponent
        name="ProductHeader"
        data={{ productId }}
      />
      <DynamicComponent
        name="ProductImages"
        data={{ productId }}
      />
      <DynamicComponent
        name="ProductDetails"
        data={{ productId }}
      />
      <DynamicComponent
        name="ProductReviews"
        data={{ productId }}
      />
    </ScrollView>
  );
}