Effects

Back

Loading concept...

🎬 React Native Effects: The Movie Director Inside Your App

Imagine you’re a movie director. You don’t just shoot scenes—you also handle what happens before a scene (setting up cameras), during the scene (action!), and after (cleaning up props). That’s exactly what Effects do in React Native!

Effects are your app’s behind-the-scenes crew. They handle all the work that happens outside of drawing the screen—like fetching data, setting up timers, or listening for events.


🎭 The useEffect Hook: Your Action Crew

What is useEffect?

Think of useEffect as telling your crew: “After you paint the scene on screen, go do this task.”

It runs after the component appears (renders). Perfect for:

  • Fetching data from the internet
  • Setting up timers
  • Subscribing to events

Simple Example

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

function WelcomeScreen() {
  const [message, setMessage] = useState('Loading...');

  useEffect(() => {
    // This runs AFTER the screen appears
    setMessage('Welcome to the app!');
  });

  return (
    <View>
      <Text>{message}</Text>
    </View>
  );
}

What happens:

  1. Screen shows “Loading
”
  2. useEffect runs after screen appears
  3. Message changes to “Welcome to the app!”

Real Life Example: Fetching User Data

function ProfileScreen() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Fetch user after screen loads
    fetch('https://api.example.com/user')
      .then(res => res.json())
      .then(data => setUser(data));
  });

  return (
    <View>
      <Text>{user ? user.name : 'Loading...'}</Text>
    </View>
  );
}

🎯 useEffect Dependencies: The Watch List

The Problem Without Dependencies

Without telling useEffect when to run, it runs every single time your screen updates. That’s like your crew doing the same task over and over—wasteful!

What Are Dependencies?

Dependencies are a watch list. You tell React: “Only run this effect when THESE things change.”

graph TD A["Component Renders"] --> B{Check Dependencies} B -->|Changed| C["Run Effect"] B -->|Same| D["Skip Effect"] C --> E["Continue"] D --> E

The Three Dependency Options

1. Empty Array [] — Run Once

useEffect(() => {
  console.log('I run only ONCE!');
}, []); // Empty = no dependencies

Perfect for: Initial data fetch, one-time setup

2. With Dependencies [value] — Run When Value Changes

useEffect(() => {
  console.log(`User ID changed to: ${userId}`);
}, [userId]); // Runs when userId changes

Perfect for: Reacting to specific state changes

3. No Array — Run Every Render

useEffect(() => {
  console.log('I run EVERY TIME!');
}); // Dangerous! Avoid unless needed

Real Life Example: Search Feature

function SearchScreen() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    // Only search when query changes
    if (query.length > 2) {
      fetch(`/api/search?q=${query}`)
        .then(res => res.json())
        .then(data => setResults(data));
    }
  }, [query]); // Watch the query!

  return (
    <View>
      <TextInput
        value={query}
        onChangeText={setQuery}
      />
      {/* Show results */}
    </View>
  );
}

đŸ§č useEffect Cleanup: The Cleaning Crew

Why Cleanup Matters

Imagine your movie crew sets up lights for a scene. When the scene ends, they need to turn off the lights. Otherwise, power keeps running!

In apps, “leaving lights on” means:

  • Timers still ticking
  • Event listeners still listening
  • Subscriptions still active

This causes memory leaks and bugs! đŸ’„

How Cleanup Works

useEffect(() => {
  // SETUP: Turn on the lights
  const timer = setInterval(() => {
    console.log('Tick!');
  }, 1000);

  // CLEANUP: Turn off the lights
  return () => {
    clearInterval(timer);
  };
}, []);

The function you return from useEffect is your cleanup crew!

graph TD A["Effect Runs"] --> B["Setup Code Executes"] B --> C["Component Unmounts&lt;br&gt;OR Dependencies Change"] C --> D["Cleanup Function Runs"] D --> E["New Effect Runs&lt;br&gt;if still mounted"]

Real Life Example: Live Timer

function TimerScreen() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    // Setup: Start timer
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);

    // Cleanup: Stop timer when leaving
    return () => {
      clearInterval(interval);
    };
  }, []); // Empty = setup once

  return (
    <View>
      <Text>Time: {seconds}s</Text>
    </View>
  );
}

Cleanup with Event Listeners

function OrientationScreen() {
  const [orientation, setOrientation] = useState('portrait');

  useEffect(() => {
    // Setup: Listen for changes
    const handler = (event) => {
      setOrientation(event.orientation);
    };

    Dimensions.addEventListener('change', handler);

    // Cleanup: Stop listening
    return () => {
      Dimensions.removeEventListener('change', handler);
    };
  }, []);

  return <Text>Mode: {orientation}</Text>;
}

