Skip to main content

🔄 What Transfers From React

Good news: most of what you know still applies!

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Identify React concepts that transfer directly to React Native
  • Recognize which areas require new learning or adaptation
  • Apply your existing hooks knowledge in a mobile context
  • Understand how state management patterns carry over
  • Adjust your mental model for touch-based event handling

⏱️ Estimated Time: 30-40 minutes

📑 In This Lesson

The Transfer Overview

Here's the encouraging truth: you already know more React Native than you think. The core of React — the mental model, the patterns, the hooks — all of it applies. You're not starting from scratch; you're adding a new rendering target to skills you already have.

Think of it like a musician who plays piano learning to play keyboards. The music theory, rhythm, hand coordination — all that transfers. You just need to learn where the new buttons are and what sounds they make.

Your React Knowledge Transfer Map ✅ Full Transfer Works exactly the same • Components • Props • State (useState) • Effects (useEffect) • Context API • useRef, useMemo • useCallback • Custom Hooks • Conditional Rendering • List Rendering • TypeScript ⚡ Transfers with Tweaks Same concept, different API • Event Handling onClick → onPress • Forms Same pattern, diff components • State Management Redux/Zustand work the same • Data Fetching fetch() works, React Query too • Testing Jest + React Native Testing Lib 🔄 Needs Relearning New concepts required • Styling StyleSheet, not CSS • Layout Flexbox (column default) • Navigation Expo Router / React Navigation • Core Components View, Text, Image, etc. • Platform APIs Camera, location, storage • Animations

Most of your React knowledge transfers directly or with minor adjustments

📊 The Bottom Line

Roughly 70% of your React knowledge applies directly to React Native. Another 15% needs minor adjustments. Only about 15% is genuinely new territory.

What Transfers Completely

Let's celebrate the good stuff first. These React concepts work exactly the same in React Native:

Components and Props

The fundamental building blocks haven't changed. You still create functional components, pass props, and compose them together:

// This works identically in React and React Native!
function Greeting({ name, isLoggedIn }) {
  return (
    <View>
      <Text>Hello, {name}!</Text>
      {isLoggedIn && <Text>Welcome back!</Text>}
    </View>
  );
}

// Usage
<Greeting name="Sarah" isLoggedIn={true} />

All the Hooks You Love

Every React hook works in React Native. No exceptions:

import { useState, useEffect, useRef, useMemo, useCallback } from 'react';

function Counter() {
  // ✅ useState - exactly the same
  const [count, setCount] = useState(0);
  
  // ✅ useEffect - exactly the same
  useEffect(() => {
    console.log('Count changed:', count);
  }, [count]);
  
  // ✅ useRef - exactly the same
  const renderCount = useRef(0);
  renderCount.current++;
  
  // ✅ useMemo - exactly the same
  const doubleCount = useMemo(() => count * 2, [count]);
  
  // ✅ useCallback - exactly the same
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);
  
  return (
    <View>
      <Text>Count: {count}</Text>
      <Text>Double: {doubleCount}</Text>
      <Pressable onPress={increment}>
        <Text>Increment</Text>
      </Pressable>
    </View>
  );
}

✅ All These Hooks Work

  • useState — local component state
  • useEffect — side effects and lifecycle
  • useContext — consuming context
  • useReducer — complex state logic
  • useCallback — memoized callbacks
  • useMemo — memoized values
  • useRef — mutable refs
  • useLayoutEffect — synchronous effects
  • useImperativeHandle — customizing refs
  • useDebugValue — dev tools labels

Context API

Global state with Context works identically:

