All React Hooks and Concepts In A Single Post!! 🤗
Tags: react, javascript, webdev
Published: 2022-04-02 13:09:34

First of all React is a JS Library not a Complete Framework 🙂 so for making a complete web application you need to know a lot of other things 🤭 that you can use with React. In this Post I will cover React concepts, Hooks and some good practices Ofc... 😁
We use React to make reusable components that can be used in a logical way to make UI. Making components in React is as easy as making a function 🤩.
For Example 👇🏻 it is a simple react component in which we can pass data as arguments which can be easily referenced inside the functions 
```React
function Component(props){
    return <h1>{props.text}</h1>
}
```
#Ohk But Now what are States in React??
The state object is where you store property values that belongs to the component. When the state object changes, the component re-renders which basically allows us to manage changing data in an application 🆒.
Now Lets Learn about states using useState()

---
# useState()

```React
const component = () => {
    // Tip: use states only inside components
    // lets console.log the state and lets see what it returns
    console.log(useState(100));
    // this will return an array [100,f]
    // basically this returns a state and a function to update the state
    // we can destructure the array and get the state and the function
    const [state, setState] = useState(100);


    return (
        <div>
            hiiieeee
        </div>
    )
}
```
but you can't ☠️ directly update the value of state by using = operator as this will change the value but it will not re render the component so basically react wants 😩 that you pass the value in the setState function if you need to change the state.

### passing functions inside the useState() 🤔

```React
// you can also pass function in useState it will set the initial value to what function returns it is useful when you use computationaly high task as initial state
const [state, setState] = useState(() => {
        console.log("initial state");
        return 100;
});
```
### passing functions inside the setState() 🙃

```React 
onClick={() => {
      // here value in the props is the state
      setState((value) => {
      //you can use this method when you need to update the state and you need the previous value of state
           return value + 1;
      });
}} 
```
---
# useEffect()

Use effect hook has 2 parts first one is a function and second one is dependency array which is optional
```React
useEffect(()=>{},[])
```

```React
// we will get a console log every time any state changes.

// for example if you have 2 states in your component and any of 
// them changes then we will get the console log

// this is something we mostly dont want.
useEffect(() => {
   console.log('change');
})
```

Your first useEffect() call will always run when your component gets mounted first time in the DOM.

#### Dependency array 🤠
We can specify the states inside the dependency array of useEffect() so that it will only monitor the changes of those states which are mentioned in the dependency array😮‍💨.

```React
    const [state1, setState1] = useState(0);
    const [state2, setState2] = useState(0);
    useEffect(() => {
        console.log('state1 changed');
    }, [state1])
```

Remember: Do not update the state in which you used the useEffect() without a proper logic it will create an infinite loop 🥵

#### Cleanup function

