Context and Refs

Back

Loading concept...

State Management: Context and Refs in React Native

The Story of the Magic Messenger and the Secret Notebook ๐Ÿ“ฌ๐Ÿ““

Imagine you live in a big castle with many rooms. Every room has family members doing different things. Now, what if everyone needed to know when dinner is ready?

You have two magic tools:

  1. A Magic Messenger (Context) - Shouts announcements to everyone in the castle at once!
  2. A Secret Notebook (Refs) - A private note only YOU can write in and peek at, without disturbing anyone.

Letโ€™s explore both!


Part 1: The Magic Messenger (Context) ๐Ÿฐ๐Ÿ“ข

What is useContext Hook?

Think of useContext as a walkie-talkie that lets any room in your castle hear important messagesโ€”without passing notes through every single door!

The Problem Without Context:

// Without Context - passing props through
// every component (prop drilling!)
<App>
  <Header user={user} />
    <Navigation user={user} />
      <Avatar user={user} /> // Finally used!

Thatโ€™s like passing a note through 10 people just to reach your friend!

The Solution With Context:

// With Context - direct access!
<UserContext.Provider value={user}>
  <App>
    <Header />
      <Navigation />
        <Avatar /> // Gets user directly!

Now Avatar can grab the message straight from the air! โœจ


Creating Context

Creating Context is like setting up a radio station. First, you decide what channel youโ€™ll broadcast on.

import { createContext } from 'react';

// Create your radio station
const ThemeContext = createContext('light');

// 'light' is the default value
// (what plays if no one is broadcasting)

Simple Analogy:

  • createContext() = Building the radio tower
  • Default value = What plays when tower is silent
  • Context object = The radio station itself

Context Provider

The Provider is the radio DJ who actually broadcasts messages. Without a DJ, the station plays default music.

import { ThemeContext } from './ThemeContext';

function App() {
  const [theme, setTheme] = useState('dark');

  return (
    // The DJ booth - broadcasting 'dark'
    <ThemeContext.Provider value={theme}>
      <MainScreen />
      <Settings />
    </ThemeContext.Provider>
  );
}

Everything inside <Provider> can tune in!

graph TD A["๐ŸŽ™๏ธ Provider - DJ Booth"] --> B["๐Ÿ“ป MainScreen"] A --> C["๐Ÿ“ป Settings"] B --> D["๐Ÿ“ป Button"] C --> E["๐Ÿ“ป Toggle"] style A fill:#667eea,color:#fff

Using Context in Components

Any component can tune in using useContext:

import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function Button() {
  // Tune into the theme station
  const theme = useContext(ThemeContext);

  return (
    <TouchableOpacity
      style={{
        backgroundColor: theme === 'dark'
          ? '#333'
          : '#fff'
      }}
    >
      <Text>Press Me!</Text>
    </TouchableOpacity>
  );
}

Context Performance โšก

The Gotcha: When the DJ changes the song, EVERYONE listening re-renders!

// โš ๏ธ Problem: Everything re-renders!
<ThemeContext.Provider value={{ theme, user }}>

Solutions:

1. Split Your Contexts:

// Good! Separate stations
<ThemeContext.Provider value={theme}>
  <UserContext.Provider value={user}>
    <App />
  </UserContext.Provider>
</ThemeContext.Provider>

2. Memoize Values:

function App() {
  const [theme, setTheme] = useState('dark');

  // Only creates new object when theme changes
  const value = useMemo(
    () => ({ theme, setTheme }),
    [theme]
  );

  return (
    <ThemeContext.Provider value={value}>
      <Content />
    </ThemeContext.Provider>
  );
}

Context for Global State

Context shines for app-wide shared data:

// AuthContext.js - Global auth state
const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  const login = async (email, password) => {
    // ... login logic
    setUser(userData);
  };

  const logout = () => setUser(null);

  return (
    <AuthContext.Provider
      value={{ user, loading, login, logout }}
    >
      {children}
    </AuthContext.Provider>
  );
}

// Custom hook for easy access
export const useAuth = () => useContext(AuthContext);

Using it anywhere:

function ProfileScreen() {
  const { user, logout } = useAuth();

  return (
    <View>
      <Text>Hello, {user.name}!</Text>
      <Button title="Logout" onPress={logout} />
    </View>
  );
}

Common Global State Uses:

  • ๐ŸŽจ Theme (dark/light mode)
  • ๐Ÿ” Authentication (user login state)
  • ๐ŸŒ Language/Localization
  • ๐Ÿ›’ Shopping cart

Part 2: The Secret Notebook (Refs) ๐Ÿ““๐Ÿ”’

What is useRef Hook?

