Advanced Customization Techniques
Advanced Customization Techniques
This guide covers advanced techniques for customizing ZEROCODE-generated apps beyond the visual editor. You'll learn to add custom components, integrate external services, and optimize performance.
Prerequisites
- Completed "Getting Started with ZEROCODE"
- Basic understanding of React Native
- Familiarity with JavaScript/TypeScript
- ZEROCODE Pro plan (for code export)
Table of Contents
- Exporting Source Code
- Custom Components
- Advanced State Management
- Third-Party Integrations
- Performance Optimization
- Custom Backend Logic
Exporting Source Code
Why Export?
While ZEROCODE's visual editor is powerful, you may need to:
- Add complex custom logic
- Integrate specialized libraries
- Optimize for specific use cases
- Maintain code in your own repository
How to Export
-
Navigate to Project Settings
-
Click "Export Code"
-
Choose export format:
- Expo Managed: Easiest, stays in Expo ecosystem
- Expo Bare: More control, can add native modules
- Full Source: Complete React Native project
-
Download ZIP file
Project Structure
my-app/
├── src/
│ ├── components/ # UI components
│ ├── screens/ # Screen components
│ ├── navigation/ # Navigation config
│ ├── services/ # API calls
│ ├── hooks/ # Custom hooks
│ └── utils/ # Helper functions
├── assets/ # Images, fonts
├── supabase/ # Backend config
└── app.json # Expo config
Custom Components
Creating a Custom Component
Let's build a custom chart component using Victory Native:
// src/components/CustomChart.tsx
import React from 'react';
import { View } from 'react-native';
import { VictoryChart, VictoryLine, VictoryTheme } from 'victory-native';
interface DataPoint {
x: number;
y: number;
}
interface CustomChartProps {
data: DataPoint[];
color?: string;
}
export const CustomChart: React.FC<CustomChartProps> = ({
data,
color = '#006BF7'
}) => {
return (
<View style={{ height: 300 }}>
<VictoryChart theme={VictoryTheme.material}>
<VictoryLine
data={data}
style={{
data: { stroke: color, strokeWidth: 3 }
}}
/>
</VictoryChart>
</View>
);
};
Installing Dependencies
npm install victory-native
Using Custom Components
// src/screens/DashboardScreen.tsx
import { CustomChart } from '../components/CustomChart';
export const DashboardScreen = () => {
const chartData = [
{ x: 1, y: 2 },
{ x: 2, y: 3 },
{ x: 3, y: 5 },
{ x: 4, y: 4 },
];
return (
<View>
<CustomChart data={chartData} color="#4f46e5" />
</View>
);
};
Advanced State Management
Using Zustand
For complex state, we recommend Zustand:
// src/stores/userStore.ts
import create from 'zustand';
interface UserState {
user: User | null;
setUser: (user: User) => void;
logout: () => void;
}
export const useUserStore = create<UserState>((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}));
Usage in Components
import { useUserStore } from '../stores/userStore';
export const ProfileScreen = () => {
const { user, logout } = useUserStore();
return (
<View>
<Text>{user?.name}</Text>
<Button onPress={logout} title="Logout" />
</View>
);
};
Third-Party Integrations
Stripe Payments
// src/services/stripe.ts
import { stripe } from '@stripe/stripe-react-native';
export const processPayment = async (amount: number) => {
try {
const paymentIntent = await createPaymentIntent(amount);
const { error } = await stripe.confirmPayment(
paymentIntent.client_secret,
{
type: 'Card',
}
);
if (error) {
throw new Error(error.message);
}
return { success: true };
} catch (error) {
console.error('Payment failed:', error);
return { success: false, error };
}
};
Google Maps Integration
// src/components/MapView.tsx
import MapView, { Marker } from 'react-native-maps';
export const CustomMapView = ({ locations }) => {
return (
<MapView
style={{ flex: 1 }}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
{locations.map((location, index) => (
<Marker
key={index}
coordinate={{
latitude: location.lat,
longitude: location.lng,
}}
title={location.name}
/>
))}
</MapView>
);
};
Performance Optimization
Memoization
import React, { useMemo } from 'react';
export const ExpensiveComponent = ({ data }) => {
const processedData = useMemo(() => {
return data.map(item => ({
...item,
computed: expensiveCalculation(item)
}));
}, [data]);
return <ListView data={processedData} />;
};
Image Optimization
import FastImage from 'react-native-fast-image';
export const OptimizedImage = ({ uri }) => {
return (
<FastImage
source={{
uri,
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.cover}
style={{ width: 200, height: 200 }}
/>
);
};
List Performance
import { FlashList } from '@shopify/flash-list';
export const OptimizedList = ({ items }) => {
return (
<FlashList
data={items}
renderItem={({ item }) => <ItemCard item={item} />}
estimatedItemSize={100}
keyExtractor={(item) => item.id}
/>
);
};
Custom Backend Logic
Supabase Edge Functions
Create custom serverless functions:
// supabase/functions/send-notification/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
const { userId, message } = await req.json();
// Custom logic
await sendPushNotification(userId, message);
return new Response(
JSON.stringify({ success: true }),
{ headers: { 'Content-Type': 'application/json' } }
);
});
Calling Edge Functions
import { supabase } from '../services/supabase';
export const sendNotification = async (userId: string, message: string) => {
const { data, error } = await supabase.functions.invoke('send-notification', {
body: { userId, message }
});
if (error) throw error;
return data;
};
Advanced Patterns
Custom Hooks
// src/hooks/useDebounce.ts
import { useState, useEffect } from 'react';
export const useDebounce = <T,>(value: T, delay: number): T => {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
}, [value, delay]);
return debouncedValue;
};
Error Boundaries
import React from 'react';
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Error caught:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <ErrorScreen />;
}
return this.props.children;
}
}
Testing
Unit Tests
import { render, fireEvent } from '@testing-library/react-native';
import { LoginScreen } from '../screens/LoginScreen';
describe('LoginScreen', () => {
it('should handle login', () => {
const { getByPlaceholderText, getByText } = render(<LoginScreen />);
fireEvent.changeText(getByPlaceholderText('Email'), 'test@example.com');
fireEvent.changeText(getByPlaceholderText('Password'), 'password123');
fireEvent.press(getByText('Login'));
// Assert login was called
});
});
Deployment Considerations
Environment Variables
// app.config.js
export default {
expo: {
extra: {
apiUrl: process.env.API_URL,
stripeKey: process.env.STRIPE_KEY,
}
}
};
CI/CD Pipeline
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm install
- run: npm test
- run: eas build --platform all
Conclusion
You now have the tools to:
- Export and customize ZEROCODE apps
- Add complex custom components
- Integrate third-party services
- Optimize performance
- Implement advanced patterns
Keep experimenting and building!
Need help? Join our Discord community or check the documentation.