useEffect always returns a cleanup function which you can use to remove unwanted behaviours thec leanup function does not only run when our component wants to unmount, it also runs right before the execution of the next scheduled effect [read in detail](https://blog.logrocket.com/understanding-react-useeffect-cleanup-function/)

```React
useEffect(() => {
        console.log(`state1 changed | ${state1}`);
        return () => {
            console.log('state1 unmounted | ', state1);
        }
    }, [state1])
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qr1uykz8gkua2auoanm3.png)

you can fetch data from an api like this 👇🏻

```React 
useEffect(() => {
        const url = "https://jsonplaceholder.typicode.com/todos/1";
        const fetchData = () => {
            fetch(url)
                .then(res => res.json())
                .then(data => {
                    setState(data.title)
                })
        }
        fetchData();
    }, []);
```

---
# useContext()

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gpbqb0k2tozs63peylp4.png)
 
The Context API provides data even to the deepest level of component in the react component tree without passing it in props

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

const StoreContext = createContext();

const component = () => {
    const data = useState({
        name: 'Ritesh',
        email: 'nyctonio.dev@gmail.com',
    })[0];

    const Child = () => {
        return <div>
            <StoreContext.Consumer>
                {value => <h1>name is {value.name}</h1>}
            </StoreContext.Consumer>
        </div>
    }

    return (
        <StoreContext.Provider value={data}>
            <Child />
        </StoreContext.Provider>
    )
}

export default component;
```

You can wrap your top level component in Your Context Provider and use it inside a function by Context Consumer.What useContext do is it replaces Context Consumer and we can get data by using useContext directly.

See this example 👇🏻.

```React
import { createContext, useContext } from "react";
import { useState } from "react";

const StoreContext = createContext();

const component = () => {
    const data = useState({
        name: 'Ritesh',
        email: 'nyctonio.dev@gmail.com',
    })[0];

    const Child = () => {
        const value = useContext(StoreContext);
        return <div>
            <h1>name is {value.name}</h1>
        </div>
    }

    return (
        <StoreContext.Provider value={data}>
            <Child />
        </StoreContext.Provider>
    )
}

export default component;
```
[read more](https://dmitripavlutin.com/react-context-and-usecontext/)

---
# useReducer()

useReducer is used for state management in React it is somewhat similar to reducer function in javascript.

// useReducer function accepts 2 params reducer function and initialState

useReducer(reducer,initialState)

// reducer functions accepts 2 params currentState and action for that and returns a new State

reducer(currentState,action)

### lets create a simple counter using useReducer

```React
import { useReducer } from 'react'

const initialState = 0;
const reducer = (state, action) => {
    switch (action) {
        case 'increment':
            return state + 1;
        case 'decrement':
            return state - 1;
        default:
            return state;
    }
}

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

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => dispatch('increment')}>+</button>
            <button onClick={() => dispatch('decrement')}>-</button>
        </div>
    )
}
```
we can make it more complex by making our state an object

```React
import { useReducer } from 'react'

const initialState = {
    firstCounter: 0,
    secondCounter: 0
};
const reducer = (state, action) => {
    switch (action.type) {
        case 'increment':
            return { ...state, firstCounter: state.firstCounter + action.value };
        case 'decrement':
            return { ...state, firstCounter: state.firstCounter - action.value };
        default:
            return { ...state };
    }
}

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

    return (
        <div>
            <p>Count: {count.firstCounter}</p>
            <button className='bg-gray-200 p-2' onClick={() => dispatch({ type: 'increment', value: 2 })}>
                increase by 2
            </button>
            <button className='bg-gray-200 p-2' onClick={() => dispatch({ type: 'decrement', value: 4 })}>
                decrease by 4
            </button>
        </div>
    )
}
```

Or We can use multiple useReducers 👇🏻

```React 
import { useReducer } from 'react'

const initialState = 0;
const reducer = (state, action) => {
    switch (action) {
        case 'increment':
            return state + 1;
        case 'decrement':
            return state - 1;
        default:
            return state;
    }
}

export default function main() {
    const [count, dispatch] = useReducer(reducer, initialState);
    const [count2, dispatch2] = useReducer(reducer, initialState);

    return (
        <div>
            <p>Count: {count}</p>
            <button className="bg-gray-100 p-2 m-2"
                onClick={() => dispatch('decrement')}>-</button>
            <button className="bg-gray-100 p-2 m-2"
                onClick={() => dispatch('increment')}>+</button>

            <p>Count2: {count2}</p>
            <button className="bg-gray-100 p-2 m-2"
                onClick={() => dispatch2('increment')}>+</button>
            <button className="bg-gray-100 p-2 m-2"
                onClick={() => dispatch2('decrement')}>-</button>
        </div>
    )
}
```
#### When to use useState and when useReducer ????

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks 😎. 

---
# useReducer() with useContext()

With the use of useContext and useReducer we can manage global states at any level of component tree try out this example 👇🏻

```React 

// main.jsx
import React from 'react'
import { useReducer } from 'react'
import ChildrenA from '../components/ChildrenA';

export const StateContext = React.createContext();
const initialState = 0;
const reducer = (state, action) => {
    switch (action) {
        case 'increment':
            return state + 1;
        case 'decrement':
            return state - 1;
        default:
            return state;
    }
}

export default function main() {
    const [count, dispatch] = useReducer(reducer, initialState);
    return (
        <div>
            <StateContext.Provider
                value={{ countState: count, countDispatch: dispatch }}>
                <ChildrenA />
            </StateContext.Provider>
        </div >
    )
}

// ChildrenA.jsx

import React from 'react'
import ChildrenB from './ChildrenB'
import { StateContext } from '../pages/main'
import { useContext } from 'react'

export default function ChildrenA() {
    const { countState, countDispatch } = useContext(StateContext)
    return (
        <div>
            In child A count state is {countState}
            <ChildrenB />
        </div>
    )
}

// ChildrenB.jsx

import React from 'react'
import { StateContext } from '../pages/main'
import { useContext } from 'react'

export default function ChildrenB() {
    const { countState, countDispatch } = useContext(StateContext)
    return (
        <div>
            <p>Count is {countState}</p>
            <button onClick={() => countDispatch('increment')}>+</button>
            <button onClick={() => countDispatch('decrement')}>-</button>
        </div>
    )
}

```
your both state will change simultaneously 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13g6t9oevfzng2qmhewi.png)
 
---
# useCallback()

lets see this code and try to understand the behaviour of functions in React

```React
import React from 'react'

export default function main() {

    function Sum() {
        return (a, b) => a + b;
    }
    const func1 = Sum();
    const func2 = Sum();
    console.log(func1 === func2);

    return (
        <div>main</div>
    )
}
```

If you will run this code you will get false in console.log

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10fzh37dnaf96r1w53s1.png)

