| 1 |
Components |
Use functional components |
Hooks-based components are standard |
Functional components with hooks |
Class components |
const App = () => { } |
class App extends Component |
Medium |
React Native Docs |
| 2 |
Components |
Keep components small |
Single responsibility principle |
Split into smaller components |
Large monolithic components |
|
500+ line component |
Medium |
- |
| 3 |
Components |
Use TypeScript |
Type safety for props and state |
TypeScript for new projects |
JavaScript without types |
const Button: FC = () => { } |
const Button = (props) => { } |
Medium |
- |
| 4 |
Components |
Colocate component files |
Keep related files together |
Component folder with styles |
Flat structure |
components/Button/index.tsx styles.ts |
components/Button.tsx styles/button.ts |
Low |
- |
| 5 |
Styling |
Use StyleSheet.create |
Optimized style objects |
StyleSheet for all styles |
Inline style objects |
StyleSheet.create({ container: {} }) |
style={{ margin: 10 }} |
High |
React Native Docs |
| 6 |
Styling |
Avoid inline styles |
Prevent object recreation |
Styles in StyleSheet |
Inline style objects in render |
style={styles.container} |
"style={{ margin: 10, padding: 5 }}" |
Medium |
- |
| 7 |
Styling |
Use flexbox for layout |
React Native uses flexbox |
flexDirection alignItems justifyContent |
Absolute positioning everywhere |
flexDirection: 'row' |
position: 'absolute' everywhere |
Medium |
React Native Docs |
| 8 |
Styling |
Handle platform differences |
Platform-specific styles |
Platform.select or .ios/.android files |
Same styles for both platforms |
"Platform.select({ ios: {}, android: {} })" |
Hardcoded iOS values |
Medium |
React Native Docs |
| 9 |
Styling |
Use responsive dimensions |
Scale for different screens |
Dimensions or useWindowDimensions |
Fixed pixel values |
useWindowDimensions() |
width: 375 |
Medium |
- |
| 10 |
Navigation |
Use React Navigation |
Standard navigation library |
React Navigation for routing |
Manual navigation management |
createStackNavigator() |
Custom navigation state |
Medium |
React Navigation |
| 11 |
Navigation |
Type navigation params |
Type-safe navigation |
Typed navigation props |
Untyped navigation |
"navigation.navigate('Home', { id })" |
"navigation.navigate('Home', { id })" |
Medium |
- |
| 12 |
Navigation |
Use deep linking |
Support URL-based navigation |
Configure linking prop |
No deep link support |
linking: { prefixes: [] } |
No linking configuration |
Medium |
React Navigation Docs |
| 13 |
Navigation |
Handle back button |
Android back button handling |
useFocusEffect with BackHandler |
Ignore back button |
BackHandler.addEventListener |
No back handler |
High |
- |
| 14 |
State |
Use useState for local state |
Simple component state |
useState for UI state |
Class component state |
"const [count, setCount] = useState(0)" |
this.state = { count: 0 } |
Medium |
- |
| 15 |
State |
Use useReducer for complex state |
Complex state logic |
useReducer for related state |
Multiple useState for related values |
useReducer(reducer initialState) |
5+ useState calls |
Medium |
- |
| 16 |
State |
Use context sparingly |
Context for global state |
Context for theme auth locale |
Context for frequently changing data |
ThemeContext for app theme |
Context for list item data |
Medium |
- |
| 17 |
State |
Consider Zustand or Redux |
External state management |
Zustand for simple Redux for complex |
useState for global state |
create((set) => ({ })) |
Prop drilling global state |
Medium |
- |
| 18 |
Lists |
Use FlatList for long lists |
Virtualized list rendering |
FlatList for 50+ items |
ScrollView with map |
|
{items.map()} |
High |
React Native Docs |
| 19 |
Lists |
Provide keyExtractor |
Unique keys for list items |
keyExtractor with stable ID |
Index as key |
keyExtractor={(item) => item.id} |
"keyExtractor={(_, index) => index}" |
High |
- |
| 20 |
Lists |
Optimize renderItem |
Memoize list item components |
React.memo for list items |
Inline render function |
renderItem={({ item }) => } |
renderItem={({ item }) => ...} |
High |
- |
| 21 |
Lists |
Use getItemLayout for fixed height |
Skip measurement for performance |
getItemLayout when height known |
Dynamic measurement for fixed items |
"getItemLayout={(_, index) => ({ length: 50, offset: 50 * index, index })}" |
No getItemLayout for fixed height |
Medium |
- |
| 22 |
Lists |
Implement windowSize |
Control render window |
Smaller windowSize for memory |
Default windowSize for large lists |
windowSize={5} |
windowSize={21} for huge lists |
Medium |
- |
| 23 |
Performance |
Use React.memo |
Prevent unnecessary re-renders |
memo for pure components |
No memoization |
export default memo(MyComponent) |
export default MyComponent |
Medium |
- |
| 24 |
Performance |
Use useCallback for handlers |
Stable function references |
useCallback for props |
New function on every render |
"useCallback(() => {}, [deps])" |
() => handlePress() |
Medium |
- |
| 25 |
Performance |
Use useMemo for expensive ops |
Cache expensive calculations |
useMemo for heavy computations |
Recalculate every render |
"useMemo(() => expensive(), [deps])" |
const result = expensive() |
Medium |
- |
| 26 |
Performance |
Avoid anonymous functions in JSX |
Prevent re-renders |
Named handlers or useCallback |
Inline arrow functions |
onPress={handlePress} |
onPress={() => doSomething()} |
Medium |
- |
| 27 |
Performance |
Use Hermes engine |
Improved startup and memory |
Enable Hermes in build |
JavaScriptCore for new projects |
hermes_enabled: true |
hermes_enabled: false |
Medium |
React Native Docs |
| 28 |
Images |
Use expo-image |
Modern performant image component for React Native |
"Use expo-image for caching, blurring, and performance" |
Use default Image for heavy lists or unmaintained libraries |
(expo-image) |
|
Medium |
Expo Image Docs |
| 29 |
Images |
Specify image dimensions |
Prevent layout shifts |
width and height for remote images |
No dimensions for network images |
<Image style={{ width: 100 height: 100 }} /> |
<Image source={{ uri }} /> no size |
High |
- |
| 30 |
Images |
Use resizeMode |
Control image scaling |
resizeMode cover contain |
Stretch images |
"resizeMode=""cover""" |
No resizeMode |
Low |
- |
| 31 |
Forms |
Use controlled inputs |
State-controlled form fields |
value + onChangeText |
Uncontrolled inputs |
|
|
Medium |
- |
| 32 |
Forms |
Handle keyboard |
Manage keyboard visibility |
KeyboardAvoidingView |
Content hidden by keyboard |
"<KeyboardAvoidingView behavior=""padding"">" |
No keyboard handling |
High |
React Native Docs |
| 33 |
Forms |
Use proper keyboard types |
Appropriate keyboard for input |
keyboardType for input type |
Default keyboard for all |
"keyboardType=""email-address""" |
"keyboardType=""default"" for email" |
Low |
- |
| 34 |
Touch |
Use Pressable |
Modern touch handling |
Pressable for touch interactions |
TouchableOpacity for new code |
|
|
Low |
React Native Docs |
| 35 |
Touch |
Provide touch feedback |
Visual feedback on press |
Ripple or opacity change |
No feedback on press |
android_ripple={{ color: 'gray' }} |
No press feedback |
Medium |
- |
| 36 |
Touch |
Set hitSlop for small targets |
Increase touch area |
hitSlop for icons and small buttons |
Tiny touch targets |
hitSlop={{ top: 10 bottom: 10 }} |
44x44 with no hitSlop |
Medium |
- |
| 37 |
Animation |
Use Reanimated |
High-performance animations |
react-native-reanimated |
Animated API for complex |
useSharedValue useAnimatedStyle |
Animated.timing for gesture |
Medium |
Reanimated Docs |
| 38 |
Animation |
Run on UI thread |
worklets for smooth animation |
Run animations on UI thread |
JS thread animations |
runOnUI(() => {}) |
Animated on JS thread |
High |
- |
| 39 |
Animation |
Use gesture handler |
Native gesture recognition |
react-native-gesture-handler |
JS-based gesture handling |
|
|
Medium |
Gesture Handler Docs |
| 40 |
Async |
Handle loading states |
Show loading indicators |
ActivityIndicator during load |
Empty screen during load |
{isLoading ? : } |
No loading state |
Medium |
- |
| 41 |
Async |
Handle errors gracefully |
Error boundaries and fallbacks |
Error UI for failed requests |
Crash on error |
{error ? : } |
No error handling |
High |
- |
| 42 |
Async |
Cancel async operations |
Cleanup on unmount |
AbortController or cleanup |
Memory leaks from async |
useEffect cleanup |
No cleanup for subscriptions |
High |
- |
| 43 |
Accessibility |
Add accessibility labels |
Describe UI elements |
accessibilityLabel for all interactive |
Missing labels |
"accessibilityLabel=""Submit form""" |
without label |
High |
React Native Docs |
| 44 |
Accessibility |
Use accessibility roles |
Semantic meaning |
accessibilityRole for elements |
Wrong roles |
"accessibilityRole=""button""" |
No role for button |
Medium |
- |
| 45 |
Accessibility |
Support screen readers |
Test with TalkBack/VoiceOver |
Test with screen readers |
Skip accessibility testing |
Regular TalkBack testing |
No screen reader testing |
High |
- |
| 46 |
Testing |
Use React Native Testing Library |
Component testing |
render and fireEvent |
Enzyme or manual testing |
render() |
shallow() |
Medium |
React Native Testing Library |
| 47 |
Testing |
Test on real devices |
Real device behavior |
Test on iOS and Android devices |
Simulator only |
Device testing in CI |
Simulator only testing |
High |
- |
| 48 |
Testing |
Use Detox for E2E |
End-to-end testing |
Detox for critical flows |
Manual E2E testing |
detox test |
Manual testing only |
Medium |
Detox Docs |
| 49 |
Native |
Use native modules carefully |
Bridge has overhead |
Batch native calls |
Frequent bridge crossing |
Batch updates |
Call native on every keystroke |
High |
- |
| 50 |
Native |
Use Expo when possible |
Simplified development |
Expo for standard features |
Bare RN for simple apps |
expo install package |
react-native link package |
Low |
Expo Docs |
| 51 |
Native |
Handle permissions |
Request permissions properly |
Check and request permissions |
Assume permissions granted |
PermissionsAndroid.request() |
Access without permission check |
High |
React Native Docs |