State v/s Props

State v/s Props

Welcome back to the journey through the fundamental concepts of React development! In the previous blogs (Understanding the React Props and Mastering the React Props) we explored the ins and outs of props, uncovering their role in creating dynamic and reusable components. Now, it's time to take the next step and dive into a closely related topic: the age-old debate of "State vs. Props".

Understanding State

What is State?

"State" refers to the values that are managed by the component, similar to the variables declared inside a function. Any time you have changing values that should be saved/displayed, you will likely be using State.

To manage these states in React developers use React hooks or management libraries like redux. Later on in this blog will take a closer look at React hooks like useState and useEffect.

React Hooks

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes - they let you use React without classes.

React provides a few built-in Hooks like useState. You can also create your Hooks to reuse stateful behavior between different components.

When would I use a Hook?

If you write a function component and realize you need to add some state to it, previously you had to convert it to a class. Now you can use a Hook inside the existing function component.

Let's take a look at the built-in Hooks first.

Using the State Hook

This example renders a counter. When you click the button, it increments the value:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable called "count"
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

What does calling useState do?

When you invoke useState, you're essentially declaring a "state variable." While we've named it 'count' here, you have the freedom to use any label you prefer, such as 'banana.' This novel feature lets you maintain values across function calls – a means of preserving data.

Think of useState as a fresh approach to harnessing the very same powers that this.state offers within class components. In the traditional sense, variables tend to vanish when a function concludes its run. However, with state variables created using useState, React goes the extra mile to ensure that data persists even after a function's exit.

What do we pass to useState as an argument?

When calling useState, you provide a single argument: the initial state. Unlike the class-based approach, this state doesn't have to be an object; it could be a simple number or string if that suits your purpose.

For instance, consider our example where we're tracking the number of user clicks. In this case, you would pass 0 as the initial state, representing the initial click count. If you were dealing with multiple values to store in state, you'd call useState multiple times.

What does useState return?

It returns a pair of values: the current state and a function that updates it. This is why we write const [count, setCount] = useState(). This is similar to this.state.count and this.setState in a class, except you get them in a pair.

Now that we know what the useState Hook does, our example should make more sense:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable called "count"
  const [count, setCount] = useState(0);

We declare a state variable called count, and set it to 0. React will remember its current value between re-renders, and provide the most recent one to our function. If we want to update the current count, we can call setCount.

Reading State

In a function, we can use count directly:

<p>You clicked {count} times</p>

Updating State

In a function, we already have setCount and count as variables:

<button onClick={() => setCount(count + 1)}>
    Click me
</button>

Now, it's time to recap our understanding of what we've learned and break it down:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable called "count"
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

We import the useState Hook from React. It lets us keep local state in a function component.

In the Example component, we introduce a fresh state variable using the useState Hook. This Hook returns a pair of values, each of which we assign a name. Our chosen label for the variable is count, as it captures the tally of button clicks. We initialize this variable to zero by supplying 0 as the sole argument to useState. The second element in the returned pair is a function – it empowers us to modify the count state. In this case, we dub it setCount, encapsulating its role of updating the count value.

When the user clicks, we call setCount with a new value. React will then re-render the Example component, passing the new count value to it.

Array Destructuring

You might have noticed the square brackets when we declare a state variable. The names on the left aren’t a part of the React API. You can name your own state variables:

const [mixtape, setMixtape] = useState('smitherens');

This JavaScript syntax is called “array destructuring”. It means that we’re making two new variables mixtape and setMixtape, where mixtape is set to the first value returned by useState, and setMixtape is the second. It is equivalent to this code:

var mixtapeStateVariable = useState('smitherens'); // Returns a pair
var mixtape = mixtapeStateVariable[0]; // First item in a pair
var setMixtape = mixtapeStateVariable[1]; // Second item in a pair

Upon declaring a state variable using useState, we receive a pair – an array consisting of two elements. The first element represents the present value, while the second element is a function that facilitates updates. Accessing these elements through [0] and [1] can lead to confusion due to their specific roles. That's why array destructuring comes into play. By utilizing array destructuring, we enhance clarity and comprehension, making the code more intuitive.

We’ve learned about one of the Hooks provided by React, called useState. We’re also sometimes going to refer to it as the "State Hook". Now let's continue by learning the next Hook: useEffect.

Using the Effect Hook

useEffect is a versatile Hook that offers a solution to manage side effects in functional components. It's your gateway to perform tasks after rendering, whether it's updating the document title, fetching data from an API, or attaching event listeners.

