React hooks allow us to use React features without writing a class
- state (useState, useReducer)
- component lifecycle (useEffect)
- much more(useRef, useContext, etc.)
Questions surrounding React Hooks
- Why can't we call hooks inside loops or conditions?
- Why isn't there a hook for this?
- Why isn't there a hook for that?
Why can't we call hooks inside Loops Or Conditions?
Why do hooks reply on call order?
1. Hooks are all about Arrays
Example for hook
- eg01
const ReactX = (() => {
const useState = (initialValue) => {
let state = initialValue;
const setterFunction = (newValue) => {
console.log('newValue: ', newValue)
state = newValue;
}
return [
state,
setterFunction
]
}
return {
useState,
};
})();
const { useState } = ReactX;
const Component = () => {
const [counterValue, setCounterValue] = useState(1);
console.log(counterValue);
if (counterValue !== 2) {
setCounterValue(2);
}
}
Component(); // 1
Component(); // 1
- eg02
const ReactX = (() => {
let state;
const useState = (initialValue) => {
if (state === undefined) {
state = initialValue;
}
const setterFunction = (newValue) => {
state = newValue;
}
return [
state,
setterFunction
]
}
return {
useState,
};
})();
const { useState } = ReactX;
const Component = () => {
const [counterValue, setCounterValue] = useState(1);
console.log(counterValue);
if (counterValue !== 2) {
setCounterValue(2);
}
}
Component(); // 1
Component(); // 2
- eg03
const ReactX = (() => {
let state = [];
let index = 0;
const useState = (initialValue) => {
const localIndex = index;
index++;
if(state[localIndex] === undefined) {
state[localIndex] = initialValue;
}
const setterFunction = (newValue) => {
console.log('newValue: ', newValue)
state[localIndex] = newValue;
}
return [
state[localIndex],
setterFunction
]
}
const resetIndex = () => {
index = 0;
}
return {
useState,
resetIndex,
};
})();
const { useState, resetIndex } = ReactX;
const Component = () => {
const [counterValue, setCounterValue] = useState(1);
console.log(counterValue);
if (counterValue !== 2) {
setCounterValue(2);
}
}
Component(); // 1
resetIndex();
Component(); // 2
So why can't we call hoos inside loops or conditions?
the state is just an array and useState access this array using indexes
if we called useState inside loops or conditions, those indexes may be different on every render
and this would cause each of the hooks to use the wrong state, which would result into application-breaking bugs.
- eg03
const ReactX = (() => {
let hooks = [];
let index = 0;
const useState = (initialValue) => {
const localIndex = index;
index++;
if(hooks[localIndex] === undefined) {
hooks[localIndex] = initialValue;
}
const setterFunction = (newValue) => {
console.log('newValue: ', newValue)
hooks[localIndex] = newValue;
}
return [
hooks[localIndex],
setterFunction
]
}
const useEffect = (callback, dependencyArray) => {
let hasChanged = true;
const oldDependencies = hooks[index];
if(oldDependencies) {
hasChanged = false
dependencyArray.forEach((dependency, index) => {
const oldDependency = oldDependencies[index];
const areTheSame = Object.is(dependency, oldDependency);
if(!areTheSame) {
hasChange = true;
}
})
}
if(hasChanged) {
callback();
}
hooks[index] = dependencyArray;
index++;
}
const resetIndex = () => {
index = 0;
}
return {
useState,
useEffect,
resetIndex,
};
})();
const { useState, useEffect, resetIndex }= ReactX;
const Component = () => {
const [counterValue, setCounterValue] = useState(1);
const [name, setName] = useState("Thomas");
console.log(counterValue);
console.log(name)
useEffect(() => {
console.log('useEffect for name')
}, [name])
if (counterValue !== 2) {
setCounterValue(2);
}
if(name !== "Jack" && counterValue === 2) {
setName("Jack")
}
}
Component();
resetIndex();
Component();
// ============ ouput ============
1
'Thomas'
'useEffect for name'
'newValue: ' 2
2
'Thomas'
'newValue: ' 'Jack'
2 Rules
- Composition = hooks don't conflit with each other.
- Debugging = bugs should be easy to find
How can useState() be part of rendering ?
- rendering is handled by React DOM but we aren't import useState() from React DOM
- when useState() get called, the call gets forwarded to dispatcher