DEV Community

Odipo Otieno (KwargDevs)
Odipo Otieno (KwargDevs)

Posted on

React Props and Hooks

Imagine you are building something with LEGOs.

  • Components are your individual LEGO bricks (<Button />, <Profile />, <Header />).
  • Props are the instructions you give to a brick.
  • Hooks are special abilities you can give to a brick.

Part 1: Props (How Components Talk to Each Other)

The Core Idea: Props (short for "properties") are used to pass data from a parent component down to a child component. It's a one-way street: data only flows downwards.

The Analogy: Ordering at a Restaurant

  • You (the Parent Component): You are the customer ordering a pizza.
  • The Chef (the Child Component): The chef is the <Pizza /> component.
  • Your Order (the Props): You tell the chef, "I want a large pizza with pepperoni and extra cheese." These specific instructions—size: 'large', topping: 'pepperoni', extraCheese: true—are the props.

The chef (<Pizza />) receives these instructions and makes the pizza exactly as you ordered. The chef cannot change your order; they can only read it and act on it. This is the most important rule of props.

Key Characteristics of Props

  1. Read-Only: A child component can never change the props it receives. It can only use them.
  2. Data Flows Down: Data is passed from parent to child, to grandchild, and so on. A child cannot pass props "up" to its parent.
  3. They are Configuration: Props are how you configure and customize a reusable component.

Simple Code Example

Let's create a reusable WelcomeMessage component.

// This is our "Chef" component. It's reusable.
// It expects to receive a `name` prop.
function WelcomeMessage({ name }) { // We "destructure" props to get the name directly
  return (
    <h1>Hello, {name}! Welcome to our app.</h1>
  );
}

// This is our "Customer" or Parent component.
function App() {
  return (
    <div>
      {/* We are using our WelcomeMessage component and giving it props */}
      <WelcomeMessage name="Alice" />
      <WelcomeMessage name="Bob" />
      <WelcomeMessage name="Charlie" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

What's happening here?

  1. The App component is the parent.
  2. It renders the WelcomeMessage component three times.
  3. Each time, it passes a different name prop.
  4. The WelcomeMessage component receives that name and displays it. We've created one reusable "template" and configured it differently each time using props.

Part 2: Hooks (Giving Components Memory and Superpowers)

The Core Idea: Before hooks, if you wanted a component to have its own internal "memory" (state) or do things when something happened (lifecycle events), you had to use cumbersome "Class Components." Hooks let you do all that and more in simple, clean "Functional Components."

Hooks are special functions that always start with the word use (e.g., useState, useEffect).

Let's focus on the two most important hooks.

1. useState (The Memory Hook)

The Analogy: A Personal Whiteboard

Imagine your component has a small whiteboard next to it.

  • The useState hook gives your component this whiteboard.
  • The component can write something on the board (the initial state).
  • It can look at what's on the board (the current state value).
  • It gets a special magic marker that is the only way to update what's on the board (the setter function).

When the component uses its magic marker to update the whiteboard, React knows something has changed and automatically re-renders the component to show the new information.

Simple Code Example

Let's build a simple counter.

import React, { useState } from 'react';

function Counter() {
  // 1. Give our component a "whiteboard" (state) called 'count'.
  //    The initial value is 0.
  //    We get back the current value (`count`) and the magic marker (`setCount`).
  const [count, setCount] = useState(0);

  return (
    <div>
      {/* 2. Display the current value from our whiteboard */}
      <p>You clicked {count} times</p>

      {/* 3. When this button is clicked, use the magic marker to update the board */}
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

What's happening here?

  1. useState(0) sets up the state. The count variable starts at 0.
  2. The component renders, showing "You clicked 0 times".
  3. When you click the button, the onClick function calls setCount(count + 1).
  4. React sees that the state was updated. It re-runs the Counter function.
  5. This time, the count variable is 1.
  6. The component renders again, showing "You clicked 1 times".

2. useEffect (The Action Hook)

The Analogy: "After ____ happens, do this."

useEffect allows your component to perform "side effects"—actions that interact with the world outside of React. This includes things like:

  • Fetching data from an API after the component first appears.
  • Setting up a timer.
  • Manually changing the document title.

It takes two arguments:

  1. A function to run (the "effect").
  2. An array of dependencies (the "trigger").

The dependency array tells useEffect when to run the effect.

  • [] (empty array): Run this effect only once, right after the component first renders on the screen. (Perfect for initial data fetching).
  • [someVariable] (array with variables): Run this effect every time someVariable changes.
  • No array at all: Run after every single render. (This is usually a mistake and can cause infinite loops).

Simple Code Example

Let's log a message to the console when our Counter component's count changes.

import React, { useState, useEffect } from 'react';

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

  // This is our "Action Hook"
  useEffect(() => {
    // This is the effect: log a message to the console.
    console.log(`The new count is: ${count}`);

    // This is the trigger: run the effect whenever `count` changes.
  }, [count]);


  // This effect runs only ONCE after the component first renders.
  useEffect(() => {
    console.log('Component has mounted!');
  }, []);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

What's happening here?

  1. When the component first renders, the second useEffect runs, and you'll see "Component has mounted!" in the console. The first useEffect also runs, printing "The new count is: 0".
  2. When you click the button, setCount is called.
  3. The state changes, so the component re-renders.
  4. Because count changed, the first useEffect's trigger is activated, and it runs again, printing "The new count is: 1". The second useEffect does not run again because its dependency array is empty.

Summary: Props vs. Hooks

Concept Props Hooks (useState, useEffect)
Purpose Pass data from Parent to Child Give a component internal memory & actions
Data Flow Top-down (unidirectional) Internal (manages its own data)
Analogy Configuration/Instructions (Ordering at a restaurant) Memory/Abilities (A personal whiteboard)
Can it be changed? No. Read-only by the child. Yes. Changed via its setter function (e.g., setCount).
Example <UserCard name="Bob" /> const [count, setCount] = useState(0);

Props and Hooks work together. A parent component might fetch data using useEffect, store it in its state using useState, and then pass parts of that data down to child components as props.

Top comments (0)