How React’s useEffect Hook Changed My Life
Tags: react, webdev, javascript, beginners
Published: 2023-04-14 15:23:18

_Oh my God, why can’t my JavaScript find my React Component. WhAt Am I DOiNg WronGGg!!!!?!?_

Is probably something every developer starting out with React has said at some point. Luckily the creators of React gave us a hook to combat this.

Any code that alters a component after the component has been mounted is called a **“side effect”**. To accomplish this, us developers are left with the **useEffect** hook.

In the below example, we are attempting to replace the textContent of a paragraph element with new text. But with this setup, an error will be thrown and no changes will be made. **WHY?**

```javascript
function Content(){

  document.getElementById("content").textContent = "New Text";

  return(
    <p id="content">Replace This Text</p>
  )
}
```
I’ll tell you why, components in React are still JavaScript objects until they have been mounted/rendered. In this example the statement to change the textContent of the paragraph is actually executed **BEFORE** the React Component has been returned, much less mounted.

**_So what can you do to access the component AFTER it’s been rendered to the DOM as HTML?_**

Now we come to it, the how. If we update our example to use the useEffect hook to get the job done, then it does what it sounds like, it gets the job done!

Now keep in mind that you **DO NOT** put your code directly into the **useEffect** function’s arguments. **useEffect** takes a function which is executed upon triggering. The simplest way for me is to pass an anonymous function containing all my JavaScript to the hook like in the example below. But you could include a named function instead.

```javascript
function Content(){

  React.useEffect(()=>{
    document.getElementById("content").textContent = "New Text";
  }); 

  return(
    <p id="content">Replace This Text</p>
  )
}
```

_**Now Guess What?**_ The code works and will now change the textContent of our paragraph to **“New Text”**.

_**What about async data????**_

If we have a value that we are fetching from an API. We kind of need to update the part of our application that relies on that data once we receive it right? **RIGHT**.

In the below example, I’ve altered our Content component to rely on some data from an API. Using **useEffect**, we define and use an async function to fetch our data and set the state of our text to the response text.

```javascript
function Content(){

const [contentText, setContentText] =  React.useState("Replace This Text");

React.useEffect(()=>{
  getData();
  async function getData(){
    const fetchData = await fetch("https://urltoapi.com");
    const textData = await fetchData.text();
    setContentText(textData);
  }
}); 

  return(
    <p id="content">{contentText}</p>
  )
}
```

**React does not allow for the function passed to useEffect to be asyncronous. So you have to define it INSIDE of the passed function and execute it there.**

**_But William, my code runs every single time the component is updated and it’s breaking my code!_**

Yes, yes it does. This is by design. By default, **useEffect** is run every time the component needs to update. For those of us that need to limit this like when you’re developing a SPA (single page application) and you need to manually trigger **useEffect** at a certain time, luckily, again we are saved by the React creators.

**useEffect** takes a second optional argument. An array of dependency states/values. Whenever one of these state’s values changes is when the **useEffect** hook is re-triggered. Whether this be on the component updating or any time in between.

Below I’ve altered our Content component to trigger **useEffect** every time the **“Trigger useEffect”** button is clicked, which changes the **triggerCount** state, and that state is a value in the **useEffect**’s dependency array.

```javascript
function Content(){
  
  const [triggerCount, setTriggerCount] = React.useState(1);

  function handleClick(){
    setTriggerCount((oldval) => ++oldval);
  }

  React.useEffect(()=>{
    console.log(`useEffect has been triggered ${triggerCount} time(s)!`);
  }, [triggerCount]);

  return(
    <button onClick={handleClick}>Trigger useEffect</button>
  )
}
```

**_But I only want it to trigger ONCEEE!!!_**

Well, if you give **useEffect** an empty array as the dependency array, the hook will only trigger once, and this is when the component has been mounted/rendered. This is because when you provide a dependency array, **useEffect** waits for one of those values to change before it re-triggers. But if you don’t provide any values, they cannot change, so it will not re-trigger.

So for those who learn visually, here’s an alteration of the first example where useEffect only triggers once.

```javascript
function Content(){

  React.useEffect(()=>{
    document.getElementById("content").textContent = "New Text";
  }, []); 

  return(
    <p id="content">Replace This Text</p>
  )
}
```

So that’s it for this article. I really hope you learned something new and enjoyed it in the process. I did spend a bit of time writing this so if you did enjoy reading it, let me know :D.

For more tips, tricks and tutorials follow me on [YouTube](https://www.youtube.com/channel/UCKuVsmlR9mRSAatMjgqhsSQ) or [Instagram](https://www.instagram.com/growincode/).