Now with an example lets try to understand how we can use useCallback  

```React
// main.jsx
import React, { useState } from 'react'
import ChildrenA from '../components/ChildrenA';
import ChildrenB from '../components/ChildrenB';
import ChildrenC from '../components/ChildrenC';

const main = () => {
    const [state1, setState1] = useState(0);
    const [state2, setState2] = useState(0);

    const handleClickA = () => {
        setState1(state1 + 1);
    }

    const handleClickB = () => {
        setState2(state2 + 1);
    }

    return (
        <div className='flex flex-col justify-center items-center'>
            <ChildrenA value={state1} handleClick={handleClickA} />
            <ChildrenB value={state2} handleClick={handleClickB} />
            <ChildrenC />
        </div>
    )
}

// what react memo do is it re-render the component only when the props change
export default React.memo(main);

// ChildrenA.jsx
import React from 'react'

function ChildrenA({ value, handleClick }) {
    console.log('ChildrenA');
    return (
        <div>ChildrenA  {value}
            <button className='bg-gray-200 p-2 m-2' onClick={handleClick} >Click</button>
        </div>

    )
}

export default React.memo(ChildrenA);

// ChildrenB.jsx
import React from 'react'

function ChildrenB({ value, handleClick }) {
    console.log('ChildrenB');
    return (
        <div>ChildrenB {value}
            <button className='bg-gray-200 p-2 m-2' onClick={handleClick} >Click</button>
        </div>
    )
}

export default React.memo(ChildrenB);

// ChildrenC.jsx

import React from 'react'

function ChildrenC() {
    console.log('ChildrenC');
    return (
        <div>ChildrenC</div>
    )
}

export default React.memo(ChildrenC);

```
when you see console.log in your browser initially all three components renders but on clicking any click button only 2 components rerenders 
Note: here we used React.memo() thats why ChildrenC do not got rerendered because the props do not changed but why on changing ChildrenA ChildrenB also gets re render 

The reason is on rerender of main function the handleClick function do not remains the same as previous one I explained this above in the blog thats why React notices change in props so it rerenders both ChildrenA and ChildrenB.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6pa3w4z5du6l3jcqxyv.png)

