The React useEffect Hook for Absolute Beginners

React State Hook

Let's talk about the state. A vital part of the React community. To help you get started with Hooks, I'll be covering the most ubiquitous of them: useState ().

Examine a class that makes use of state.

import React, { Component } from 'react';
import './styles.css';
class Counter extends Component {
            state = {
                        count: this.props.initialValue,
            };
            setCount = () => {
                        this.setState({ count: this.state.count + 1 });
            };
            render() {
                        return (
                                    <div>
                                                <h2>This is a counter using a class</h2>
                                                <h1>{this.state.count}</h1>
                                                <button onClick={this.setCount}>Click to Increment</button>
                                    </div>
                        );
            }
}
export default Counter;


The use of React Hooks allows us to redesign this component while stripping it of unnecessary code, making it more readable:

import React, { useState } from 'react';
function CounterWithHooks(props) {
            const [count, setCount] = useState(props.initialValue);
            return (
                        <div>
                                    <h2>This is a counter using hooks</h2>
                                    <h1>{count}</h1>
                                    <button onClick={() => setCount(count + 1)}>Click to Increment</button>
                        </div>
            );
}
export default CounterWithHooks;

React State Syntax

Okay, we have our first hook! Hurrah!

const [count, setCount] = useState();

Essentially, array assignments are handled through destructuring here. There are two benefits to using the useState() function:

a state value storing variable (count) and a setCount function (used to alter the value).

You're free to give them whatever names you like:

const [myCount, setCount] = useState(0);

Additionally, they may be used anywhere in the code just like any other variables or functions:

function CounterWithHooks() {
const [count, setCount] = useState();
return (
<div>
<h2>This is a counter using hooks</h2>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>Click to Increment</button>
</div>
);
}

Take note of the top-level useState hook. We are stating and deconstructing the following:

count: a number that will keep our internal state value set

A function that modifies our internal "counter" variable.

Next, we'll reach this line in the code:

<h1>{count}</h1>

This demonstrates the application of a state hook variable. By enclosing our count variable in JSX's, which causes it to be processed as JavaScript, we are able to see its value shown on the page.

If we look at the traditional "class-based" approach to employing a state variable, we can see several key differences:

<h1>{this.state.count}</h1>

You'll see that we no longer have to fret about utilizing this, which simplifies our lives tremendously; for instance, the VS Code editor will notify us if count is not specified, helping us to see issues before they snowball. On the other hand, it won't know whether this.state.count is undefined until it's actually used.

Now, onto the next line!

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

In this case, we're modifying the count variable by using the setCount method (recall that we destructured/declared this from the useState() hook).

We increment the count variable by one every time the button is pressed. This causes a re-render, and React automatically adjusts the display to reflect the new count value due to the state transition. Sweet!

What are my options for establishing a default value?

By providing a value as an input to the useState() idiom, the starting state may be determined. A fixed value may be used here.

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

It may also be gleaned from the set pieces:

const [count, setCount] = useState(props.initialValue);

By doing so, the count would be initialized to the number specified by the props.initialValue property.

That's all there is to useState (). The great thing about using state variables and functions is that they are treated exactly the same as any other variables and functions you could create.

When there are several state variables, how do I manage them?

The fact that hooks can do this is also really amazing. In a given part, we may have as many as we desire.

const [count, setCount] = useState(props.initialValue);
const [title, setTitle] = useState("This is my title");
const [age, setAge] = useState(25);

There are 3 distinct items representing states. To modify the age, for instance, we would simply use the setAge() method. The same holds true for rank and status. We are liberated from the inefficient old method of maintaining state using setState() and a centralised heap of class components:

this.setState({ count: props.initialValue, title: "This is my title", age: 25 })

What about refreshing when props or state are updated?

After switching to hooks and functional components, we can no longer use the standard React lifecycle methods like componentDidMount, componentDidUpdate, and so on. Poor thing! Do not worry, React has provided us with yet another tool:

  • Tune the Drums *

The useEffect!

We save "side effects" in the Effect hook (useEffect()).

Consequences, huh? What? Let's digress for a second and talk about what it means when something has a side effect. Our comprehension of useEffect() and its value will increase greatly as a result of this.

