Skip to main content
React Native Introduction
CHAPTER 08 Beginner

State and useState Hook

Updated: May 16, 2026
6 min read

# CHAPTER 8

State and useState Hook

1. Introduction

A UI built exclusively with Props is beautiful, but it is dead. It cannot react to user clicks, it cannot update form text, and it cannot track a shopping cart total. To make an app interactive, it needs memory. In React Native, this memory is called State. In this chapter, we will master State and the useState Hook. We will learn how to declare dynamic variables, modify them safely, and utilize the golden rule of React: *Whenever state changes, the UI automatically redraws.*

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Explain the critical difference between Props and State.
  • Import and initialize the useState Hook.
  • Destructure the getter variable and setter function.
  • Update state safely using the setter function.
  • Build dynamic, interactive components (Counters, Toggles).

3. The Problem with Standard Variables

Why can't we just use standard JavaScript variables like let score = 0; and increment them when a button is clicked?
javascript
123456789101112
// THIS WILL NOT WORK!
export default function App() {
  let score = 0;

  const handlePress = () => {
    score = score + 1;
    console.log(score); // Terminal will show 1, 2, 3...
  };

  // But the screen will ALWAYS say 0!
  return <Text onPress={handlePress}>Score: {score}</Text>;
}

*Why?* Because React does not constantly scan your files looking for changes. React only redraws the UI when you explicitly tell it to. Standard variables do not trigger UI re-renders.

4. Introducing useState

To tell React a value has changed and the screen must redraw, we use a "Hook" called useState. First, you must import it from the core react library.
javascript
1
import React, { useState } from &#039;react&#039;;

5. Syntax of useState

useState is a function that takes the *initial value* of your variable and returns an array with exactly two things:
  1. 1. The current value (The Getter)
  1. 2. A special function to change that value (The Setter)

We use Array Destructuring to grab them instantly!

javascript
12345
// Syntax: const [getter, setter] = useState(initialValue);

const [score, setScore] = useState(0); 
const [username, setUsername] = useState("Guest");
const [isDarkMode, setIsDarkMode] = useState(false);

6. Updating State (The Setter Function)

You MUST NEVER change the state variable directly (e.g., score = score + 1;). You must ALWAYS use the special Setter function provided by the hook: setScore(score + 1);.

When you call the Setter function, two magical things happen:

  1. 1. The value of the state is updated in memory.
  1. 2. React instantly triggers a UI Re-Render, drawing the exact screen again with the new data!

7. Mini Project: The Counter App

Let's build a fully interactive Counter app with an Increment and Reset button.
javascript
1234567891011121314151617181920212223242526272829303132
import React, { useState } from &#039;react&#039;;
import { View, Text, Button, StyleSheet } from &#039;react-native&#039;;

export default function CounterApp() {
  // 1. Initialize State to 0
  const [count, setCount] = useState(0);

  // 2. The Logic Functions
  const handleIncrement = () => {
    setCount(count + 1); // Triggers a redraw!
  };

  const handleReset = () => {
    setCount(0); // Triggers a redraw!
  };

  return (
    <View style={styles.container}>
      {/* 3. The UI automatically reflects the current state */}
      <Text style={styles.text}>Current Count: {count}</Text>
      
      {/* 4. Buttons trigger the logic */}
      <Button title="Increase" onPress={handleIncrement} />
      <Button title="Reset" onPress={handleReset} color="red" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: &#039;center&#039;, alignItems: &#039;center&#039; },
  text: { fontSize: 24, marginBottom: 20 }
});

8. Toggling State (Booleans)

State is incredibly useful for hiding or showing UI elements.
javascript
12345678910111213141516
export default function LightSwitch() {
  const [isOn, setIsOn] = useState(false);

  return (
    <View>
      {/* Use a Ternary Operator to conditionally render text! */}
      <Text>{isOn ? "The light is ON" : "The light is OFF"}</Text>
      
      <Button 
        title="Toggle Light" 
        // When clicked, set isOn to the opposite of whatever it currently is!
        onPress={() => setIsOn(!isOn)} 
      />
    </View>
  );
}

9. Common Mistakes

  • Infinite Render Loops: If you call the setter function immediately during rendering instead of passing it to a button, your app will crash.
BAD: <Button onPress={setCount(count + 1)} /> (This calls the function instantly, triggering a redraw, which draws the button, which calls the function instantly...) GOOD: <Button onPress={() => setCount(count + 1)} /> (This wraps it in an arrow function, meaning it will ONLY execute when physically clicked by the user).

10. Best Practices

  • Naming Conventions: The setter function should always be named starting with set. If your variable is isLoading, the setter MUST be named setIsLoading. This is a universal React standard.

11. Practice Exercises

  1. 1. Write the exact line of code to initialize a state variable named isMenuOpen with a default value of false.
  1. 2. Write the button onPress logic required to change isMenuOpen from false to true.

12. MCQs with Answers

Question 1

Why is it strictly forbidden to mutate a state variable directly (e.g., count = count + 1) in React?

Question 2

When utilizing the useState hook, what two distinct items are returned within the array?

13. Interview Questions

  • Q: Explain the mechanical difference between Props and State regarding mutability and data flow.
  • Q: Describe the React rendering lifecycle regarding state changes. What exactly happens behind the scenes from the millisecond a user clicks a button that triggers a setState function?
  • Q: A junior developer writes <Button onPress={setScore(10)} title="Click" /> and their app immediately crashes with a "Maximum update depth exceeded" error. Explain why this happened and how to fix it.

14. FAQs

Q: What if I have complex state, like an Array of Shopping Cart items? A: useState handles arrays perfectly! However, you must remember the golden rule: you cannot mutate arrays directly with .push(). You must use the Spread Operator to create a new array: setCart([...cart, newItem]). We will practice this deeply later!

15. Summary

In Chapter 8, we brought our applications to life. We learned that standard JavaScript variables cannot trigger visual UI updates. Instead, we adopted the useState Hook, declaring our dynamic data alongside its dedicated Setter Function. We built interactive components, utilizing setCount and setIsOn to safely modify memory. Most importantly, we witnessed the heartbeat of React Native: the automated, instantaneous UI Re-Render that occurs every time a state setter is invoked.

16. Next Chapter Recommendation

Our logic and data flow are perfect, but our apps currently look like simple white screens with plain text. We need to become designers. Proceed to Chapter 9: Styling in React Native.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·