How React Hooks Work in simple words?
Tags: javascript, react, reacthooks, beginners
Published: 2020-11-13 07:49:09

##Let's start with what is a Hook?
A Hook is a react function that lets you use state and react features from a function based component. Hooks let you use the functions instead of switching between HOCs, Classes, and functions. As Hooks are regular Javascript functions, thus you can use the built-in Hooks and create your own custom one. So the solution to your problem will be a "one-liner" now.

Before we know how React hooks work, let us define what closure is.

>_“Closure is when a function is able to remember and access its lexical scope even when that function is executing outside its lexical scope.”_

In the upcoming examples there will be Closures, so that made me define it.


##How does the useState work?

To illustrate how useState works, let us consider an example.

```javascript
const OurReact = (function(){
	let val; // ‘val’ stores the value in the module scope 
		return {
		    render(Component) {
			   const Comp = Component();
			   Comp.render();
			   return Comp;
            },
		    useState(initialVal) {
			   val = val || initialVal;// Assigns a new value every run 
			   function setState(newVal) {
				   val = newVal;
               }
               return [val, setState];
            },
        };	
})();
```

Here we have used the [Module Pattern](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript) in the above example to create our own small React clone. So if you want to access the useState then you need to access it as OurReact.useState(...). Like in React, to keep track of the Component State, we are making use of the ‘val’ variable (To keep it simple, it tracks only one component.). As you can see, the useState is inside a closure. Now let us use the above code.


```javascript
function Character () {
	const [characteName, setCharacterName] = OurReact.useState(‘Mario’); // default value to ‘Mario’
	return{
		changeName: (charName) => setCharacterName(charName),
		render: () => console.log(‘Rendered character:’, characteName),
    }
}
let App;
App = OurReact.render(Character);  // Rendered character: Mario
App.changeName(‘Luigi’);
App = OurReact.render(Character); // Rendered character: Luigi
```
So this was the simple code to Illustrate useState hook.

##Now how does useEffect works?

Whenever you want to do something as a side effect after each render(i.e. Make an API Call or Check component has the data or not), you can pass such effects to the useEffect. If you are familiar with Class-based components, then useEffect serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes, but unified into a single API.

```
function Example() {
	const [characterName, setCharacterName] = useState(‘Mario’);
	// Similar to componentDidMount and componentDidUpdate:
	useEffect(()=>{
	   document.title = `Character name ${characterName}`;
    });
    return(
	   <div>
		  <p>Character : {characterName}</p>
		  <input type=’text’ value={characterName} onChange={e => setCharacterName(e.target.value)} />
       </div>
    );
};

```

Let us replicate the useEffect hook by extending our tiny react clone that we created before.

```javascript
const OurReact = (function(){
	let val, deps; // A new variable ‘deps’ to hold our dependencies
	return {
		render(Component) {
			const Comp = Component();
			Comp.render();
			Return Comp;
        },
        useEffect(callBack, dependencyArr){
	       const hasNoDependency = !dependencyArr,
                 hasDependencyChanged = deps ? !dependencyArr.every((el, i) => el === deps[i]) : true;
           if (hasNoDependency  || hasDependencyChanged ) {
               callback();
               deps = dependencyArr;
           }
        },
		useState(initialVal) {
	       val = val || initialVal;
	       function setState(newVal) {
	          val = newVal;
           };
           return [val, setState];
        },
    };	
})();

```
###Usage:
```javascript
function Character () {
	const [characteName, setCharacterName] = OurReact.useState(‘Mario’);
	OurReact.useEffect(() => {
		console.log(‘effect called ’, characterName);
    }, [characteName])
	return{
		changeName: (charName) => setCharacterName(charName),
		noopFunction: () => setCharacterName(characteName),  // Similar to Jquery.noop that does nothing.
		render: () => console.log(‘Rendered character:’, characteName),
    }
}

let App;
App = OurReact.render(Character);
//   effect called Mario
// Rendered character: Mario

App.changeName(‘Luigi’);
App = OurReact.render(Character); 
// effect called Luigi
// Rendered character: Luigi

App.noopFunction()
App = OurReact.render(Character); 
// No effects
// Rendered character: Luigi

App.changeName(‘Yoshi’);
App = OurReact.render(Character); 
// effect called Yoshi
// Rendered character: Yoshi

```
The useEffect runs whenever there is a change in the dependencies, thus we have introduced a new variable in the above example as ‘deps’. So that was the simple explanation of the useEffect Hook.
 