In the realm of computers, the explanation would be dull.

When a procedure modifies a variable that is outside of its scope, this is known as a side effect in computer programming.

"when a component's variables or state change depending on some outside item," as the React community puts it. This might include things like:

  • A state transition occurs when an element gets updated parameters.
  • What happens when a piece of code makes an API request and acts on the result (e.g, changes the state)

To what end, therefore, is it classified as a "side effect"? The outcome of this action is uncertain at this time. In the case of API calls, we can never know for sure what parameters will be sent to us or what kind of answer we will get. Furthermore, we are unsure of the consequences of this on our component.

While it's true that we can build code to validate, manage errors, and the like, this does not mean that we know for sure what such actions will cause.

A common kind of side effect is the modification of our internal states in response to outside stimuli.

Now that we have it settled, we can return to React and the useEffect Hook.

Life cycle methods such as componentDidMount(), componentDidUpdate(), etc. are unavailable when utilizing functional components. Therefore, the existing React Life Cycle hooks have been replaced with useEffect hooks.

Here's how the useEffect hook stacks up against a class-based component:

import React, { Component } from 'react';
class App extends Component {
componentDidMount() {
console.log('I have just mounted!');
}
render() {
return <div>Insert JSX here</div>;
}
}

And now using useEffect():

function App() {
useEffect(() => {
console.log('I have just mounted!');
});
return <div>Insert JSX here</div>;
}

First, it's vital that you understand that the useEffect hook is automatically invoked before each and every render and re-render. Therefore, the useEffect hook will be invoked repeatedly whenever the state of your component changes or when your component receives new props.

Invoking a function once (componentDidMount)

Is there a way to restrict hook execution to once per component mount rather than each time the component is rendered? For instance, it's undesirable for data fetched from an API by a component to be re-fetched each time the component is re-rendered.

The useEffect() hook accepts an array as a second parameter, containing the conditions under which the hook should be executed. The effect hook is activated when the value is modified. To trigger an effect only once, simply supply an empty array as the parameter.

useEffect(() => {
console.log('This only runs once');
}, []);

In other words, the useEffect hook will execute normally during the initial render. However, useEffect will assume that your component has changed when it re-renders "I don't need to run again because I've already done so and the array contains nothing. I need to go back to bed." and makes no effort to do so.

In conclusion, the useEffect hook is invoked only once on mount when the array is empty.

Using repercussions when circumstances shift (componentDidUpdate)

We've discussed how to limit the number of times a useEffect hook is executed, but what about when our component is passed a new prop? Alternatively, we'd like to trigger the execution of a script whenever the state shifts. Hooks make it possible for us to do this as well!

useEffect(() => {
console.log("The name props has changed!")
}, [props.name]);

Take note that this time, the props.name variable is being passed on to the useEffect array.

The useEffect hook will execute normally, at the start of the initial load, in this case. The useEffect hook will be activated whenever your component gets a new name prop from its parent.

The same holds true for state variables:

const [name, setName] = useState("Chris");
useEffect(() => {
console.log("The name state variable has changed!");
}, [name]);

Each time the name variable is modified, the component will re-render and the useEffect hook will be activated, causing the message to be shown. Because this already is an array, we can insert several items:

const [name, setName] = useState("Chris");
useEffect(() => {
console.log("Something has changed!");
}, [name, props.name]);

This time, the console message will be shown whenever the useEffect hook is activated, regardless of whether the name state variable or name prop has changed.

Is componentWillUnmount() available for use?

Simply returning a function from the useEffect hook causes it to be executed immediately before the component is unmounted.

useEffect(() => {
console.log('running effect');
return () => {
console.log('unmounting');
};
});

Can I combine hook types?

Yes! You're free to combine and utilize whatever many hooks you wish inside a single component:

function App = () => {
const [name, setName] = useState();
const [age, setAge] = useState();
useEffect(()=>{
console.log("component has changed");
}, [name, age])
return(
<div>Some jsx here...<div>
)
}

Conclusion

So there you go. With the help of hooks, we can write less-cumbersome React components using traditional JavaScript functions.

You are free to experiment with construction on your own in the React hooks universe now.