Skip to main content

createApp

The createApp function initializes a new Refract application instance. It serves as the entry point for your application, handling the root component setup and providing configuration options for the entire application.

Syntax

const app = createApp(RootComponent, options?);
const unmount = app.mount(container);

Parameters

RootComponent

  • Type: Component
  • Required: Yes
  • Description: The root component that will serve as the entry point for your application

options

  • Type: AppOptions
  • Required: No
  • Description: Configuration options for the application
interface AppOptions {
// Development mode settings
devMode?: boolean;

// Error handling
errorBoundary?: Component;
onError?: (error: Error, errorInfo: any) => void;

// Performance settings
batchUpdates?: boolean;

// Plugin system
plugins?: Plugin[];
}

Mounting the Application

After creating your application with createApp, you need to mount it to a DOM element using the mount method.

app.mount(container)

Mounts the application to the specified container.

Parameters

  • container: string | HTMLElement - A DOM element or a CSS selector string where the app will be mounted

Returns

  • Function - A function to unmount the application

Example

// Mount to a DOM element
const container = document.getElementById('app');
const unmount = app.mount(container);

// Later, you can unmount the app
// unmount();

Return Value

Returns an App instance with the following methods:

interface App {
/**
* Mounts the application to the specified container
* @param container - A DOM element or selector string where the app will be mounted
* @returns A function to unmount the application
*/
mount(container: string | Element): () => void;

/**
* Unmounts the application from the DOM
*/
unmount(): void;

/**
* Gets the current application configuration
*/
getConfig(): AppConfig;

/**
* Registers a plugin with the application
* @param plugin - The plugin to register
* @returns The app instance for chaining
*/
use(plugin: Plugin): App;
}

Basic Usage

Simple Application

import { createApp, createComponent } from 'refract';

const App = createComponent(({ lens }) => {
const message = lens.useRefraction('Hello, Refract!');

return (
<div>
<h1>{message.value}</h1>
<button onClick={() => message.set('Updated!')}>
Update Message
</button>
</div>
);
});

// Create and mount the application
const app = createApp(App);
app.mount('#root');

Application with Configuration

import { createApp, createComponent } from 'refract';

const ErrorBoundary = createComponent(({ lens, children, error }) => {
if (error) {
return (
<div className="error-boundary">
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
);
}

return children;
});

const App = createComponent(({ lens }) => {
return (
<div>
<h1>My Refract App</h1>
</div>
);
});

const app = createApp(App, {
devMode: process.env.NODE_ENV === 'development',
errorBoundary: ErrorBoundary,
onError: (error, errorInfo) => {
console.error('Application error:', error, errorInfo);
// Send to error reporting service
},
batchUpdates: true
});

app.mount('#root');

App Instance Methods

mount(selector)

Mounts the application to a DOM element.

Parameters

  • selector (string | Element): CSS selector string or DOM element

Example

const app = createApp(App);

// Mount using CSS selector
app.mount('#root');

// Mount using DOM element
const rootElement = document.getElementById('root');
app.mount(rootElement);

// Mount to body
app.mount(document.body);

unmount()

Unmounts the application and cleans up all resources.

Example

const app = createApp(App);
app.mount('#root');

// Later, unmount the application
app.unmount();

use(plugin)

Adds a plugin to the application.

Parameters

  • plugin (Plugin): Plugin instance to add

Example

import { createApp } from 'refract';
import { routerPlugin } from '@refract/router';
import { devToolsPlugin } from '@refract/devtools';

const app = createApp(App)
.use(routerPlugin({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
}))
.use(devToolsPlugin());

app.mount('#root');

Configuration Options

Development Mode

Enable development features like detailed error messages and performance warnings:

const app = createApp(App, {
devMode: true // Enables development features
});

Error Handling

Global Error Boundary

const GlobalErrorBoundary = createComponent(({ lens, children, error }) => {
const hasError = lens.useRefraction(false);

lens.useEffect(() => {
if (error) {
hasError.set(true);
}
}, [error]);

if (hasError.value) {
return (
<div className="global-error">
<h1>Oops! Something went wrong</h1>
<details>
<summary>Error details</summary>
<pre>{error?.stack}</pre>
</details>
<button onClick={() => hasError.set(false)}>
Try Again
</button>
</div>
);
}

return children;
});

const app = createApp(App, {
errorBoundary: GlobalErrorBoundary,
onError: (error, errorInfo) => {
// Log to external service
console.error('Global error:', error);

// Send to analytics
analytics.track('application_error', {
error: error.message,
stack: error.stack,
componentStack: errorInfo.componentStack
});
}
});

Custom Error Handler

