Follow these best practices to maintain code quality, performance, and maintainability in your React Native application.
Clean, readable code
Optimized for speed
Secure by design
Comprehensive testing
Writing clean, maintainable, and readable code
// Define clear interfaces
interface User {
id: string
name: string
email: string
avatar?: string
}
// Use strict typing for props
interface ButtonProps {
title: string
onPress: () => void
variant?: 'primary' | 'secondary'
disabled?: boolean
}
// Leverage union types
type Status = 'loading' | 'success' | 'error'
// Use generics for reusable components
interface ApiResponse<T> {
data: T
message: string
success: boolean
}// Don't use 'any' type
const data: any = fetchUserData()
// Don't skip prop validation
const Button = ({ title, onPress }) => { ... }
// Don't use unclear naming
interface Props {
a: string
b: number
c: boolean
}// Good component structure
import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native'
import { useTheme } from '@/hooks/useTheme'
import { ButtonProps } from './Button.types'
import { styles } from './Button.styles'
export const Button: React.FC<ButtonProps> = ({
title,
onPress,
variant = 'primary',
disabled = false,
testID
}) => {
const { colors } = useTheme()
const buttonStyle = [
styles.button,
styles[variant],
disabled && styles.disabled,
{ borderColor: colors.border }
]
return (
<TouchableOpacity
style={buttonStyle}
onPress={onPress}
disabled={disabled}
testID={testID}
accessibilityRole="button"
accessibilityLabel={title}
>
<Text style={[styles.text, { color: colors.text }]}>
{title}
</Text>
</TouchableOpacity>
)
}
Button.displayName = 'Button'components/atoms/Button/
├── Button.tsx # Main component
├── Button.types.ts # TypeScript interfaces
├── Button.styles.ts # Styles (if complex)
├── Button.test.tsx # Unit tests
├── Button.stories.tsx # Storybook stories (optional)
└── index.ts # Barrel export
// index.ts
export { Button } from './Button'
export type { ButtonProps } from './Button.types'Techniques to ensure smooth and fast app performance
// Use React.memo for expensive components
export const ExpensiveComponent = React.memo<Props>(({ data, onAction }) => {
// Expensive rendering logic
return <ComplexView data={data} onAction={onAction} />
}, (prevProps, nextProps) => {
// Custom comparison function
return prevProps.data.id === nextProps.data.id
})
// Use useCallback for event handlers
const MyComponent = () => {
const [count, setCount] = useState(0)
const handlePress = useCallback(() => {
setCount(prev => prev + 1)
}, [])
return <Button onPress={handlePress} title={`Count: ${count}`} />
}
// Use useMemo for expensive calculations
const MyComponent = ({ items }) => {
const expensiveValue = useMemo(() => {
return items.reduce((sum, item) => sum + item.value, 0)
}, [items])
return <Text>{expensiveValue}</Text>
}// Use FlashList for better performance
import { FlashList } from '@shopify/flash-list'
const ItemsList = ({ data }) => {
const renderItem = useCallback(({ item }) => (
<ItemComponent key={item.id} item={item} />
), [])
return (
<FlashList
data={data}
renderItem={renderItem}
estimatedItemSize={100}
keyExtractor={(item) => item.id}
// Optimize rendering
removeClippedSubviews={true}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
windowSize={10}
/>
)
}// Use FastImage for better image performance
import FastImage from 'react-native-fast-image'
const OptimizedImage = ({ uri, style }) => (
<FastImage
style={style}
source={{
uri,
priority: FastImage.priority.normal,
cache: FastImage.cacheControl.immutable,
}}
resizeMode={FastImage.resizeMode.cover}
fallback={true}
/>
)Comprehensive testing strategies for reliable applications
70% - Test individual functions and components
20% - Test component interactions
10% - Test complete user flows
// Button.test.tsx
import React from 'react'
import { render, fireEvent } from '@testing-library/react-native'
import { Button } from './Button'
describe('Button Component', () => {
it('renders correctly with title', () => {
const { getByText } = render(
<Button title="Click me" onPress={() => {}} />
)
expect(getByText('Click me')).toBeTruthy()
})
it('calls onPress when pressed', () => {
const mockOnPress = jest.fn()
const { getByText } = render(
<Button title="Click me" onPress={mockOnPress} />
)
fireEvent.press(getByText('Click me'))
expect(mockOnPress).toHaveBeenCalledTimes(1)
})
it('is disabled when disabled prop is true', () => {
const mockOnPress = jest.fn()
const { getByText } = render(
<Button title="Click me" onPress={mockOnPress} disabled />
)
fireEvent.press(getByText('Click me'))
expect(mockOnPress).not.toHaveBeenCalled()
})
})// useAuth.test.ts
import { renderHook, act } from '@testing-library/react-native'
import { useAuth } from './useAuth'
describe('useAuth Hook', () => {
it('should initialize with default values', () => {
const { result } = renderHook(() => useAuth())
expect(result.current.user).toBeNull()
expect(result.current.isAuthenticated).toBe(false)
})
it('should login user correctly', async () => {
const { result } = renderHook(() => useAuth())
await act(async () => {
await result.current.login('user@example.com', 'password')
})
expect(result.current.isAuthenticated).toBe(true)
expect(result.current.user).not.toBeNull()
})
})Protecting your application and user data
// services/secureStorage.ts
import { MMKV } from 'react-native-mmkv'
// Create encrypted storage instance
const secureStorage = new MMKV({
id: 'secure-storage',
encryptionKey: 'your-encryption-key'
})
export const SecureStorage = {
setItem: (key: string, value: string) => {
secureStorage.set(key, value)
},
getItem: (key: string): string | undefined => {
return secureStorage.getString(key)
},
removeItem: (key: string) => {
secureStorage.delete(key)
},
clear: () => {
secureStorage.clearAll()
}
}Efficient development processes and tools
# Pre-commit hooks (Husky)
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"pre-push": "npm test"
}
}
# Lint-staged configuration
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md}": [
"prettier --write"
]
}Use this checklist before releasing new features