React Hooks allow us to use React features without writing a class
- state
useState
,useReducer
- component lifecycle
useEffect
A lot of questions surrounding react hooks
- why can't we call hooks inside loops or conditions? (why do hooks rely on call order?)
const ReactX = (() => {
let hooks = [];
let index = 0;
const useState = (initialValue) => {
const localIndex = index;
index++;
if (hooks[localIndex] === undefined) {
hooks[localIndex] = initialValue;
}
const setterFunction = (newValue) => (hooks[localIndex] = newValue);
return [hooks[localIndex], setterFunction];
};
const resetIndex = () => {
index = 0;
};
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) {
hasChanged = true;
}
});
}
if (hasChanged) {
callback();
}
hooks[index] = dependencyArray;
index ++;
};
return {
useState,
useEffect,
resetIndex
};
})();
const { useState, useEffect, resetIndex } = ReactX;
const Component = () => {
const [counterValue, setCounterValue] = useState(1);
console.log(counterValue);
useEffect(() => {
console.log('useEffect');
}, []);
if (counterValue !== 2) {
setCounterValue(2);
}
};
Component();
resetIndex();
Component();
- Why isn't X A HOOK?
- useProvider()
- useCatch()
- useBailout()
Composition = hooks don't conflict with each other
Debugging = bugs should be easy to find
const Button = ({ color }) => {
// it will bail out re-render unless callback returns true
useBailout(previousColor => previousColor !== color, color);
return (<button className={`${color}-button`}>Button</button>)
}
-
useMemo()
does similar work touseBailout()
- it doesn't explicitly bail out of re-rendering
How can useState() be a part of rendering?
- rendering is handled by React DOM, but we aren't importing useState() from React DOM
- when
useState()
gets called, the call gets forwarded todispatcher
// inside React
const React = {
// ...
__currentDispatcher: null,
useState(initialState) {
return React.__currentDispatcher.useState(initialState);
}
};
// inside React DOM
const previousDispatcher = React.__currentDispatcher;
React.__currentDispatcher = ReactDOMDispatcher;
let result;
try {
result = Component(props);
} finally {
React.__currentDispatcher = previousDispatcher;
}
网友评论