Skip to main content
React Native is built on top of React, so understanding React fundamentals is essential. This guide covers the core React concepts you’ll use every day in React Native development.

Components

Components are the building blocks of React Native apps. A component is a JavaScript function that returns JSX describing what should appear on screen.

Function Components

import {View, Text} from 'react-native';

function Welcome() {
  return (
    <View>
      <Text>Hello, World!</Text>
    </View>
  );
}

export default Welcome;

JSX Syntax

JSX lets you write markup inside JavaScript. In React Native, you use components like <View> and <Text> instead of HTML elements:
// This JSX:
<View style={{padding: 16}}>
  <Text>Hello</Text>
</View>

// Is transformed to:
React.createElement(
  View,
  {style: {padding: 16}},
  React.createElement(Text, null, 'Hello')
);

Props

Props (properties) let you pass data from parent to child components. Props are read-only and cannot be modified by the child.
import {View, Text, StyleSheet} from 'react-native';

function Greeting(props) {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Hello, {props.name}!</Text>
      <Text>You are {props.age} years old.</Text>
    </View>
  );
}

// Using the component
function App() {
  return (
    <View>
      <Greeting name="Alice" age={25} />
      <Greeting name="Bob" age={30} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#f0f0f0',
    marginBottom: 8,
  },
  text: {
    fontSize: 18,
    fontWeight: 'bold',
  },
});

Destructuring Props

Common pattern for cleaner code:
// Instead of props.name, props.age
function Greeting({name, age}) {
  return (
    <View>
      <Text>Hello, {name}!</Text>
      <Text>Age: {age}</Text>
    </View>
  );
}

State

State is data that changes over time. When state changes, React re-renders the component.

useState Hook

import {View, Text, Button} from 'react-native';
import {useState} from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <View>
      <Text>Count: {count}</Text>
      <Button
        title="Increment"
        onPress={() => setCount(count + 1)}
      />
      <Button
        title="Decrement"
        onPress={() => setCount(count - 1)}
      />
      <Button
        title="Reset"
        onPress={() => setCount(0)}
      />
    </View>
  );
}

Multiple State Variables

import {View, TextInput, Text, Button} from 'react-native';
import {useState} from 'react';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [isLoading, setIsLoading] = useState(false);

  const handleLogin = () => {
    setIsLoading(true);
    // Perform login...
  };

  return (
    <View>
      <TextInput
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
      />
      <TextInput
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
      />
      <Button
        title="Login"
        onPress={handleLogin}
        disabled={isLoading}
      />
    </View>
  );
}
State updates are asynchronous. Don’t rely on the previous state value immediately after calling the setter.

Hooks

Hooks let you use state and other React features in function components.

useEffect Hook

Run side effects after rendering:
import {View, Text} from 'react-native';
import {useState, useEffect} from 'react';

function UserProfile({userId}) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // This runs after component mounts and when userId changes
    setLoading(true);
    fetch(`https://api.example.com/users/${userId}`)
      .then(response => response.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });
  }, [userId]); // Dependency array

  if (loading) {
    return <Text>Loading...</Text>;
  }

  return (
    <View>
      <Text>Name: {user.name}</Text>
      <Text>Email: {user.email}</Text>
    </View>
  );
}

useEffect Cleanup

import {useEffect} from 'react';
import {AppState} from 'react-native';

function MyComponent() {
  useEffect(() => {
    const subscription = AppState.addEventListener('change', (state) => {
      console.log('App state changed to:', state);
    });

    // Cleanup function
    return () => {
      subscription.remove();
    };
  }, []); // Empty array = run once on mount
}

Common Hooks

const [value, setValue] = useState(initialValue);
Manage component state

Conditional Rendering

Render different content based on conditions:
import {View, Text, Button} from 'react-native';
import {useState} from 'react';

function LoginScreen() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <View>
      {isLoggedIn ? (
        <View>
          <Text>Welcome back!</Text>
          <Button title="Logout" onPress={() => setIsLoggedIn(false)} />
        </View>
      ) : (
        <View>
          <Text>Please log in</Text>
          <Button title="Login" onPress={() => setIsLoggedIn(true)} />
        </View>
      )}
    </View>
  );
}

Logical && Operator

function Notification({message, show}) {
  return (
    <View>
      {show && (
        <View style={{backgroundColor: 'yellow', padding: 10}}>
          <Text>{message}</Text>
        </View>
      )}
    </View>
  );
}

Rendering Lists

Use map() to render arrays of data:
import {View, Text} from 'react-native';

function TodoList() {
  const todos = [
    {id: 1, text: 'Learn React Native'},
    {id: 2, text: 'Build an app'},
    {id: 3, text: 'Deploy to stores'},
  ];

  return (
    <View>
      {todos.map(todo => (
        <View key={todo.id}>
          <Text>{todo.text}</Text>
        </View>
      ))}
    </View>
  );
}
Always include a unique key prop when rendering lists. Keys help React identify which items have changed.

Component Composition

Build complex UIs by combining smaller components:
import {View, Text, Image, StyleSheet} from 'react-native';

function Avatar({url, size = 50}) {
  return (
    <Image
      source={{uri: url}}
      style={{width: size, height: size, borderRadius: size / 2}}
    />
  );
}

function UserCard({name, role, avatarUrl}) {
  return (
    <View style={styles.card}>
      <Avatar url={avatarUrl} size={60} />
      <View style={styles.info}>
        <Text style={styles.name}>{name}</Text>
        <Text style={styles.role}>{role}</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    flexDirection: 'row',
    padding: 16,
    backgroundColor: 'white',
    borderRadius: 8,
    marginBottom: 8,
  },
  info: {
    marginLeft: 12,
    justifyContent: 'center',
  },
  name: {
    fontSize: 16,
    fontWeight: 'bold',
  },
  role: {
    fontSize: 14,
    color: '#666',
  },
});

React Native-Specific Considerations

No HTML Elements

// ❌ Wrong - HTML doesn't work in React Native
<div>
  <p>Hello</p>
</div>

// ✅ Correct - Use React Native components
<View>
  <Text>Hello</Text>
</View>

StyleSheet API

import {StyleSheet} from 'react-native';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

Event Handlers

// Web: onClick
<button onClick={() => console.log('clicked')}>Click</button>

// React Native: onPress
<Button onPress={() => console.log('pressed')} title="Press" />

Next Steps

Handling Text Input

Learn to work with forms and user input

Using Lists

Render large lists efficiently with FlatList

Build docs developers (and LLMs) love