useRef is like a secret notebook that:

  • Only YOU can read and write
  • Doesnโ€™t tell anyone when you change it
  • Remembers everything between renders
import { useRef } from 'react';

function StopwatchScreen() {
  // Create a secret notebook
  const timerRef = useRef(null);

  const startTimer = () => {
    // Write in the notebook
    timerRef.current = setInterval(() => {
      console.log('tick');
    }, 1000);
  };

  const stopTimer = () => {
    // Read from the notebook
    clearInterval(timerRef.current);
  };

  return (
    <View>
      <Button title="Start" onPress={startTimer} />
      <Button title="Stop" onPress={stopTimer} />
    </View>
  );
}

Key Difference from State:

Feature useState useRef
Changes cause re-render? โœ… Yes โŒ No
Preserved between renders? โœ… Yes โœ… Yes
When to use? UI data Silent data

Accessing DOM/Native Elements

Refs can grab a direct handle to components:

function AutoFocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // Focus the input when screen loads
    inputRef.current.focus();
  }, []);

  return (
    <TextInput
      ref={inputRef}
      placeholder="I auto-focus!"
    />
  );
}

Common Uses:

  • ๐Ÿ“ Focus an input
  • ๐Ÿ“œ Scroll to a position
  • ๐Ÿ“ Measure element size
  • ๐ŸŽฌ Play/pause video

Ref Forwarding

The Problem: What if you wrap a component and still need to access its ref?

// This won't work!
function FancyInput(props) {
  return <TextInput {...props} />;
}

// Parent can't get the ref!
<FancyInput ref={myRef} />

The Solution - forwardRef:

import { forwardRef } from 'react';

const FancyInput = forwardRef((props, ref) => {
  return (
    <TextInput
      ref={ref}  // Pass it through!
      style={styles.fancy}
      {...props}
    />
  );
});

// Now it works!
function Form() {
  const inputRef = useRef(null);

  return (
    <FancyInput
      ref={inputRef}
      placeholder="Fancy!"
    />
  );
}
graph TD A["๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง Parent Component"] -->|ref| B["๐Ÿ“ฆ FancyInput"] B -->|forwardRef| C["๐Ÿ“ TextInput"] style B fill:#4ECDC4,color:#fff

Think of it like:

  • Normal component = Package with no forwarding address
  • forwardRef = Package with โ€œplease forward toโ€ sticker

Imperative Handle

Sometimes you want to control what the parent can do with the ref. Itโ€™s like giving someone a remote control with only specific buttons.

import {
  forwardRef,
  useRef,
  useImperativeHandle
} from 'react';

const VideoPlayer = forwardRef((props, ref) => {
  const videoRef = useRef(null);

  // Create a custom remote control
  useImperativeHandle(ref, () => ({
    // Only expose these buttons!
    play: () => videoRef.current.play(),
    pause: () => videoRef.current.pause(),
    seek: (time) => {
      videoRef.current.currentTime = time;
    }
  }));

  return <Video ref={videoRef} source={props.src} />;
});

// Parent usage
function Screen() {
  const playerRef = useRef(null);

  return (
    <View>
      <VideoPlayer ref={playerRef} src="movie.mp4" />

      <Button
        title="Play"
        onPress={() => playerRef.current.play()}
      />
      <Button
        title="Skip to 30s"
        onPress={() => playerRef.current.seek(30)}
      />
    </View>
  );
}

Why use Imperative Handle?

  • ๐Ÿ”’ Hide internal implementation
  • ๐ŸŽฎ Expose only whatโ€™s needed
  • ๐Ÿ“– Create clean, documented APIs

Quick Summary: When to Use What? ๐ŸŽฏ

graph TD A{What do you need?} --> B{Share data across<br/>many components?} A --> C{Store value without<br/>re-rendering?} A --> D{Access component<br/>methods/elements?} B -->|Yes| E["โœ… useContext"] C -->|Yes| F["โœ… useRef"] D -->|Yes| G["โœ… useRef + forwardRef"] style E fill:#667eea,color:#fff style F fill:#4ECDC4,color:#fff style G fill:#FF6B6B,color:#fff
Tool Use Whenโ€ฆ
Context Many components need same data
useRef Store values silently
forwardRef Pass refs through wrappers
useImperativeHandle Create custom ref APIs

The Castle Recap ๐Ÿฐ

Remember our castle?

  • Context = The castleโ€™s intercom system. Announce once, everyone hears!
  • Refs = Your private diary. Write notes, no one gets notified!
  • forwardRef = A mail forwarding service for refs
  • useImperativeHandle = A custom remote control with only the buttons you choose

Now youโ€™re ready to manage state like a true React Native wizard! ๐Ÿง™โ€โ™‚๏ธโœจ

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.