const app = createApp(App, {
onError: (error, errorInfo) => {
// Custom error handling logic
if (error.name === 'ChunkLoadError') {
// Handle code splitting errors
window.location.reload();
} else {
// Send to error reporting service
errorReportingService.captureException(error, {
extra: errorInfo
});
}
}
});

Performance Configuration

const app = createApp(App, {
batchUpdates: true, // Batch state updates for better performance

// Custom batching configuration
batchingOptions: {
maxBatchSize: 100,
batchTimeout: 16 // ~60fps
}
});

Advanced Usage

Multiple App Instances

// Main application
const mainApp = createApp(MainApp);
mainApp.mount('#main-app');

// Widget application (separate instance)
const widgetApp = createApp(WidgetApp);
widgetApp.mount('#widget');

// Both apps can run independently

App with Plugins

import { createApp } from 'refract';
import { routerPlugin } from '@refract/router';
import { storePlugin } from '@refract/store';
import { i18nPlugin } from '@refract/i18n';

const app = createApp(App)
.use(routerPlugin({
mode: 'history',
base: '/app/'
}))
.use(storePlugin({
modules: {
user: userStore,
cart: cartStore
}
}))
.use(i18nPlugin({
locale: 'en',
messages: {
en: englishMessages,
es: spanishMessages
}
}));

app.mount('#root');

Server-Side Rendering

// server.js
import { createApp, renderToString } from 'refract';
import App from './App';

const app = createApp(App, {
// SSR-specific configuration
ssr: true,
hydrate: false
});

const html = await renderToString(app);

// client.js
import { createApp } from 'refract';
import App from './App';

const app = createApp(App, {
hydrate: true // Enable hydration mode
});

app.mount('#root');

Error Scenarios

Mount Errors

const app = createApp(App);

try {
app.mount('#nonexistent');
} catch (error) {
console.error('Mount failed:', error.message);
// Fallback: mount to body
app.mount(document.body);
}

Component Errors

const BuggyComponent = createComponent(({ lens }) => {
lens.useEffect(() => {
throw new Error('Something went wrong!');
}, []);

return <div>This won't render due to error</div>;
});

const App = createComponent(({ lens }) => {
return (
<div>
<h1>My App</h1>
<BuggyComponent />
</div>
);
});

const app = createApp(App, {
onError: (error, errorInfo) => {
console.error('Component error caught:', error);
// Error is handled, app continues running
}
});

Testing

Testing App Creation

import { createApp } from 'refract';
import { render } from '@refract/testing-utils';

describe('App Creation', () => {
test('creates app instance', () => {
const TestComponent = createComponent(() => <div>Test</div>);
const app = createApp(TestComponent);

expect(app).toBeDefined();
expect(typeof app.mount).toBe('function');
expect(typeof app.unmount).toBe('function');
});

test('mounts and unmounts correctly', () => {
const TestComponent = createComponent(() => <div>Test</div>);
const app = createApp(TestComponent);

const container = document.createElement('div');
document.body.appendChild(container);

app.mount(container);
expect(container.innerHTML).toContain('Test');

app.unmount();
expect(container.innerHTML).toBe('');

document.body.removeChild(container);
});
});

Testing with Configuration

test('handles errors correctly', () => {
const errorSpy = jest.fn();

const BuggyComponent = createComponent(() => {
throw new Error('Test error');
});

const app = createApp(BuggyComponent, {
onError: errorSpy
});

const container = document.createElement('div');
app.mount(container);

expect(errorSpy).toHaveBeenCalledWith(
expect.objectContaining({ message: 'Test error' }),
expect.any(Object)
);
});

Best Practices

1. Single App Instance

// ✅ Good - Single app instance
const app = createApp(App);
app.mount('#root');

// ❌ Bad - Multiple instances for same app
const app1 = createApp(App);
const app2 = createApp(App);

2. Proper Error Handling

// ✅ Good - Comprehensive error handling
const app = createApp(App, {
errorBoundary: ErrorBoundary,
onError: (error, errorInfo) => {
logError(error, errorInfo);
reportToService(error);
}
});

// ❌ Bad - No error handling
const app = createApp(App);

3. Environment-Specific Configuration

// ✅ Good - Environment-aware configuration
const app = createApp(App, {
devMode: process.env.NODE_ENV === 'development',
onError: process.env.NODE_ENV === 'production'
? reportToService
: console.error
});

4. Graceful Cleanup

// ✅ Good - Proper cleanup
window.addEventListener('beforeunload', () => {
app.unmount();
});

// Handle hot module replacement in development
if (module.hot) {
module.hot.accept('./App', () => {
app.unmount();
const NextApp = require('./App').default;
const newApp = createApp(NextApp);
newApp.mount('#root');
});
}