Auteur : JD Retail Zheng Bingyi
avant-propos
React Hooks
est React
une nouvelle fonctionnalité introduite dans la version 16.8 qui permet state
d'utiliser d'autres fonctionnalités de React dans des composants de fonction sans avoir à utiliser des composants de classe. Hooks
sont un concept très important car ils offrent une React
expérience de développement plus simple et plus compréhensible.
React Hooks
Le code source principal comprend principalement deux parties : React
le gestionnaire interne Hook
et une série de Hook
fonctions prédéfinies .
Tout d'abord, regardons le gestionnaire React
à l'intérieur . Hook
Ce gestionnaire est React
un mécanisme interne important chargé de tout gérer dans le composant Hook
et de s'assurer qu'ils sont appelés dans le bon ordre lors du rendu du composant.
Gestionnaire de hook interne
Exemple:
const Hook = {
queue: [],
current: null,
};
function useState(initialState) {
const state = Hook.current[Hook.queue.length];
if (!state) {
Hook.queue.push({
state: typeof initialState === 'function' ? initialState() : initialState,
setState(value) {
this.state = value;
render();
},
});
}
return [state.state, state.setState.bind(state)];
}
function useHook(callback) {
Hook.current = {
__proto__: Hook.current,
};
try {
callback();
} finally {
Hook.current = Hook.current.__proto__;
}
}
function render() {
useHook(() => {
const [count, setCount] = useState(0);
console.log('count:', count);
setTimeout(() => {
setCount(count + 1);
}, 1000);
});
}
render();
Dans cet exemple, Hook
l'objet a deux propriétés importantes : queue
et current
. queue
Stockez toutes Hook
les fonctions d'état et de mise à jour dans le composant, et current
stockez une liste liée des composants en cours de rendu Hook
. useState
et useHook
les fonctions sont responsables de la création d'un nouvel Hook
état et de son utilisation dans le composant , respectivement Hook
.
Fonction crochet préréglée
crochet useState
Voici useState Hook
un exemple d'implémentation de :
function useState(initialState) {
const hook = updateWorkInProgressHook();
if (!hook.memoizedState) {
hook.memoizedState = [
typeof initialState === 'function' ? initialState() : initialState,
action => {
hook.queue.pending = true;
hook.queue.dispatch = action;
scheduleWork();
},
];
}
return hook.memoizedState;
}
Le code ci-dessus est implémenté useState Hook
et sa fonction principale est de renvoyer un state
tableau avec la fonction de mise à jour, et la valeur initiale de l'état est initialState
.
Dans cette implémentation, updateWorkInProgressHook()
la fonction est utilisée pour obtenir l'objet fibre du composant de fonction en cours d'exécution et déterminer s'il en existe un correspondant hook
. Il est implémenté comme suit :
function updateWorkInProgressHook() {
const fiber = getWorkInProgressFiber();
let hook = fiber.memoizedState;
if (hook) {
fiber.memoizedState = hook.next;
hook.next = null;
} else {
hook = {
memoizedState: null,
queue: {
pending: null,
dispatch: null,
last: null,
},
next: null,
};
}
workInProgressHook = hook;
return hook;
}
getWorkInProgressFiber()
La fonction est utilisée pour obtenir l'objet du composant de fonction en cours d'exécution fiber
et workInProgressHook
est utilisée pour stocker l' hook
objet en cours d'exécution. Dans un composant de fonction, chaque useState
appel crée un nouvel objet hook et l'ajoute à la liste liée fiber
d'objets hooks
. Cette hooks
liste chaînée est maintenue via les propriétés fiber
de l'objet .memoizedState
Nous devons également noter que dans useState Hook
l'implémentation de , chaque hook
objet contient un queue
objet pour stocker l'état à mettre à jour et la fonction de mise à jour. scheduleWork()
Les fonctions sont utilisées pour notifier React
au planificateur qu'une tâche doit être exécutée.
Dans React
le code source de , useState
la fonction est en fait une useStateImpl
fonction interne appelée .
Voici useStateImpl
le code source :
function useStateImpl<S>(initialState: (() => S) | S): [S, Dispatch<SetStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
On peut voir que useStateImpl
la fonction de la fonction est d'obtenir le courant dispatcher
et d'appeler sa useState
méthode, et de retourner un tableau, le premier élément est la valeur de l'état et le deuxième élément est une dispatch
fonction pour mettre à jour l'état. La fonction ici resolveDispatcher
est utilisée pour obtenir la fonction actuelle dispatcher
, et son implémentation est la suivante :
function resolveDispatcher(): Dispatcher {
const dispatcher = currentlyRenderingFiber?.dispatcher;
if (dispatcher === undefined) {
throw new Error('Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)');
}
return dispatcher;
}
resolveDispatcher
fiber
La fonction essaie d'abord d'obtenir les propriétés de l'objet en cours de rendu dispatcher
, et si elle ne peut pas l'obtenir, elle dit
Si le composant n'est pas actuellement dans le processus de rendu, une erreur sera générée.
Enfin, regardons comment la méthode est implémentée useState
dans une implémentation spécifique . dispatcher
nous useReducer
prenons
dispatcher
Par exemple, il est implémenté comme suit :
export function useReducer<S, A>(
reducer: (prevState: S, action: A) => S,
initialState: S,
initialAction?: A,
): [S, Dispatch<A>] {
const [dispatch, currentState] = updateReducer<S, A>(
reducer,
// $FlowFixMe: Flow doesn't like mixed types
[initialState, initialAction],
// $FlowFixMe: Flow doesn't like mixed types
reducer === basicStateReducer ? basicStateReducer : updateStateReducer,
);
return [currentState, dispatch];
}
Comme vous pouvez le voir, useReducer
la méthode appelle en fait une updateReducer
fonction appelée , qui renvoie un dispatch
tableau contenant l'état et la fonction actuels. updateReducer
La mise en œuvre de est plus compliquée et implique beaucoup de détails, je ne vais donc pas la présenter ici.
useEffect Hook
useEffect
Est une fonction React
couramment utilisée dans les composants pour effectuer des opérations d'effet secondaire dans les composants, telles que l'accès à des données distantes, l'ajout/la suppression d'écouteurs d'événements, des opérations manuelles , etc. La fonction principale de est d'exécuter la fonction de rappel de manière asynchrone après la fin du processus de rendu du composant, et sa mise en œuvre implique le mécanisme de rendu asynchrone dans React.Hook
DOM
useEffect
Voici un exemple d'implémentation de useEffect Hook :
function useEffect(callback, dependencies) {
// 通过调用 useLayoutEffect 或者 useEffect 方法来获取当前的渲染批次
const batch = useContext(BatchContext);
// 根据当前的渲染批次判断是否需要执行回调函数
if (shouldFireEffect(batch, dependencies)) {
callback();
}
// 在组件被卸载时清除当前 effect 的状态信息
return () => clearEffect(batch);
}
Dans cet exemple, useEffect
deux paramètres sont reçus : une fonction de rappel et un tableau de dépendances. Lorsqu'une valeur du tableau des dépendances change,
React
useEffect
La fonction callback transmise sera ré-exécutée au prochain rendu .
useEffect
L'implémentation de la fonction dépend principalement du React
mécanisme de rendu asynchrone dans . Lorsqu'un composant doit être rendu à nouveau, React
toutes state
les opérations de mise à jour seront ajoutées à une file d'attente, et ces opérations de mise à jour seront exécutées de manière asynchrone après la fin du lot de rendu en cours, évitant ainsi plusieurs opérations de mise à jour consécutives dans le même lot de rendu.
Dans useEffect
la fonction, nous useContext(BatchContext)
obtenons le lot de rendu actuel en appelant la méthode et shouldFireEffect
jugeons si la fonction de rappel doit être exécutée conformément à la méthode. Une fois la fonction de rappel exécutée, nous devons utiliser clearEffect
des méthodes pour effacer les effect
informations d'état actuelles afin d'éviter d'affecter les lots de rendu suivants.
Résumer
En général, React Hooks
le principe de mise en œuvre du système n'est pas compliqué, il dépend principalement de React
la structure de données interne fiber
et du système d'ordonnancement, à travers ces mécanismes pour réaliser la gestion et la mise à jour de l'état des composants. Hooks
Cela nous permet d'utiliser l'état et d'autres fonctionnalités dans les composants de fonction React
, rendant les composants de fonction comparables aux composants de classe.
En plus de useState
, useEffect
etc . hook
, React
il en existe useContext
d' autres couramment utilisés Hook
. Leurs principes d'implémentation sont fondamentalement similaires et ils utilisent tous fiber
l'architecture pour implémenter des fonctions telles que la gestion d'état et les crochets de cycle de vie.
Ce qui précède sont hook
des exemples d'implémentation simples, ce ne sont pas React
les codes réels utilisés dans , mais ils peuvent nous aider à mieux comprendre hook
l'implémentation de base.