Mapplets
Mapplets are the core building blocks of Mapples applications. They are self-contained components that integrate with the Mapples ecosystem to provide interactive, data-driven experiences. This guide shows you how to create and use Mapplets effectively.
What is a Mapplet?
A Mapplet is a React component that leverages Mapples packages to create rich, interactive interfaces. It combines:
- @mapples/render - For rendering UI components
- @mapples/types - For TypeScript type definitions
- @mapples/action - For handling user interactions
- @mapples/state - For managing application state
Auto-Generated Mapplet Example
When you run Mapples CLI commands, they automatically generate Mapplet components for you. You can generate Mapplets using any of the following commands:
npx @mapples/cli init
npx @mapples/cli sync
npx @mapples/cli pages --sync
Here's an example of what an auto-generated Mapplet looks like after running these commands:
import { RenderComponent } from '@mapples/render';
import { MappletType } from '@mapples/types';
import ActionProvider from '@mapples/action';
import StateProvider from '@mapples/state';
import { root } from './Home.json';
// @todo: This Mapplet can be updated
// read docs of how you can customize it: https://docs.com
export type HomeMappletProps<T extends object> = MappletType<T> & {};
export default function HomeMapplet<State extends object = object>({
state,
onAction,
}: HomeMappletProps<State>) {
return (
<StateProvider state={state}>
<ActionProvider onAction={onAction}>
<RenderComponent {...root} />
</ActionProvider>
</StateProvider>
);
}
Key Components Explained
- StateProvider: Provides state management context to child components
- ActionProvider: Handles user interactions and action dispatching
- RenderComponent: Renders the UI based on the JSON configuration from Mapples Creator
- MappletType: TypeScript interface that ensures type safety for your Mapplet props
Using Mapplets in Expo Router
Once you have created a Mapplet, you can use it in your Expo application. Here's how to integrate it at the top level using Expo Router:
In your app/index.tsx
:
import React from 'react';
import { View, StyleSheet } from 'react-native';
import HomeMapplet from '../components/HomeMapplet';
// Define your application state
const appState = {
user: {
name: 'John Doe',
email: 'john@example.com',
preferences: {
theme: 'light',
language: 'en'
}
},
navigation: {
currentScreen: 'home',
history: []
},
content: {
title: 'Welcome to Mapples',
description: 'Build amazing apps with ease'
}
};
export default function HomeScreen() {
// Handle actions from the Mapplet
const handleMappletAction = (action: any) => {
console.log('Action received:', action);
// Handle different action types
switch (action.type) {
case 'NAVIGATE':
// Handle navigation
console.log('Navigate to:', action.payload.screen);
break;
case 'UPDATE_USER':
// Handle user updates
console.log('Update user:', action.payload);
break;
default:
console.log('Unknown action:', action);
}
};
return (
<View style={styles.container}>
<HomeMapplet
state={appState}
onAction={handleMappletAction}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
Advanced Usage with Dynamic State
For more complex applications, you might want to manage state dynamically:
import React, { useState, useCallback } from 'react';
import { View } from 'react-native';
import HomeMapplet from '../components/HomeMapplet';
export default function HomeScreen() {
const [appState, setAppState] = useState({
user: { name: 'John Doe', email: 'john@example.com' },
settings: { theme: 'light', notifications: true },
data: { items: [], loading: false }
});
const handleMappletAction = useCallback((action: any) => {
switch (action.type) {
case 'UPDATE_SETTINGS':
setAppState(prev => ({
...prev,
settings: { ...prev.settings, ...action.payload }
}));
break;
case 'LOAD_DATA':
setAppState(prev => ({ ...prev, data: { ...prev.data, loading: true } }));
// Simulate API call
setTimeout(() => {
setAppState(prev => ({
...prev,
data: { items: ['Item 1', 'Item 2'], loading: false }
}));
}, 1000);
break;
default:
console.log('Unhandled action:', action);
}
}, []);
return (
<View style={{ flex: 1 }}>
<HomeMapplet
state={appState}
onAction={handleMappletAction}
/>
</View>
);
}
Best Practices
- Memoization: Use
useCallback
for action handlers to prevent unnecessary re-renders - Component Optimization: Apply
React.memo
for expensive Mapplet components - Immutable Updates: Keep state updates immutable for predictable behavior
- Lazy Loading: Consider lazy loading for large Mapplets to improve initial load times
- Keep your state structure flat and organized for better maintainability
- Use meaningful names for state properties that clearly describe their purpose
- Provide default values for optional data to prevent undefined errors
- Structure your state to separate UI state from business logic
- Keep Mapplets in a dedicated
components
ormapplets
directory for better project structure - Use consistent naming conventions (e.g.,
HomeMapplet
,ProfileMapplet
) across your project - Document your custom Mapplets with JSDoc comments for better developer experience
- Always handle actions with proper error boundaries and TypeScript for type safety
- Use TypeScript for action type safety and better development experience
- Log actions during development for debugging and monitoring
- Test your Mapplets with different state configurations
- Follow React best practices for component lifecycle and state management
What's Next?
🎯 Handling Actions
Learn how to handle user interactions and create responsive Mapplets.
Action Handling →