## HOOKS + CONTEXTAPI === AWESOME
Published: 2020-11-30 05:05:14

*Disclaimer: Only for ReactJS/JS Devs - TLDR*

Hey NERDS. We are gonna discuss about some **AWESOME** concepts in React like

 - **Hooks (useState, useEffect, useContext & useReducer)** &
 - **Context API**

*FIRST THINGS FIRST,*

This blog assumes that if not decent, at-least some level of understanding in when & how to use class components, state, props & handling events.

With that clarification out of our way, lets get started ->
For those who use Class Components for a while, as per docs **HOOKS** are a new addition in **React 16.8** & by this FEB 2021, it will be 2 yrs old (not so new, may be) 

Having said that, Hooks are better when it comes to performance, abstraction & readability in comparison to class based components. Yes true, if you don't believe my word, take it from [React Core Team demo](https://youtu.be/dpw9EHDh2bM)
*NOTE: Video is about inspiration for HOOKS*

**But ... What is HOOK?**

Provides some direct API that makes us to use state in functional components . In simple terms, they let you use state & other react features without having to write a class.

Here is an implementation of hook called `useState` hook for example,


```javascript
import React, { Fragment, useState } from "react";

export const Example = () => {
  const [name, setName] = useState("");
  const [login, setLogin] = useState(false);
  return (
    <Fragment>
      {!login ? (
        <input
          type="name"
          value={name}
          placeholder="Enter your Name"
          onChange={(e) => setName(e.target.value)}
        />
      ) : (
        <div className="display__text">Hello {name}</div>
      )}

      <button type="submit" onClick={() => setLogin(!login)}>
        {!login ? "Login" : "Go back"}
      </button>
    </Fragment>
  );
};

```
        