// ThemeContext.js - exactly the same pattern!
import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [isDark, setIsDark] = useState(false);
  
  const toggle = () => setIsDark(prev => !prev);
  
  return (
    <ThemeContext.Provider value={{ isDark, toggle }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

// Usage in a component
function SettingsScreen() {
  const { isDark, toggle } = useTheme();
  
  return (
    <View>
      <Text>Dark Mode: {isDark ? 'On' : 'Off'}</Text>
      <Switch value={isDark} onValueChange={toggle} />
    </View>
  );
}

Custom Hooks

Your custom hooks? They'll probably work with zero changes:

// This custom hook works in both React and React Native!
function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  
  const toggle = useCallback(() => {
    setValue(v => !v);
  }, []);
  
  const setTrue = useCallback(() => setValue(true), []);
  const setFalse = useCallback(() => setValue(false), []);
  
  return { value, toggle, setTrue, setFalse };
}

// Works perfectly in React Native
function ExpandableCard() {
  const { value: isExpanded, toggle } = useToggle(false);
  
  return (
    <View>
      <Pressable onPress={toggle}>
        <Text>{isExpanded ? 'Collapse' : 'Expand'}</Text>
      </Pressable>
      {isExpanded && <Text>Hidden content revealed!</Text>}
    </View>
  );
}

Conditional and List Rendering

JSX patterns are unchanged:

function TaskList({ tasks, isLoading, error }) {
  // Conditional rendering - same as web!
  if (isLoading) {
    return <ActivityIndicator />;
  }
  
  if (error) {
    return <Text style={styles.error}>{error.message}</Text>;
  }
  
  if (tasks.length === 0) {
    return <Text>No tasks yet!</Text>;
  }
  
  // List rendering - same pattern, but use FlatList for long lists
  return (
    <View>
      {tasks.map(task => (
        <View key={task.id}>
          <Text>{task.title}</Text>
          {task.completed && <Text>✓</Text>}
        </View>
      ))}
    </View>
  );
}

What Transfers with Tweaks

These concepts carry over, but the syntax or API differs slightly. It's like speaking British English vs American English — same language, slightly different vocabulary.

Event Handling

The concept is identical (functions that respond to user actions), but the event names and properties change:

// 🌐 React (Web)
<button onClick={handleClick}>Click me</button>
<input onChange={handleChange} onFocus={handleFocus} />
<div onMouseEnter={handleHover} />

// 📱 React Native
<Pressable onPress={handlePress}>
  <Text>Press me</Text>
</Pressable>
<TextInput onChangeText={handleChange} onFocus={handleFocus} />
// No mouse events! Touch only.

Event Name Mapping

Web Event React Native Event Notes
onClick onPress Touch equivalent of click
onChange onChangeText Gets text string directly, not event
onSubmit onSubmitEditing When keyboard "done" is pressed
onKeyDown onKeyPress Limited support
onMouseEnter/Leave ❌ Not available No hover on touchscreens
onScroll onScroll Same name, different event shape

Forms and Controlled Inputs

The controlled component pattern works the same; only the component and prop names differ:

// 🌐 React (Web)
function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={e => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={e => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  );
}

// 📱 React Native
function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  
  return (
    <View>
      <TextInput
        keyboardType="email-address"
        value={email}
        onChangeText={setEmail}  // Gets string directly!
        placeholder="Email"
      />
      <TextInput
        secureTextEntry  // Instead of type="password"
        value={password}
        onChangeText={setPassword}
        placeholder="Password"
      />
      <Pressable onPress={handleSubmit}>
        <Text>Login</Text>
      </Pressable>
    </View>
  );
}

💡 Nice Improvement

Notice how onChangeText gives you the string directly instead of e.target.value? React Native often has more convenient APIs for common mobile patterns!

State Management Libraries

Redux, Zustand, MobX, Jotai — they all work with zero changes:

// Zustand store - identical to web usage
import { create } from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

// Use it in React Native - exactly the same!
function Counter() {
  const { count, increment, decrement } = useStore();
  
  return (
    <View>
      <Text>{count}</Text>
      <Pressable onPress={increment}><Text>+</Text></Pressable>
      <Pressable onPress={decrement}><Text>-</Text></Pressable>
    </View>
  );
}

Data Fetching

The fetch API and libraries like React Query work the same:

// React Query - works identically in React Native!
import { useQuery } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  });
  
  if (isLoading) return <ActivityIndicator />;
  if (error) return <Text>Error: {error.message}</Text>;
  
  return (
    <View>
      <Text>{data.name}</Text>
      <Text>{data.email}</Text>
    </View>
  );
}

What You Need to Relearn

Okay, here's the part that actually requires new learning. These areas use different paradigms or entirely new APIs:

🎨 Styling

This is the biggest adjustment. No CSS files, no class names, no cascade:

flowchart LR
    subgraph Web["Web Styling"]
        A["CSS Files"] --> B["Class Names"]
        B --> C["Cascade & Inheritance"]
        C --> D["Media Queries"]
    end
    
    subgraph RN["React Native Styling"]
        E["StyleSheet.create()"] --> F["Style Objects"]
        F --> G["No Cascade"]
        G --> H["Dimensions API"]
    end
    
    style Web fill:#ffebee,stroke:#c62828
    style RN fill:#e8f5e9,stroke:#388e3c
                
// Web CSS
.card {
  background-color: white;
  padding: 16px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.card-title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 8px;
}

// React Native StyleSheet
const styles = StyleSheet.create({
  card: {
    backgroundColor: 'white',      // camelCase
    padding: 16,                   // number, not '16px'
    borderRadius: 8,
    // Shadows are complex in RN
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,  // Android shadow
  },
  cardTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 8,
  },
});

⚠️ Key Differences

  • No units — numbers represent density-independent pixels
  • No shorthand — use marginTop, not margin-top in shorthand
  • Limited properties — not all CSS properties exist
  • Flexbox is default — and flexDirection defaults to column

🧭 Navigation

