Hooks in React
Tags: webdev, programming, react
Published: 2021-05-09 06:55:02

Today we'll learn about the widely used hooks in React. First, let me tell you the need for hooks. As we all know React has functional and class components. Previously, the functional components were only used to render the data but didn't consist of the business logic or any side effect in itself. 

So hooks were introduced to implement lifecycle methods and states in functional components. They also bought the idea of code reusability along with them, that's why it was so quickly accepted within the React Community.


** Drum rolls 🥁 **

Let's move ahead with the main topic.

- **useState hook**

This hook helps us to use and maintain a state within the functional component. It's very easy to use. The useState hook returns an array having two elements, the first one is the state variable and the second is the function that modifies the state variable.


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

export default function App() {
  const [number, setNumber] = useState(0);

  return (
    <div className="App">
      <button onClick={() => setNumber(number - 1)}>Subtract</button>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <button onClick={() => setNumber(number + 1)}>Add</button>
    </div>
  );
}
```

Here, we have `number` as the *state variable* and `setNumber` as the *function* which will modify the `number`.


         
  






- 
**useEffect hook**

This hook works as a replacement for all the lifecycle methods which were used in class components. It contains a callback and a dependencies array. The hook will run every time when any of the values in the dependencies array changes.

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

export default function App() {
  const [number, setNumber] = useState(0);
  const [isEven, toggleEven] = useState(true);

  useEffect(() => {
    if (number % 2 !== 0) {
      toggleEven(false);
    } else {
      toggleEven(true);
    }
  }, [number]);

  return (
    <div className="App">
      <button onClick={() => setNumber(number - 1)}>Subtract</button>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <button onClick={() => setNumber(number + 1)}>Add</button>
      <p>{isEven ? "Even" : "Odd"}</p>
    </div>
  );
}
```

Here as you can see, the dependencies array contains `number`. So every time the user presses any of the buttons or changes the input value, the `useEffect` hook will *trigger* and it'll check the number whether it's odd or even.

Within this hook, you can call side effects such as changing something in *DOM*, fetching data from an *API*, etc.

One more thing used in this hook is the *cleanup* function, which runs when we return a function in the *callback*. This function helps in cleaning of side effects i.e clearing a timer, closing a web socket, etc.



- **useContext hook**

As in the class components, we had the **Context API** in the same way, we have `useContext` hook in functional components. This hook basically helps you to maintain a common global state across components. When the state changes it triggers re-renders across all the child components under the Context, even if the parent component uses `shouldComponentUpdate` or  `React.memo`.

This hook can be used to implement a loading state within the application, passing data to children components, etc.

To create it, we use the `createContext` function and pass the initial value. In the context provider, we pass a prop called `value` which consists of the context variables and functions to modify the context.  

```javascript
import { createContext } from "react";

export const UserContext = createContext({
  name: "Initial Name"
});                                                           
```

Then we use this context in our *Parent Component* and wrap our app inside the Context Provider and pass a value. So now all the child components have the access to the `value` prop.

```javascript
import { useContext, useState } from "react";
import Person from "./Person";
import { UserContext } from "./Context";

export default function App() {
  const user = useContext(UserContext);

  const [person, togglePerson] = useState(user);

  return (
    <UserContext.Provider value={[person, togglePerson]}>
      <div className="App">Hello {user.name}!</div>
      <Person />
    </UserContext.Provider>
  );
}
```

Now in the child component `Person` we can access the `value` prop and we can change the context value too.

```javascript
import { useContext } from "react";
import { UserContext } from "./Context";

function Person() {
  const [person, togglePerson] = useContext(UserContext);

  return (
    <div>
      Person: {person.name}
      <button
        onClick={() => {
          togglePerson({ name: "Stuart Little" });
        }}
      >
        Change
      </button>
    </div>
  );
}

export default Person;
```

This way you can use the `useContext` hook. Make a context, wrap the parent component with the context's provider and you are good to go!

You can experiment with the above code [here](https://codesandbox.io/s/usecontext-hook-zuoxi).


- **useReducer hook**

If you know Redux then you already know what this hook does, if not then simply it changes the `state` according to the `action` passed. It helps in maintaining a local state easily whereas in Redux we can do that globally.

To use the reducer globally, we can make a context and pass it across the components. Geddit!

Here we have an initial state and a dispatch to modify the state. Within the dispatch, we pass actions along with some info called `payload`. The action then goes to the reducer which in turn changes the state.

```javascript
import { useReducer } from "react";
import "./styles.css";

const initialState = [
  {
    name: "Mad Angles",
    quantity: 5
  },
  {
    name: "Pringles",
    quantity: 3
  },
  {
    name: "Lays",
    quantity: 2
  },
  {
    name: "Kurkure",
    quantity: 1
  },
  {
    name: "Uncle Chips",
    quantity: 9
  }
];

function reducer(state, action) {
  switch (action.type) {
    case "add":
      return [...state, action.payload];
    case "delete":
      return state.filter((_, index) => index !== action.payload);
    default:
      return state;
  }
}

export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <ul>
        {state.map(({ name, quantity }, index) => (
          <div className="list-item">
            <li key={name}>
              <b>{name}</b> - {quantity}
            </li>
            <button
              onClick={() => {
                dispatch({ type: "delete", payload: index });
              }}
            >
              delete
            </button>
          </div>
        ))}
        <button
          onClick={() => {
            dispatch({
              type: "add",
              payload: {
                name: "Doritoes",
                quantity: 5
              }
            });
          }}
        >
          add
        </button>
      </ul>
    </div>
  );
}
```

You can find the above code [here](https://codesandbox.io/s/github/deepansh946/use-reducer-example/tree/main/?file=/src/App.js).


That's it for now. There are other hooks too like `useRef`, `useCallback` but they are rarely used. Thanks for reading this article. Let me know if anything is not clear.

Happy Coding!