React Native that feels native

Surendra Tamang

Surendra Tamang

24 min read
React Native Development

I’ve built enough React Native apps to know where they usually fall apart: startup time, list scrolling, and animations. These are the settings and patterns I now apply by default.

Performance Optimization

1. Use Hermes Engine

Hermes significantly improves startup time and memory usage:

android/app/build.gradle
project.ext.react = [
enableHermes: true
]

2. Implement Lazy Loading

const HomeScreen = lazy(() => import('./screens/HomeScreen'));
function App() {
return (
<Suspense fallback={<LoadingScreen />}>
<HomeScreen />
</Suspense>
);
}

3. Optimize Images

Use proper image formats and implement caching:

import FastImage from 'react-native-fast-image';
<FastImage
style={styles.image}
source={{
uri: imageUrl,
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.cover}
/>

State Management

Redux Toolkit

import { configureStore, createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: { profile: null },
reducers: {
setProfile: (state, action) => {
state.profile = action.payload;
}
}
});
export const store = configureStore({
reducer: {
user: userSlice.reducer
}
});

React Navigation 6

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerLargeTitle: true,
headerTransparent: true
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

Animations

Reanimated 3

import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring
} from 'react-native-reanimated';
function AnimatedCard() {
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }]
}));
const handlePress = () => {
scale.value = withSpring(0.9, {}, () => {
scale.value = withSpring(1);
});
};
return (
<Animated.View style={[styles.card, animatedStyle]}>
<TouchableOpacity onPress={handlePress}>
<Text>Press me!</Text>
</TouchableOpacity>
</Animated.View>
);
}

General rules

  1. Use TypeScript: Catch errors early and improve maintainability
  2. Implement Error Boundaries: Gracefully handle crashes
  3. Optimize Bundle Size: Use dynamic imports and tree shaking
  4. Test on Real Devices: Simulators don’t catch all issues
  5. Monitor Performance: Use Flipper and React DevTools

Conclusion

Most React Native jank traces back to skipping one of the items above. Profile on a real low-end device before deciding the app is fast.

Surendra Tamang

About Surendra Tamang

Software Engineer specializing in web scraping, data engineering, and full-stack development. Passionate about transforming complex data challenges into elegant solutions.

Continue reading