React 80% : useState and useEffect
Tags: webdev, react, hooks, beginners
Published: 2024-01-01 17:26:41

_Let's dive into React hooks. One thing to keep in mind is that hooks were introduced for functional components only. Hooks don't work inside classes._

> Hooks are just functions responsible for certain behavior. In this article, we will be discussing useState and useEffect.

- **useState**

_useState_ is a React hook used for managing state variables. We can declare a state variable and update it directly. useState is imported from the react module. 

Here is an example of useState:

```
const [count,setCount] = useState(0)
```
Here, `count `is the name of the variable, and `setCount `is the name of the callback function that will update the state. `useState(0)` means we set 0 as the default value. 0 will be rendered initially, and after that, when we update the variable, the new value will be rendered.

Now let's take an example of a counter app to learn more

```
import { useState } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const increase = () => {
    setCount(count + 1);
  };
  const decrease = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>count : {count}</h1>
      <button onClick={decrease}>-</button>
      <button onClick={increase}>+</button>
    </div>
  );
}
```

In the above code, we use `setCount `to update a new value, i.e., increasing the count by 1. Similarly, we can decrease the count value by 1. This is a basic way of writing code.

The problem arises when we use another `setCount `in the increase or decrease function. The count value ideally should decrease by 2, but this won't happen.

Add this code to the _counter app_, and you will see that the count will increase and decrease by 1 only:

```
 const increase = () => {
    setCount(count + 1);
    setCount(count + 1);
  };
  const decrease = () => {
    setCount(count - 1);
    setCount(count - 1);
  };
```

If we want to increase or decrease the count by 2, then we should pass a callback function:

```
const increase = () => {
    setCount((prevCount) => prevCount + 1);
    setCount((prevCount) => prevCount + 1);
  };
  const decrease = () => {
    setCount((prevCount) => prevCount - 1);
    setCount((prevCount) => prevCount - 1);
  };

```

Here, `setCount `takes a callback function that will track the previous value of `count `and then increase or decrease the count value.

Note: We passed `0 `as a default value. Since `0 `is a hard-coded value, it will run every time the component renders. To avoid rendering `0 `every time, pass a callback function that will return `0`:

```
import { useState } from "react";
function value() {
  console.log("render");
  return 0;
}
export default function App() {
  const [count, setCount] = useState(value());
  const increase = () => {
    setCount((prevCount) => prevCount + 1);
    setCount((prevCount) => prevCount + 1);
  };
  const decrease = () => {
    setCount((prevCount) => prevCount - 1);
    setCount((prevCount) => prevCount - 1);
  };

  return (
    <div>
      <h1>count : {count}</h1>
      <button onClick={decrease}>-</button>
      <button onClick={increase}>+</button>
    </div>
  );
}

```

`useState(value())` and `useState(0)` both work in the same way. Here, the value function will return `0` and log "render" every time. To avoid calling "render" every time, write `useState(() => return 0)`. It will render only one time.


- **useEffect** 

_useEffect_ is used to perform side effects in components and is imported from the React module. By "side effects," we mean tasks such as fetching data or updating the DOM, etc.

_useEffect_ takes two arguments: a _function_ and optional _dependencies_ (an array).

```
import { useEffect } from 'react';

useEffect(() => {
  //code
}, [dependencies]);
```

The dependencies array ensures when the effect will re-run.

There are three cases of dependency arrays:

1. No dependency array : `useEffect` will be called every time. Let's see `useEffect` in action:

```
import { useEffect, useState } from "react";

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

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
      console.log("called");
    }, 2000);
  });

  return (
    <div>
      <h1>Count is called {count} times.</h1>
    </div>
  );
}

```
Here, after every 2 seconds, the `count` will increase by 1, and "called" will be logged in the console.

2. Empty dependency array [] : `useEffect` will be called once,during initial render.

```
import { useEffect, useState } from "react";

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

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
      console.log("called");
    }, 2000);
  }, []);

  return (
    <div>
      <h1>Count is called {count} times.</h1>
    </div>
  );
}

```
In the above code , we added an empty dependency array `[]`.Now, `useEffect` will run only one time.

3. Some value passed in the dependency array: `useEffect` will be called every time whenever the value passed in the dependency array changes. We can pass any number of values in the dependency array.

```
import { useEffect, useState } from "react";

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

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
      console.log("called");
    }, 2000);
  }, [count]);

  return (
    <div>
      <h1>Count is called {count} times.</h1>
    </div>
  );
}

```

In the above code, `count` is passed in the dependency array. So whenever `count` is updated, `useEffect` will be called again. In the above code, the `count` will increase infinitely as every time `count` is updated, `useEffect` will be called again, and this will go on and on.

There is an effect _cleanup_ function, which will stop the `useEffect` re-execution, as there may be a memory leak problem. The _cleanup_ ensures that no unexpected behaviour occurs.

```
import { useEffect, useState } from "react";

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

  useEffect(() => {
    const timer = setTimeout(() => {
      setCount((count) => count + 1);
      console.log("called");
    }, 2000);

    return () => clearInterval(timer);
  }, [count]);

  return (
    <div>
      <h1>Count is called {count} times.</h1>
    </div>
  );
}
```

Note: `useEffect` will at least run once in the initial render.