What are side effects in React?

When your components interact with the outside world - fetching data, subscribing to events, manipulating the DOM – they're generating side effects. These side effects often need to be managed to prevent memory leaks, and unnecessary re-renders, and ensure a seamless user experience.

This is why useEffect exists: to provide a way to handle performing these side effects in what are otherwise pure React components.

For example, if we wanted to change the title meta tag to display the user's name in their browser tab, we could do it within the component itself, but we shouldn't.

function User({ name }) {
  document.title = name; 
  // This is a side effect.    
  return <h1>{name}</h1>;   
}

If we perform a side effect directly in our component body, it gets in the way of our React component's rendering.

Side effects should be separated from the rendering process. If we need to perform a side effect, it should strictly be done after our component renders. useEffect is a tool that lets us interact with the outside world but does not affect the rendering or performance of the component that it's in.

How to use useEffect?

Here's the basic structure of the useEffect Hook:

useEffect(() => {
  // Side effect logic
  return () => {
      // Cleanup logic (optional)
  };
}, [dependencies]);

--> The first parameter is a function containing your side effect logic.

--> The optional return function, known as the cleanup function, handles cleanup after the component is unmounted or before the next side effect.

--> The second parameter, an array of dependencies, specifies when the effect should be re-run.

What is the cleanup function in useEffect?

The cleanup function in the useEffect Hook is a mechanism that allows you to handle any necessary cleanup operations when a component unmounts or before the next effect runs. It helps prevent memory leaks and ensures that your component doesn't leave any lingering side effects behind.

Here's how the cleanup function works:

  1. Unmounting of Component: When a component that has a useEffect runs, and then it's removed from the screen (unmounted), the cleanup function associated with that effect is executed.

  2. Before Next Effect: If the component re-renders and the effect is run again, the cleanup function of the previous effect is executed before the new effect is run.

The cleanup function is especially useful when your effect involves setting up subscriptions, event listeners, timers, or any resource allocation that needs to be properly released when the component is no longer in use.

Here's an example of how you might use the cleanup function in a useEffect:

useEffect(() => {
  // Effect logic
  const subscription = subscribeToSomeEvent();

  // Cleanup function
  return () => {
    unsubscribeFromSomeEvent(subscription);
  };
}, []);

In this example, when the component unmounts or before the next effect runs (if the dependency array is empty), the unsubscribeFromSomeEvent function is called, ensuring that the subscription is properly cleaned up.

Now, it's time to recap our understanding of Props.

Understanding Props

"Props" refers to the properties being passed into a component in order to for it to work correctly, similar to how a function receives parameters.

A component receiving props is not allowed to modify those props. (I.e. they are "immutable".)

State v/s Props

State refers to the internal data managed by a component. It represents the dynamic aspects of a component that can change over time. Each component can have its own state, and when state changes, React re-renders the component to reflect the updated data.

Props are external inputs that a parent component passes to its child components. These inputs are immutable, meaning they cannot be modified within the child component. Props provide a way to communicate data from parent to child components, enabling component composition and reusability.

Distinguishing State and Props

  1. Mutability:

    --> State is mutable; it can be updated within a component using appropriate methods or Hooks.

    --> Props are immutable; they cannot be changed within the receiving component.

  2. Source:

    --> State is managed within the component itself.

    --> Props are passed from parent to child components.

  3. Initiation:

    --> State is usually initialized using the useState Hook or class component's constructor.

    --> Props are passed down from parent components when the child components are created.

Use Cases

State: State is ideal for managing data that can change during the component's lifecycle. Examples include toggling UI elements, tracking user input, and managing component-specific state.

Props: Props shine when you need to pass data from a parent component to its child components. This is useful for creating reusable components and structuring complex UI hierarchies.

When to Use Each Concept

Use state when you want to manage data that is local to a component and can change over time. For example, tracking the number of clicks on a button within that component.

Use props when you need to pass data from a parent component to its child components, fostering component reusability and a clear separation of concerns.

Conclusion

State and props serve as cornerstones in React development, each contributing distinct roles in data management and component communication. By understanding the nuances between these concepts, you empower yourself to build applications that are flexible, interactive, and efficiently structured. Whether you're tracking internal changes or orchestrating data flow across your app's hierarchy, grasping the dynamics of state and props will elevate your React development prowess.

Thanks for Reading.