Advanced Usage
Advanced patterns and techniques for the Lingu React Native SDK.
Custom Chat UI
Build your own chat interface using the useLinguChat hook:
tsx
import { useState, useEffect, useRef } from 'react';
import {
View,
Text,
TextInput,
FlatList,
TouchableOpacity,
StyleSheet,
KeyboardAvoidingView,
Platform,
} from 'react-native';
import { useLinguChat } from '@lingu/react-native-sdk';
export function CustomChatScreen() {
const [input, setInput] = useState('');
const flatListRef = useRef<FlatList>(null);
const {
messages,
isLoading,
sendMessage,
startSession,
endSession,
isSessionActive,
} = useLinguChat({
apiKey: process.env.EXPO_PUBLIC_LINGU_API_KEY!,
});
useEffect(() => {
startSession();
return () => {
endSession();
};
}, []);
useEffect(() => {
// Auto-scroll to bottom on new messages
if (messages.length > 0) {
flatListRef.current?.scrollToEnd();
}
}, [messages]);
const handleSend = async () => {
if (!input.trim() || isLoading) return;
const text = input;
setInput('');
await sendMessage(text);
};
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
>
<FlatList
ref={flatListRef}
data={messages}
keyExtractor={(item) => item.id}
contentContainerStyle={styles.messageList}
renderItem={({ item }) => (
<View style={[
styles.messageBubble,
item.sender === 'user' ? styles.userBubble : styles.botBubble,
]}>
<Text style={[
styles.messageText,
item.sender === 'user' && styles.userText,
]}>
{item.text}
</Text>
</View>
)}
/>
{isLoading && (
<View style={styles.typingIndicator}>
<Text style={styles.typingText}>AI is typing...</Text>
</View>
)}
<View style={styles.inputContainer}>
<TextInput
value={input}
onChangeText={setInput}
placeholder="Type a message..."
style={styles.input}
multiline
/>
<TouchableOpacity
onPress={handleSend}
style={[styles.sendButton, !input.trim() && styles.sendButtonDisabled]}
disabled={!input.trim() || isLoading}
>
<Text style={styles.sendButtonText}>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff' },
messageList: { padding: 16 },
messageBubble: { maxWidth: '80%', padding: 12, borderRadius: 16, marginVertical: 4 },
userBubble: { alignSelf: 'flex-end', backgroundColor: '#3b82f6' },
botBubble: { alignSelf: 'flex-start', backgroundColor: '#f3f4f6' },
messageText: { fontSize: 16 },
userText: { color: '#fff' },
typingIndicator: { padding: 16 },
typingText: { color: '#6b7280', fontStyle: 'italic' },
inputContainer: { flexDirection: 'row', padding: 12, borderTopWidth: 1, borderTopColor: '#e5e7eb' },
input: { flex: 1, borderWidth: 1, borderColor: '#d1d5db', borderRadius: 20, paddingHorizontal: 16, paddingVertical: 8, maxHeight: 100 },
sendButton: { marginLeft: 8, backgroundColor: '#3b82f6', borderRadius: 20, paddingHorizontal: 16, justifyContent: 'center' },
sendButtonDisabled: { backgroundColor: '#9ca3af' },
sendButtonText: { color: '#fff', fontWeight: '600' },
});Analytics Integration
Track chat events with your analytics provider:
tsx
import analytics from '@segment/analytics-react-native';
<LinguChat
apiKey="your-api-key"
onSessionStart={(sessionId) => {
analytics.track('Chat Started', { sessionId });
}}
onSessionEnd={(sessionId) => {
analytics.track('Chat Ended', { sessionId });
}}
onMessageSent={(message) => {
analytics.track('Chat Message Sent', {
message,
messageLength: message.length,
});
}}
onMessageReceived={(message) => {
analytics.track('Chat Response Received', {
response: message.substring(0, 100), // First 100 chars
});
}}
/>Navigation Integration
React Navigation
Open chat as a modal screen:
tsx
// navigation/types.ts
export type RootStackParamList = {
Home: undefined;
Chat: undefined;
};
// screens/ChatScreen.tsx
import { useNavigation } from '@react-navigation/native';
import { LinguChat } from '@lingu/react-native-sdk';
export function ChatScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1 }}>
<LinguChat
apiKey="your-api-key"
showBackButton={true}
onBackPress={() => navigation.goBack()}
/>
</View>
);
}
// App.tsx
<Stack.Screen
name="Chat"
component={ChatScreen}
options={{
presentation: 'modal',
headerShown: false,
}}
/>Expo Integration
Environment Variables
bash
# .env
EXPO_PUBLIC_LINGU_API_KEY=lingu_abc123tsx
<LinguChat
apiKey={process.env.EXPO_PUBLIC_LINGU_API_KEY!}
/>Development Build
For production, create a development build:
bash
npx expo prebuild
npx expo run:ios
# or
npx expo run:androidEAS Build
bash
eas build --platform allConditional Rendering
Show Only When Authenticated
tsx
function App() {
const { user, isAuthenticated } = useAuth();
return (
<View style={{ flex: 1 }}>
{/* Your app content */}
{isAuthenticated && (
<LinguChat
apiKey="your-api-key"
onSessionStart={(id) => {
// Associate session with user
api.associateUser(id, user.id);
}}
/>
)}
</View>
);
}Show on Specific Screens
tsx
function ProductScreen({ route }) {
const showChat = route.params?.showSupport ?? false;
return (
<View style={{ flex: 1 }}>
{/* Product content */}
{showChat && (
<LinguChat apiKey="your-api-key" autoOpen={true} />
)}
</View>
);
}Session Persistence
Messages are automatically persisted using AsyncStorage. To clear history:
typescript
import AsyncStorage from '@react-native-async-storage/async-storage';
async function clearChatHistory() {
await AsyncStorage.removeItem('lingu_messages');
await AsyncStorage.removeItem('lingu_session');
}Error Handling
Wrap the component with error boundary:
tsx
import { ErrorBoundary } from 'react-error-boundary';
function ChatErrorFallback({ error, resetErrorBoundary }) {
return (
<View style={{ padding: 20 }}>
<Text>Chat temporarily unavailable</Text>
<Button title="Try Again" onPress={resetErrorBoundary} />
</View>
);
}
function App() {
return (
<ErrorBoundary FallbackComponent={ChatErrorFallback}>
<LinguChat apiKey="your-api-key" />
</ErrorBoundary>
);
}Performance Tips
- Lazy Load: Only mount
LinguChatwhen needed - Memoize Callbacks: Use
useCallbackfor event handlers - Limit Re-renders: Don't pass new object references as props
- Clean Up: Unmount the component when navigating away
tsx
const handleSessionStart = useCallback((id: string) => {
console.log('Session:', id);
}, []);
<LinguChat
apiKey="your-api-key"
onSessionStart={handleSessionStart}
/>