⚡ useLayoutEffect: The Lightning-Fast Crew

When useEffect Isn’t Fast Enough

Remember: useEffect runs after the screen is painted. But sometimes you need to measure or change something before the user sees it.

That’s useLayoutEffect!

The Difference

useEffect useLayoutEffect
When After paint Before paint
User sees Old → New (flicker) Just the final result
Use for Data fetching, timers Measuring, DOM changes
graph LR A["Render"] --> B["Paint Screen"] B --> C["useEffect"] D["Render"] --> E["useLayoutEffect"] E --> F["Paint Screen"]

Real Life Example: Measuring Elements

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

function MeasuredBox() {
  const boxRef = useRef(null);
  const [height, setHeight] = useState(0);

  useLayoutEffect(() => {
    // Measure BEFORE user sees
    boxRef.current.measure((x, y, w, h) => {
      setHeight(h);
    });
  }, []);

  return (
    <View>
      <View ref={boxRef}>
        <Text>Content here</Text>
      </View>
      <Text>Box height: {height}px</Text>
    </View>
  );
}

When to Use useLayoutEffect

✅ Measuring element sizes ✅ Scrolling to a position ✅ Animations that need measurements ✅ Preventing visual flicker

❌ Data fetching (use useEffect) ❌ Timers (use useEffect) ❌ Most other side effects


📐 Layout Events: Knowing When Things Change

What Are Layout Events?

When a component’s size or position changes, React Native can tell you! It’s like having a spy that reports: “Hey, this box just got bigger!”

The onLayout Event

Every View can have an onLayout prop:

function ResponsiveBox() {
  const [dimensions, setDimensions] = useState({
    width: 0,
    height: 0
  });

  const handleLayout = (event) => {
    const { width, height } = event.nativeEvent.layout;
    setDimensions({ width, height });
  };

  return (
    <View onLayout={handleLayout} style={{ flex: 1 }}>
      <Text>Width: {dimensions.width}px</Text>
      <Text>Height: {dimensions.height}px</Text>
    </View>
  );
}

What onLayout Gives You

event.nativeEvent.layout = {
  x: 0,      // Position from left
  y: 0,      // Position from top
  width: 350,  // Element width
  height: 200  // Element height
}

Real Life Example: Responsive Image

function ResponsiveImage() {
  const [containerWidth, setContainerWidth] = useState(0);

  return (
    <View
      style={{ flex: 1 }}
      onLayout={(e) => {
        setContainerWidth(e.nativeEvent.layout.width);
      }}
    >
      <Image
        source={{ uri: 'https://...' }}
        style={{
          width: containerWidth,
          height: containerWidth * 0.6 // 60% ratio
        }}
      />
    </View>
  );
}

Combining Layout Events with useLayoutEffect

function SmartComponent() {
  const [size, setSize] = useState({ w: 0, h: 0 });
  const [adjusted, setAdjusted] = useState(false);

  useLayoutEffect(() => {
    // React to size changes BEFORE paint
    if (size.w > 300) {
      setAdjusted(true);
    }
  }, [size.w]);

  return (
    <View
      onLayout={(e) => {
        const { width, height } = e.nativeEvent.layout;
        setSize({ w: width, h: height });
      }}
      style={adjusted ? styles.wide : styles.narrow}
    >
      <Text>Responsive content</Text>
    </View>
  );
}

🎬 Putting It All Together

Here’s our movie analogy in full:

Concept Movie Analogy When to Use
useEffect Crew tasks after scene is shot Data fetching, timers, subscriptions
Dependencies “Only redo if THIS changes” Control when effects run
Cleanup Turning off lights after wrap Prevent memory leaks
useLayoutEffect Set changes before camera rolls Measurements, flicker prevention
Layout Events “The stage just changed size!” Responsive layouts

The Golden Rules

  1. Always add dependencies — Don’t let effects run wild
  2. Always cleanup — Turn off the lights!
  3. Use useLayoutEffect sparingly — Only for visual measurements
  4. Use onLayout for responsiveness — Know your container sizes

🚀 Quick Reference

// Run once on mount
useEffect(() => {
  // setup
  return () => { /* cleanup */ };
}, []);

// Run when value changes
useEffect(() => {
  // react to change
}, [value]);

// Measure before paint
useLayoutEffect(() => {
  // measure/adjust
}, []);

// React to size changes
<View onLayout={(e) => {
  const { width, height } = e.nativeEvent.layout;
}}>

You’re now ready to direct your app’s behind-the-scenes crew like a pro! 🎬

Effects might seem complex at first, but remember: they’re just your helpful crew handling tasks at the right time. Setup when needed, cleanup when done, and always tell them what to watch!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.