[Basic useState implementation](https://codesandbox.io/s/login-hooks-soz9h?file=/src/Contexts/test.js:0-314)

From above, you can see it is just simple login simulation app, i have used `useState` hook to use the state within the functional Component, one state for handling user input name field and other for toggling into welcome page.

Yes, you can `useState` as many times you want, there is no restriction but there is one caveat to  using hooks in general, that is they should be used only inside the function definition.

Just for Comparison, check the equivalent class component implementation here,



```javascript
import React, { Component, Fragment } from "react";

export class Example extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "",
      login: false
    };
  }

  render() {
    return (
      <Fragment>
        {!this.state.login ? (
          <input
            type="name"
            value={this.state.name}
            placeholder="Enter your Name"
            onChange={(e) => this.setState({ name: e.target.value })}
          />
        ) : (
          <div className="display__text">Hello {this.state.name}</div>
        )}

        <button
          type="submit"
          onClick={() => this.setState({ login: !this.state.login })}
        >
          {!this.state.login ? "Login" : "Go back"}
        </button>
      </Fragment>
    );
  }
}

```

[Class Based Implementation](https://codesandbox.io/s/login-class-m2251)

I bet you can already see the difference, not only 10 unnecessary lines are removed, overall code logic looks neat. We can further drill down in our hooks implementation

```javascript
import React, { Fragment, useState } from "react";

export const Example = () => {
  //using objects to keep multiple states
  const [state, setState] = useState({ name: "", login: false });
  const { name, login } = state;

  return (
    <Fragment>
      {!login ? (
        <input
          type="name"
          value={name}
          placeholder="Enter your Name"
          onChange={(e) => setState({ ...state, name: e.target.value })}
        />
      ) : (
        <div className="display__text">Hello {name}</div>
      )}

      <button
        type="submit"
        onClick={() => setState({ ...state, login: !login })}
      >
        {!login ? "Login" : "Go back"}
      </button>
    </Fragment>
  );
};
```
[Modified useState implementation](https://codesandbox.io/s/login-hooks2-2u80q?file=/src/Components/Example.js:0-718)


Well, this look more better than before. Instead of using many `useState`(s) , irrespective of number of states in your application, we can use single `useState` call with an object to account for all the states.  Also, check i have also changed the setLogin, setName into single setState call with **`(...)` spread operator** to update the respective states on particular event.

---

All is fine. But how to use life cycle methods like `componentDidMount`, `componentDidUpdate`, `componentWillUnmount`for API calls or side effects in HOOKS?

To answer that, we have an another hook called  `useEffect` which takes function as a argument. Cool thing about this hook is, it replaces all the life cycle methods mentioned above.

```javascript
import React, { Fragment, useState, useEffect } from "react";
import Axios from "axios";

export const Example = () => {
  const [state, setState] = useState({ posts: [] });
  const postsUrl = "https://jsonplaceholder.typicode.com/posts";

  useEffect(() => {
    //Fetching Posts

    const fetchPosts = async () => {
      const posts = await Axios.get(postsUrl);
      setState({ ...state, posts: posts.data });
    };
    try {
      fetchPosts();
    } catch (err) {
      console.log("Network error", err);
    }
    //dependency array is none, it acts as componentDidMount
  }, []);

  return (
    <>
      <h1>My posts</h1>
      <ul>
        {state.posts.length > 0 &&
          state.posts.map((posts, index) => {
            return <li key={index}>{posts.title}</li>;
          })}
      </ul>
    </>
  );
};

```
[Basic useEffect implementation (componentDidMount)](https://codesandbox.io/s/login-hooks3-4i3z6)



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

export const Example = () => {
  const [title, setTitle] = useState("");

  useEffect(() => {
    document.title = title;
    //runs everytime when title state is changed
    //Acts as componentDidUpdate
  }, [title]);

  return (
    <input
      type="text"
      name="title"
      value={title}
      placeholder="Enter your title"
      onChange={(e) => setTitle(e.target.value)}
    />
  );
};


```

[Basic useEffect implementation (componentDidUpdate)](https://codesandbox.io/s/login-hooks4-6338c?file=/src/Components/Example.js:0-453)

From above you can see `componentDidMount` & `componentDidUpdate` implementation in hooks with `useEffect`.  First one fetches posts from an fake rest API endpoint and empty dependency array is passed as an second argument to simulate `componentDidMount` and second one updates the title tab of browser whenever the input field value is updated by the user. Note it has an dependency array value and it simulates `componentDidUpdate`.

In addition to `useState` & `useEffect` hook there are built_in_hooks like `useReducer`, `useRef`, `useLayoutEffect` & some more which you can check in [React Docs](https://reactjs.org/docs/hooks-reference.html)

---

**Alright! What is Context in nutshell?**

In simple terms, if you use context, we can avoid prop drilling meaning there is no need to pass props to unnecessary intermediate component in between when you work with deep nested components.
 
```javascript

import React, { createContext } from "react";

//creating context
export const AppContext = createContext();

//Not necessary in react new versions
export const AppConsumer = AppContext.Consumer;

//Exporting provider
export const AppProvider = ({ children }) => {
  return <AppContext.Provider>{children}</AppContext.Provider>;
};


```

[useReducer WITH contextAPI (AppContext.js)](https://codesandbox.io/s/reducer-context-cii49)


You can see, I have to `createcontext` first and passing initial values to it is optional, then export respective `context` and `provider` in *AppContext.js*.

*Note: You have to wrap the `children` prop inside the `Provider`
pass in the values you wanna pass in `value` prop in `Provider` so that you can use the values latter in wherever you wanna use in component tree (Here we have passed dispatch function and state)*



```javascript
import React from "react";
import "./styles.css";
import { Example } from "./Components/Example";
import { AppProvider } from "./Contexts/AppContext";

export default function App() {
  return (
    <AppProvider>
      <Example />
    </AppProvider>
  );
}


```

[useReducer WITH contextAPI(App.js)](https://codesandbox.io/s/reducer-context-cii49)


Make sure to wrap the provider with components you wanna use context values in `App.js` as well.

So, all set before talking about how to use context values inside the respective components, there is another hook we need to discuss about which simulates how `redux` works called `useReducer`



![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r87hwrmfzdj5xazgthur.jpg)



For those who doesn't know how `redux` works, this is the simple flow diagram that explains well



Redux is quite complex to understand but in simple terms, we as users dispatch an action (trigger an event) in an application, there is pure function called `reducer`which takes in respective action and the current state,  updates with new state based on the action.


```javascript

import React, { createContext, useReducer } from "react";
//importing Reducer
import { reducer } from "../reducer";

//creating context
export const AppContext = createContext();

//Not necessary in react new versions
export const AppConsumer = AppContext.Consumer;

//Exporting provider
export const AppProvider = ({ children }) => {
  //usng useReducer hook and passing reducer and initial state to it
  const [state, dispatch] = useReducer(reducer, []);

  //pass the app state and dispatch function to the value prop in provider
  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
};


```

[useReducer WITH contextAPI (AppContext.js)](https://codesandbox.io/s/reducer-context-cii49)


`useReducer` hook takes in two things - reducer function and the state and return two things again the state and dispatch function

```javascript
//reducer function which takes in dispatched action and update
//the respective state

export const reducer = (todos, action) => {
  switch (action.type) {
    case "ADD_TODO":
      return [
        ...todos,
        {
          id: Date.now(),
          todoName: action.payload.todoName,
          completed: false
        }
      ];
    default:
      return todos;
  }
};


```

[useReducer WITH contextAPI (reducer.js)](https://codesandbox.io/s/reducer-context-cii49)


Here you can see the implementation of reducer, which is nothing but a pure function takes in state and action. Based on the action type, we update the state.
**Note**: payload (optional) is the data we pass while dispatching an action.

So, todos is our initial State and with help of reducer we are updating the state, here it is adding to the todo array with condition of action type and payload.

All good. Now there is only one piece remaining to fix this puzzle which is attaching dispatching function to form submission. To do that, if you remember we have passed `state` and `dispatch` in `Provider` . In order to access that, we have an another hook called `useContext`that takes in a parameter of respective provider. Just by using this one line, we will get access to context values.


```javascript

import React, { Fragment, useState, useContext } from "react";
import { AppContext } from "../Contexts/AppContext";
import { Todo } from "./Todo";

export const Example = () => {
  const [todoName, setTodoName] = useState("");
  // here used useContext hook to access state & dispatch from top level
  const { state, dispatch } = useContext(AppContext);

  const handleSubmit = (e) => {
    e.preventDefault();
    //dispatching action here along with payload
    dispatch({ type: "ADD_TODO", payload: { todoName: todoName } });
    setTodoName("");
  };
  return (
    <Fragment>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          name="todoName"
          value={todoName}
          onChange={(e) => setTodoName(e.target.value)}
          placeholder="Enter the todo Name"
        />
        <button type="submit">Submit</button>
        <Todo todos={state} />
      </form>
    </Fragment>
  );
};


```

[useReducer WITH contextAPI (Example.js)](https://codesandbox.io/s/reducer-context-cii49)



Now that we have our dispatch we want to attach it with form submission and pass the action type and payload along with it


Finally pass the state you get from useContext to Todo Component to list down below the field.

This might lead to one question, why so much code just to update state i can do this easily with `useState`. Yes you can. But what if you want to update the todo, delete the todo, mark as completed then there will be whole lot of complexity if you use `useState`that is where `useReducer` comes handy.


*`useReducer` VS `useState`
`useReducer` is meant for handling complex state update updates, every action for the application will be mentioned only in reducer function that makes state changes predictable. Though both does the same things, using one over another completely depends on the situation you are in.*




***Final Thoughts:***

*This is not ALL, there are other hooks which has good use cases but it is not covered here. Checkout if you want to learn more about HOOKS in this [docs](https://reactjs.org/docs/hooks-reference.html). Once you feel confident in using hooks, you can learn to develop your own CUSTOM HOOKS* *Yes you can do that.

*Please let me know if there is anything i've missed,*

*Happy Coding**

***