We know that Hook implementation has thousands of lines of code in it. But hopefully, you got an idea of how things work inside.


##Rules to follow while using the Hooks.
* **Hooks should always be called at the Top Level.**

By following this rule, you are making sure that Hooks are always called in the same order as they were declared each time your component renders. (*Remember that don't ever call the hooks inside the functions that are nested and also inside the loops.*)

**Explanation:**
```javascript
functions character() {
    const [characterName, setCharacterName] = useState(‘Mario’);
    useEffect(function storeTheCharacter(){
	    localStorage.setItem(‘formData’, characterName);
    });
    const [characterAbility, setCharacterAbility] = useState(‘Fire flower’); 
    useEffect(function displayDetails(){
    document.getElementById(‘characterView’).innerHTML(`Character: ${characterName}, Ability: ${ characterAbility}`)
    });
}
```

We might have a question that, how does React know which state fits with which useState? The answer is just what we discussed, we always need to call the hooks in the same order as they were declared. And if we call the hooks inside a loop or the order of the hook changes, React will get confused about how to maintain the state for our component. 

```javascript
// 1st Render
useState(‘Mario);  // Initialize the ‘characterName’ state variable to ‘Mario’
useEffect(storeTheCharacter);  // Adding an effect to store the ‘characterName’ to the localStorage
useState(‘Fire Flower’);  // Initialize the ‘characterAbility’ state variable with 'Active'
useEffect(displayDetails);  // Adding an effect to update the displaying data

// 2nd render
useState(‘Mario);  // Read the characterName state variable (argument is ignored)
useEffect(storeTheCharacter);  // Replace the effect for persisting the form
useState(‘Fire Flower’);  // Read the characterAbilities state variable (argument is ignored)
useEffect(displayDetails);  // Replace the effect for updating the displaying data

```

Since the order of the hooks is maintained, React will be able to Maintain our component’s state.
 
What if we call a hook with a condition?
```javascript
if( characterName !== ‘’ ){
	useEffect(function storeTheCharacter () {
     		localStorage.setItem('formData', characterName);
  	});
}

```
Here we are breaking the first rule of the Hook in a condition. Let’s see what happens when the condition is ‘false’, the hook is skipped during the rendering, and the order of the Hook call becomes different.
i.e.
```javascript
useState(Mario) // 1. Read the name state variable (argument is ignored)
// useEffect(storeTheCharacter)  // This Hook was skipped!
useState(‘Fire Flower’)  // 2 (but was 3). Fail to read the surname state variable
useEffect(updateTitle)  // 3 (but was 4). Fail to replace the effect
```
React fails to recognize what to return for the second useState Hook call. React expected that the second Hook call in this component corresponds to the 'storeTheCharacter' effect, just like during the previous render, but it doesn’t anymore. From that point, every next Hook call after the one we skipped would also shift by one, leading to bugs. So that's the reason why hooks are always called on the top level of our component.

* **Hooks should always be called from React Functions.**

Don't call Hooks from regular JavaScript functions. Instead, you can
 
1. Call Hooks from React Function components. 
2. Call Hooks from custom Hooks.

**Explanation:**
```javascript
import { useState } from ‘react’;
const lives = 3;
const isGameOver = (noOfDeaths) =>{
    const livesLeft = lives – noOfDeaths;
    const [characterName, setCharacterName] = useState(‘Mario’);
	    if (livesLeft === 0) { return ‘Game Over’’; } else { return ‘Continue’; }
}

```

This doesn't make any sense to call the useState inside a regular function.
 
So those were the rules that you need to follow while using the hooks.

---

Hope you guys got a clear idea about how things are working inside the React Hooks API and what rules we need to follow while using the hooks. Nowadays hooks are a crucial part of most of the react components. If you guys got any questions related to this post, feel free to shoot them in the comment box.Thank you