React Native With TypeScript
This documentation is a complete learning path for developers who want to master React Native CLI with TypeScript. Each topic includes explanations, code examples, and best practices.
Hello World App
Your first React Native CLI app.
Example:
import React from "react";
import { Text, View } from "react-native";
const App = () => {
return (
<View>
<Text>Hello World!</Text>
</View>
);
};
export default App;
Using Text
The Text component is used to display strings.
Example with styling:
<Text style={{fontSize: 20, fontWeight: "bold", color: "blue"}}>
Welcome to React Native with TypeScript!
</Text>
View Component
View is the container for layout and styling.
Example:
<View style={{backgroundColor: "#eee", padding: 20}}>
<Text>Inside a View</Text>
</View>
Button Usage
Button is used for simple press actions.
Example:
<Button title="Click Me" onPress={() => alert("Button pressed!")}/>
Components
A component is a reusable piece of UI.
Functional Component Example:
type Props = { name: string };
const User: React.FC<Props> = ({name}) => <Text>Hello {name}</Text>;
const LongUser: React.FunctionComponent<Props> = ({name}) => <Text>Hello {name}</Text>;
Props
Props are inputs to components.
Defining and using props in a component:
type GreetingProps = {
name: string;
age: number
};
const Greeting: React.FC<GreetingProps> = ({name, age}) => {
return <Text>Hello {name}, you are {age} years old.</Text>;
};
Passing props from a parent:
const App = () => {
return <Greeting name="John" age={25}/>;
};
State with useState
useState manages component state.
const [count, setCount] = useState<number>(0);
<Button title="Increase" onPress={() => setCount(count + 1)}/>
<Text>{count}</Text>
Children (with PropsWithChildren)
Components can accept child elements.
import React, { PropsWithChildren } from "react";
import { View } from "react-native";
const Card: React.FC<PropsWithChildren> = ({children}) => (
<View style={{padding: 10, borderWidth: 1}}>{children}</View>
);
<Card>
<Text>Hello inside a Card!</Text>
</Card>
Components can accept child elements using PropsWithChildren.
You can also extend your own props interface so that both children and custom props are supported.
Example with extended Props:
import React, { PropsWithChildren } from "react";
import { View, Text } from "react-native";
type CardProps = PropsWithChildren<{
title: string;
}>;
const Card: React.FC<CardProps> = ({title, children}) => (
<View style={{padding: 10, borderWidth: 1}}>
<Text style={{fontWeight: "bold"}}>{title}</Text>
{children}
</View>
);
const App = () => (
<Card title="User Info">
<Text>Name: John</Text>
<Text>Age: 25</Text>
</Card>
);
Alert
Alerts interact with users.
<Button
title="Show Alert"
onPress={() => Alert.alert("Warning", "This is an alert!")}
/>
Flexbox
Key points:
- Default
flexDirection= column justifyContent= vertical alignmentalignItems= horizontal alignment
<View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
<Text>Centered Content</Text>
</View>
flexDirectionoptions:column,column-reverse,row,row-reverse.
<View style={{flexDirection: 'row'}}>
<Text>A</Text>
<Text>B</Text>
</View>
<View style={{flexDirection: 'row-reverse'}}>
<Text>A</Text>
<Text>B</Text>
</View>
Image
<Image
style={{width: 100, height: 100, borderRadius: 50}}
source={{uri: "https://placekitten.com/200/200"}}
/>
ImageBackground
<ImageBackground
source={require("./bg.png")}
style={{width: "100%", height: 200}}
imageStyle={{borderRadius: 20}}
>
<Text>Overlay text</Text>
</ImageBackground>
ScrollView
<ScrollView contentContainerStyle={{padding: 20}}>
<Text>Item 1</Text>
<Text>Item 2</Text>
<Text>Item 3</Text>
</ScrollView>
ScrollView with Object Mapping:
<ScrollView>
{users.map(u => (
<Text key={u.id}>{u.name}</Text>
))}
</ScrollView>
TouchableOpacity
<TouchableOpacity onPress={() => alert("Pressed!")}>
<Text>Press Me</Text>
</TouchableOpacity>
Custom Hook
function useCounter(initial: number) {
const [count, setCount] = useState<number>(initial);
const increment = () => setCount(prev => prev + 1);
return {count, increment};
}
Switch
const [enabled, setEnabled] = useState(false);
<Switch
value={enabled}
onValueChange={() => setEnabled(prev => !prev)}
/>
TextInput
<TextInput
placeholder="Enter your name"
value={name}
onChangeText={setName}
style={{borderWidth: 1, borderRadius: 5, padding: 10}}
/>
Modal
<Modal visible={true} transparent animationType="slide">
<View style={{flex: 1, justifyContent: "flex-end"}}>
<View style={{height: 200, backgroundColor: "white"}}>
<Text>Modal Content</Text>
</View>
</View>
</Modal>
Class Component
class Counter extends React.Component<{}, { count: number }> {
state = {count: 0};
render() {
return (
<View>
<Text>{this.state.count}</Text>
<Button
title="Add"
onPress={() => this.setState({count: this.state.count + 1})}
/>
</View>
);
}
}
Lifecycle:
componentDidMount→ after first rendercomponentDidUpdate→ after state/prop changecomponentWillUnmount→ cleanup
Stack Navigation
To use stack navigation, first install the required packages:
npm install @react-navigation/native @react-navigation/native-stack
Then configure your stack:
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
// 1. Create the stack
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
// 2. Define screens
const HomeScreen = ({navigation}) => (
<View>
<Text>Home Screen</Text>
<Button
title="Go to Profile"
onPress={() => navigation.navigate('Profile', {userId: '123'})}
/>
</View>
);
const ProfileScreen = ({route}) => (
<View>
<Text>Profile Screen</Text>
<Text>User ID: {route.params.userId}</Text>
</View>
);
// 3. Use the stack in NavigationContainer
const App = () => (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="Profile" component={ProfileScreen}/>
</Stack.Navigator>
</NavigationContainer>
);
export default App;
FlatList
<FlatList
data={users}
renderItem={({item}) => <Text>{item.name}</Text>}
keyExtractor={item => item.id.toString()}
/>
Activity Indicator
<ActivityIndicator size="large" color="blue"/>
Fetch API
useEffect(() => {
fetch("https://dummyjson.com/users")
.then(res => res.json())
.then(data => setUsers(data.users));
}, []);
Context API with useContext
const ThemeContext = React.createContext("light");
const Child = () => {
const theme = React.useContext(ThemeContext);
return <Text>Theme: {theme}</Text>;
};
const App = () => (
<ThemeContext.Provider value="dark">
<Child/>
</ThemeContext.Provider>
);
Ref & memo
const inputRef = useRef<TextInput>(null);
<TextInput ref={inputRef}/>
const Memoized = React.memo(MyComponent);
Styling & Tools
StyleSheet
const styles = StyleSheet.create({
text: {fontSize: 20, color: "red"},
});
Redux Toolkit Example
Slice (counterSlice.ts)
import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
initialState: {
count: 0,
author: {
name: 'John',
surname: 'Doe'
}
},
reducers: {
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
},
refresh(state) {
state.count = 0;
},
setAuthor(state, action) {
const name = action.payload.name;
const surname = action.payload.surname;
state.author.name = name;
state.author.surname = surname;
}
},
});
export const {increment, decrement, setAuthor} = counterSlice.actions;
export default counterSlice.reducer;
Store (store.ts)
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: {counter: counterReducer},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
App with Provider (App.tsx)
import React from 'react';
import { Provider } from 'react-redux';
import { store } from './store';
import Main from './Main';
const App = () => (
<Provider store={store}>
<Main/>
</Provider>
);
export default App;
Using useSelector (Main.tsx)
import React from 'react';
import { Text, View } from 'react-native';
import { useSelector } from 'react-redux';
import { RootState } from './store';
const Main = () => {
const count = useSelector((state: RootState) => state.counter.count);
const author = useSelector((state: RootState) => state.counter.author);
return (
<View>
<Text>Count: {count}</Text>
<Text>Author: {author.name} {author.surname}</Text>
</View>
);
};
export default Main;
Using useDispatch (CounterButtons.tsx)
import React from 'react';
import { Button, View } from 'react-native';
import { useDispatch } from 'react-redux';
import { decrement, increment, refresh, setAuthor } from './counterSlice';
const CounterButtons = () => {
const dispatch = useDispatch();
return (
<View>
<Button title="Increment" onPress={() => dispatch(increment())}/>
<Button title="Decrement" onPress={() => dispatch(decrement())}/>
<Button title="Reset" onPress={() => dispatch(refresh())}/>
<Button
title="Set Author"
onPress={() => dispatch(setAuthor({name: 'Alex', surname: 'Smith'}))}
/>
</View>
);
};
export default CounterButtons;
AsyncStorage
await AsyncStorage.setItem("token", "123");
const token = await AsyncStorage.getItem("token");
await AsyncStorage.removeItem("token");