To Solve this we will use useCallback 

useCallback returns a memoized callback. 

useCallback accepts a function and a dependency array same as useEffect

now lets change our code in main function and see the logs

```React
// main.jsx

import React, { useState, useCallback } from 'react'
import ChildrenA from '../components/ChildrenA';
import ChildrenB from '../components/ChildrenB';
import ChildrenC from '../components/ChildrenC';

const main = () => {
    const [state1, setState1] = useState(0);
    const [state2, setState2] = useState(0);


    const handleClickA = useCallback(() => {
        setState1(state1 + 1);
    }, [state1])

    const handleClickB = useCallback(() => {
        setState2(state2 + 1);
    }, [state2])

    return (
        <div className='flex flex-col justify-center items-center'>
            <ChildrenA value={state1} handleClick={handleClickA} />
            <ChildrenB value={state2} handleClick={handleClickB} />
            <ChildrenC />
        </div>
    )
}

// what react memo do is it re-render the component only when the props change
export default React.memo(main);
```
now you can see everything is fine 👇🏻.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y08fw53pwyhqmvydkptc.png)

---
# useMemo()

useCallback returns a memorized function similarly useMemo returns a memorized value for example we need to find the factorial and only recalculate when number changes not everytime when component re-renders so we will use useCallback

```React
import React, { useState, useMemo } from 'react'

function factorialOf(n) {
    console.log('factorialOf(n) called!');
    return n <= 0 ? 1 : n * factorialOf(n - 1);
}

const main = () => {
    const [number, setNumber] = useState(2)
    const factorial = useMemo(() => factorialOf(number), [number])
    const [count, setCount] = useState(0)

    return (
        <div className='flex flex-col justify-center items-center'>
            {factorial}
            <button className='bg-gray-200 p-2 m-2' onClick={() => setNumber(number + 1)}>+</button>
            {count} <button className='bg-gray-200 p-2 m-2' onClick={() => setCount(count + 1)}>+</button>
        </div>
    )
}

export default main;
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8tn95fxmouf71ru16jkv.png) 

---
# useRef()

lets console log useRef and see what it returns

console.log(useRef(100));
// this will return something like this 👉🏻 {current: 100}

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

when you compare an normal object with itself in useEffect after a rerender those are not the same, and that will trigger the useEffect on that object you can run this code 👇🏻 and try out.

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

const component = () => {
    const obj1 = { hi: 100 };
    const obj2 = useRef({ hi: 100 });
    console.log(obj1 === obj2.current);

    const [state, setState] = useState(() => {
        return 1;
    });

    useEffect(() => {
        console.log('obj1 changed | ', obj1);
    }, [obj1])

    useEffect(() => {
        console.log('obj2 changed | ', obj2.current);
    }, [obj2])


    return (
        <div onClick={() => {
            setState((value) => {
                return value + 1;
            });
        }} className="w-screen h-screen flex justify-center items-center text-4xl font-extralight">
            {state}
        </div>
    )
}

export default component;
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yshzgvt44155cjc9ghqq.png)

you can also use useState to work similar to useRef
const obj = useState({current:10})[0];

🥳🥳🥳🥳🎊🎊🎊🎊 hurrayyyyy!!!! 
you have covered all important hooks.

Connect me on Twitter :- [Twitter 🤝🏻](https://twitter.com/nyctonio)

Do check out my Github for amazing projects:- [Github 🤝🏻](https://github.com/nyctonio/)

Connect me on LinkedIn :- [Linkedin 🤝🏻](https://www.linkedin.com/in/nyctonio)

Read my another article :- [Authentication in nodejs with mongodb bcrypt and jwt web tokens](https://dev.to/nyctonio/authentication-in-node-js-with-mongodb-bcrypt-and-jwt-web-tokens-with-cookies-hl3)