Last active
July 8, 2025 18:15
-
-
Save wilsolutions/a27e5078e9c0c0cc4e8153ed86ef185f to your computer and use it in GitHub Desktop.
React Native Notes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Optimizations | |
1. FlatList | |
const VehicleItem = React.memo(({ item }) => ( | |
<View style={{ height: ITEM_HEIGHT }}> | |
<Card style={styles.card}> | |
<Text style={styles.plate}>{item.plate}</Text> | |
<Text>Status: {statusMap[item.status]}</Text> | |
<Text style={[styles.battery, { color: getBatteryColor(item.battery) }]}> | |
Battery: {item.battery}% | |
</Text> | |
</Card> | |
</View> | |
)); | |
---- | |
<FlatList data={vehicles} renderItem={({ item }) => <VehicleItem item={item} | |
keyExtractor={item => item.id} | |
getItemLayout={(_, index) => ({ | |
length: ITEM_HEIGHT, | |
offset: ITEM_HEIGHT * index, | |
index | |
})} | |
initialNumToRender={10} | |
maxToRenderPerBatch={5} | |
windowSize={7} | |
removeClippedSubviews={true} | |
/>} /> | |
1.2 Use FlashList | |
1.3 Use recyclerlistview | |
2. Memoize Components & Functions | |
import React, { memo, useCallback } from 'react'; | |
// Memoize component | |
const MyComponent = memo(({ data }) => ( | |
<Text>{data}</Text> | |
)); | |
// Memoize function | |
const Parent = () => { | |
const handlePress = useCallback(() => { | |
console.log("Optimized press!"); | |
}, []); | |
return <MyComponent onPress={handlePress} />; | |
}; | |
3. Optimize FlatList Performance | |
<FlatList | |
data={data} | |
keyExtractor={(item) => item.id} | |
renderItem={({ item }) => <ListItem item={item} />} | |
windowSize={5} // Render 5 items ahead/behind | |
initialNumToRender={10} // First render count | |
maxToRenderPerBatch={10} // Items per batch | |
updateCellsBatchingPeriod={50} // Batch update delay (ms) | |
removeClippedSubviews={true} // Unmount offscreen views (Android) | |
/> | |
4. Avoid Inline Functions & Styles | |
❌ Bad: Recreates on every render | |
<Button onPress={() => doSomething()} /> | |
<View style={{ padding: 10 }} /> | |
✅ Good: Uses useCallback and StyleSheet | |
const handlePress = useCallback(() => doSomething(), []); | |
const styles = StyleSheet.create({ padding: 10 }); | |
5. Use React.memo for Heavy Components | |
const HeavyComponent = React.memo(({ data }) => { | |
return <ExpensiveRenderLogic data={data} />; | |
}); | |
6. Lazy Load Screens & Components | |
// For screens (React Navigation) | |
const HomeScreen = React.lazy(() => import('./HomeScreen')); | |
// For components | |
const ExpensiveComponent = React.lazy(() => import('./ExpensiveComponent')); | |
7. Optimize Re-Renders with useMemo | |
const processedData = useMemo(() => | |
data.filter(item => item.isActive), | |
[data]); // Only recomputes if `data` changes | |
8. Reduce JS ↔ Native Thread Communication | |
Avoid frequent setState in rapid succession (e.g., animations). | |
Use InteractionManager for heavy post-animation work: | |
InteractionManager.runAfterInteractions(() => { | |
// Heavy task after animation | |
}); | |
9. Optimize Images | |
<Image | |
source={{ uri: 'https://example.com/image.jpg' }} | |
resizeMode="contain" | |
fadeDuration={0} // Disable fade (Android) | |
progressiveRenderingEnabled={true} // iOS only | |
/> | |
9.1 Use react-native-fast-image | |
# References | |
- Fetch data | |
const [todos, setTodos] = useState<Todo[]>([]); | |
const [loading, setLoading] = useState(true); | |
const [error, setError] = useState<string | null>(null); | |
useEffect(() => { | |
const fetchTodos = async () => { | |
try { | |
const response = await fetch('https://dummyjson.com/todos?limit=5'); | |
const data = await response.json(); | |
setTodos(data.todos); | |
} catch (err) { | |
setError('Failed to fetch todos'); | |
console.error(err); | |
} finally { | |
setLoading(false); | |
} | |
}; | |
fetchTodos(); | |
}, []); | |
1. Functional Component with Hooks | |
import React, { useState, useEffect } from 'react'; | |
import { View, Text } from 'react-native'; | |
const MyComponent = () => { | |
const [data, setData] = useState(null); | |
useEffect(() => { | |
fetchData(); | |
}, []); | |
const fetchData = async () => { | |
const response = await fetch('https://api.example.com/data'); | |
setData(await response.json()); | |
}; | |
return ( | |
<View> | |
<Text>{data ? data.message : 'Loading...'}</Text> | |
</View> | |
); | |
}; | |
export default MyComponent; | |
2. Navigation (React Navigation v6) | |
import { NavigationContainer } from '@react-navigation/native'; | |
import { createNativeStackNavigator } from '@react-navigation/native-stack'; | |
const Stack = createNativeStackNavigator(); | |
const App = () => ( | |
<NavigationContainer> | |
<Stack.Navigator> | |
<Stack.Screen name="Home" component={HomeScreen} /> | |
<Stack.Screen name="Details" component={DetailsScreen} /> | |
</Stack.Navigator> | |
</NavigationContainer> | |
); | |
3. Custom Hook (e.g., for API Calls) | |
const useFetch = (url) => { | |
const [data, setData] = useState(null); | |
const [loading, setLoading] = useState(true); | |
useEffect(() => { | |
const fetchData = async () => { | |
const response = await fetch(url); | |
setData(await response.json()); | |
setLoading(false); | |
}; | |
fetchData(); | |
}, [url]); | |
return { data, loading }; | |
}; | |
4. Styled with StyleSheet | |
import { StyleSheet, View } from 'react-native'; | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
padding: 16, | |
}, | |
}); | |
const MyComponent = () => <View style={styles.container} />; | |
5. Handling Press Events | |
<TouchableOpacity onPress={() => console.log('Pressed!')}> | |
<Text>Press Me</Text> | |
</TouchableOpacity> | |
6. Platform-Specific Code | |
import { Platform } from 'react-native'; | |
const styles = StyleSheet.create({ | |
text: { | |
fontSize: Platform.OS === 'ios' ? 16 : 14, | |
}, | |
}); | |
7. Context API for State Management | |
import React, { createContext, useContext, useState } from 'react'; | |
const AppContext = createContext(); | |
const AppProvider = ({ children }) => { | |
const [user, setUser] = useState(null); | |
return ( | |
<AppContext.Provider value={{ user, setUser }}> | |
{children} | |
</AppContext.Provider> | |
); | |
}; | |
const useAppContext = () => useContext(AppContext); | |
8. Animations with Reanimated v2 | |
import Animated, { useSharedValue, withSpring } from 'react-native-reanimated'; | |
const MyComponent = () => { | |
const width = useSharedValue(100); | |
const expand = () => { | |
width.value = withSpring(width.value + 50); | |
}; | |
return ( | |
<Animated.View style={{ width }}> | |
<Button title="Expand" onPress={expand} /> | |
</Animated.View> | |
); | |
}; | |
# Issues: | |
- Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication). A frequent cause of the error is that the application entry file path is incorrect. | |
Fix: watchman watch-del-all; react-native start --reset-cache | |
# IPA generation | |
1. Create the bundle | |
execAndLogCommand('Creating bundle...', `(npx react-native bundle \ | |
--entry-file='index.js' \ | |
--bundle-output=${bundleOutput} \ | |
--dev=false \ | |
--platform='${platform}' \ | |
--assets-dest ${platform})` | |
); | |
2. Export the archive | |
execShell(`(export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild clean archive -workspace ${platform}/${appName}.xcworkspace \ | |
-scheme ${appName} \ | |
-sdk iphoneos \ | |
-configuration ${configuration} \ | |
-archivePath ${archivePath})`, | |
{silent: false} | |
); | |
3. Export the .ipa pkg | |
execAndLogCommand('Exporting IPA...', `(xcodebuild -exportArchive \ | |
-archivePath $PWD/build/${appName}.xcarchive \ | |
-exportOptionsPlist ${exportOptionsPlist} \ | |
-exportPath $PWD/build -allowProvisioningUpdates)` | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment