Understanding the difference between props and State in React

Prerequisites

Before diving into React, you should be familiar with HTML and CSS because they are necessary to create and style React components. Also, it's essential to have a solid grasp of JavaScript, as React is a JavaScript library. Understanding concepts like functions, variables, and object-oriented programming will be beneficial.

Table of contents

  1. Prerequisites

  2. Introduction to props

  3. Understanding State in React

  4. Declaring State within a Component

  5. Understanding and using Functions in state

  6. Proper State Update with a Callback Function

  7. Using a ternary operator with useState

  8. Quiz Questions

  9. Solutions to the questions

  10. conclusion

Introduction to props

Understanding props in React is all about knowing that properties aren't pushed into a component; they're received by it.

Learning how to code is easier when you can read and understand code. In this lesson, we'll get the hang of props and states by showing you practical examples. Consider this simple JavaScript function that calculates the area of a rectangle based on its length and width:

function areaOfRectangle(length, width) {
    return length * width;
}

const length = 10;
const width = 20;
const area = areaOfRectangle(length, width);

console.log(`The rectangle's area is ${area} square units.`);

In this example, notice that the properties (length and width) aren't defined within the function itself. This flexibility lets you change these values and reuse the function for different rectangles, just like assessing the gym-goers' areas when they're trying to get in shape.

This JavaScript function is a simple way to understand how props work in React. In React, data is sent into components to customize their behavior without changing their core logic.

Now, imagine if the function was written like this:

function areaOfRectangle(length, width) {
    let length = 2;
    return length * width;
}

const length = 10;
const width = 20;
const area = areaOfRectangle(length, width);

console.log(`The rectangle's area is ${area} square units.`);

What's wrong with the code above? Do you think it would calculate the area correctly?

This code breaks the props concept because it redefines the value of length within the function using let length = 2. This goes against the idea of props.

Props, Short for Properties

Props act as a way for parent components to communicate with child components. They allow child components to access and use properties in the parent component tree.

Here's an example of how props work between parent and child components:

Parent Component:

function Parent() {
    const message = "Hello from Parent Component";

    return (
        <div>
            <h1>Parent Component</h1>
            <ChildComponent message={message} />
        </div>
    )
}

child component

function ChildComponent(props) {
    return (
        <div>
            <h2>Child Component</h2>
            <p>{props.message}</p>
        </div>
    )
}

In the child component, props.message lets you access and display the message set in the parent component.

Take your time to understand these examples, experiment with changing the message, and practice writing and rewriting code without referring to it for better learning.

Understanding State in React

Now, let's demystify what state is in React. In contrast to props, React state represents variables used to store and manage data within a component. States are defined within the component itself, holding values created within React components.

Declaring State within a Component

React provides a function called useState to manage state. You can use it directly or as a hook:

import React, { useState } from 'react';

// or

const [state, setState] = React.useState(initialValue);

When you log console.log(state) after using useState(), you'll see an array containing the default state value and a function, like [initialValue, setState].

If you input text or values into useState(), here's what happens:

const [result, setResult] = React.useState("Hello, I'm learning React");
console.log(result);

From this code, you get both the default state value and a function in an array, like ["Hello, I'm learning React", setState].

To make things simpler, let's explore a code snippet and understand why it works the way it does:

export default function App() {
    const answer = React.useState("YES");
    return (
        <div>
            <p>Arsenal is the best club in Europe</p>
            <h1>{answer[0]}</h1>
        </div>
    )
}

Even if you strongly disagree with the statement, the answer will still be "YES." Why is that?

The reason is that we've set the default value to "YES" using React.useState("YES"). Additionally, we use {answer[0]} because, as I mentioned earlier, useState returns an array with two elements: the current state value and a function to update that state. We want to access the state value at index 0 in the array.

To practice this concept, try writing a question and setting the default value to either 'yes" or "no." It's a fun way to learn coding by doing it rather than just reading about it. When you feel comfortable, let's continue.

Now, let's enhance the code to allow user interaction on our page.

We can simplify {answer[0]} by using array destructuring. Here's how you can restructure the code to include the array and the function:

const [answer, func] = React.useState("YES");
console.log(answer); // logs out "YES"
<h1>{answer}</h1>

One of the great things about array restructuring is that you can name the elements as you like.

Understanding and using Functions in state

Functions are used to make changes so that React can handle those changes immediately. Let's clear our JavaScript code and write a new example. We'll create a useState code that uses an array and a function to ask a question and reply with "YES" or "NO."

export default function App() {
    const [Answer, func] = React.useState("YES");

    function handleClick() {
        func("NO");
    }

    return (
        <div onClick={handleClick}>
            <p>...</p>
            <h1>{Answer}</h1>
        </div>
    );
}

This way the answer changes from YES to NO or otherwise any time it's clicked.

Let's take it a step further and create something more exciting—an app with a counter that has two buttons, "+" and "-". The "add" button increases the number, and the "minus" button reduces it.

export default function App() {
    const [count, func] = React.useState(0);

    function add() {
        func(count + 1);
    }
    function minus() {
        func(count - 1);
    }
    return (
        <div>
            <button onClick={minus}>-</button>
            <h1>{count}</h1>
            <button onClick={add}>+</button>
        </div>
    );
}

Proper State Update with a Callback Function

Now let's write this in a proper way, making use of the function and asking it to behave like one. In the code above, you'll notice that we use a callback function when updating the state. For example, in the add function, we have:

export default function App() {
    const [count, func] = React.useState(0);

    function add() {
        func(prevCount => prevCount + 1);
    }
    function minus() {
        func(prevCount => prevCount - 1);
    }
    return (
        <div>
            <button onClick={minus}>-</button>
            <h1>{count}</h1>
            <button onClick={add}>+</button>
        </div>
    );
}

React really cares about not changing the state too directly. They suggest using a special function that takes the old state and uses that to figure out the new state. This way, we make sure we're always working with the most up-to-date information without messing up the state by changing it too directly. This is all about keeping things stable and avoiding any problems that might happen.

Using a ternary operator with useState

A ternary operator, commonly known as the conditional operator, serves as a concise method for expressing an if-else statement in JavaScript

Now Let's go back to our previous "YES/NO" example and make it more flexible, let's make it flip from YES to NO whenever the button is clicked.

import React, { useState } from 'react';

export default function App() {
    const [answer, setAnswer] = useState("YES");

    function handleClick() {
        setAnswer(prevAnswer => (prevAnswer === "YES" ? "NO" : "YES"));
    }

    return (
        <div onClick={handleClick}>
            <p>Click me to toggle:</p>
            <h1>{answer}</h1>
        </div>
    );
}

Before we conclude the discussion on props vs. state in React, let's answer a few questions:

  1. Which is more practical between props and state, and why?

  2. Which one can you change after setting it, props or state?

  3. What does "props" stand for?

  4. Which one allows changes to happen asynchronously?

  5. Props are considered read-only; what does this mean?

Solutions to the questions

PropsState
Props are useful for making components reusable.State is mutable, which means it can be changed.
"Props" stands for properties.State changes asynchronously.
Props are considered read-only.

Conclusion

In this article, we've covered everything beginners need to know about props and state in React, including their usage and when to apply them. Remember, a common secret to becoming proficient in coding is to practice by getting your hands on the keyboard and coding.

If you found this article helpful, please consider sharing it. Thanks for reading!