Web routing (React Router) doesn't apply. Mobile navigation is stack-based and fundamentally different:

flowchart TB
    subgraph Web["Web Navigation"]
        A["URL-based"] --> B["Browser History"]
        B --> C["React Router"]
    end
    
    subgraph Mobile["Mobile Navigation"]
        D["Stack-based"] --> E["Screen Transitions"]
        E --> F["Expo Router or React Navigation"]
        F --> G["Tabs, Stacks, Drawers"]
    end
    
    style Web fill:#e3f2fd,stroke:#1976d2
    style Mobile fill:#e8f5e9,stroke:#388e3c
                
// Web - React Router
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/profile">Profile</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </BrowserRouter>
  );
}

// React Native - Expo Router (file-based)
// app/
//   _layout.tsx      ← Root layout
//   index.tsx        ← Home screen (/)
//   profile.tsx      ← Profile screen (/profile)
//   settings/
//     index.tsx      ← Settings screen (/settings)

// Navigation happens via Link or router
import { Link, router } from 'expo-router';

function HomeScreen() {
  return (
    <View>
      <Link href="/profile">Go to Profile</Link>
      <Pressable onPress={() => router.push('/settings')}>
        <Text>Settings</Text>
      </Pressable>
    </View>
  );
}

📱 Core Components

You need to learn the new component vocabulary (covered in Module 3):

Concept What to Learn
Containers View, ScrollView, SafeAreaView
Text Text (and its nesting rules)
Images Image, ImageBackground
Lists FlatList, SectionList (virtualized)
Buttons Pressable, Button
Inputs TextInput, Switch

📷 Platform APIs

Accessing device features is completely new territory:

  • Cameraexpo-camera
  • Locationexpo-location
  • StorageAsyncStorage or expo-secure-store
  • Notificationsexpo-notifications
  • Hapticsexpo-haptics

These have no web equivalent and will be covered in Module 8.

✨ Animations

CSS animations and transitions don't exist. You'll learn:

  • Animated API (built-in)
  • React Native Reanimated (better performance)
  • LayoutAnimation (simple layout changes)

These are covered in Module 9.

Side-by-Side Examples

Let's look at a complete component to see the differences in context:

A Todo Item Component

// 🌐 React (Web) Version
import { useState } from 'react';
import './TodoItem.css';

function TodoItem({ todo, onToggle, onDelete }) {
  const [isEditing, setIsEditing] = useState(false);
  
  return (
    <div className={`todo-item ${todo.completed ? 'completed' : ''}`}>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span className="todo-text">{todo.text}</span>
      <button onClick={() => onDelete(todo.id)}>
        Delete
      </button>
    </div>
  );
}
// 📱 React Native Version
import { useState } from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
import Checkbox from 'expo-checkbox';

function TodoItem({ todo, onToggle, onDelete }) {
  const [isEditing, setIsEditing] = useState(false);  // Same!
  
  return (
    <View style={[
      styles.todoItem,
      todo.completed && styles.completed  // Conditional styles
    ]}>
      <Checkbox
        value={todo.completed}
        onValueChange={() => onToggle(todo.id)}
      />
      <Text style={styles.todoText}>{todo.text}</Text>
      <Pressable onPress={() => onDelete(todo.id)}>
        <Text style={styles.deleteButton}>Delete</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  todoItem: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    backgroundColor: '#fff',
    borderRadius: 8,
    marginBottom: 8,
  },
  completed: {
    opacity: 0.5,
  },
  todoText: {
    flex: 1,
    marginLeft: 12,
    fontSize: 16,
  },
  deleteButton: {
    color: '#ef4444',
    fontWeight: '600',
  },
});

✅ What Stayed the Same

  • Component structure and props
  • useState hook
  • Conditional rendering logic
  • Event handler patterns
  • Composition approach

⚡ What Changed

  • divView
  • spanText
  • buttonPressable + Text
  • classNamestyle
  • onClickonPress
  • CSS file → StyleSheet.create()

Summary

🎉 Key Takeaways

  • ~70% of React knowledge transfers directly — components, props, state, hooks, context, and patterns
  • Event handling is similar — just different event names (onPress vs onClick)
  • State management libraries work unchanged — Redux, Zustand, MobX all work identically
  • Styling requires the biggest adjustment — StyleSheet objects instead of CSS
  • Navigation is a new paradigm — stack-based, not URL-based
  • Platform APIs are new territory — camera, location, etc. will be learned fresh

🚀 What's Next?

Now that you know what transfers, let's complete your mental map of the React Native world. In the next lesson, we'll survey the React Native ecosystem — the tools, libraries, and resources that you'll be working with throughout this course.

💪 You're Not Starting Over!

Your React foundation is solid and valuable. You're building on top of it, not replacing it. The learning curve is shorter than you might fear!