Autor: JD Einzelhandel Zheng Bingyi
Vorwort
React Hooks
ist React
eine neue Funktion, die in 16.8 eingeführt wurde und die es ermöglicht, state
und andere React-Funktionen in Funktionskomponenten zu verwenden, ohne Klassenkomponenten verwenden zu müssen. Hooks
sind ein sehr wichtiges Konzept, da sie eine einfachere und verständlichere React
Entwicklungserfahrung bieten.
React Hooks
Der Kernquellcode besteht hauptsächlich aus zwei Teilen: React
dem internen Hook
Manager und einer Reihe voreingestellter Hook
Funktionen .
Sehen wir uns zunächst den Manager React
im Inneren an . Hook
Dieser Manager ist React
ein wichtiger interner Mechanismus, der dafür verantwortlich ist, alles in der Komponente zu verwalten Hook
und sicherzustellen, dass sie während des Renderns der Komponente in der richtigen Reihenfolge aufgerufen werden.
Interner Hook-Manager
Beispiel:
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();
In diesem Beispiel Hook
hat das Objekt zwei wichtige Eigenschaften: queue
und current
. queue
Speichern Sie alle Hook
Zustands- und Aktualisierungsfunktionen in der Komponente und current
speichern Sie eine verknüpfte Liste von Komponenten, die derzeit gerendert werden Hook
. useState
und useHook
Funktionen sind dafür verantwortlich, einen neuen Hook
Status zu erstellen und ihn in der Komponente zu verwenden Hook
.
Voreingestellte Hook-Funktion
useState-Hook
Hier ist useState Hook
eine Beispielimplementierung von:
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;
}
Der obige Code ist implementiert useState Hook
und seine Hauptfunktion besteht darin, ein state
Array mit der Aktualisierungsfunktion zurückzugeben, und der Anfangswert des Zustands ist initialState
.
In dieser Implementierung updateWorkInProgressHook()
wird die Funktion verwendet, um das Faserobjekt der aktuell ausgeführten Funktionskomponente zu erhalten und zu bestimmen, ob es ein entsprechendes gibt hook
. Es wird wie folgt implementiert:
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()
Die Funktion wird verwendet, um das Objekt der aktuell ausgeführten Funktionskomponente 10 zu erhalten fiber
, workInProgressHook
und wird verwendet, um das aktuell ausgeführte hook
Objekt zu speichern. In einer Funktionskomponente useState
erstellt jeder Aufruf ein neues Hook-Objekt und fügt es der verknüpften Liste fiber
von Objekten hinzu hooks
. Diese hooks
verknüpfte Liste wird über die Eigenschaften fiber
des Objekts verwaltet.memoizedState
Wir müssen auch beachten, dass in useState Hook
der Implementierung von jedes hook
Objekt ein queue
Objekt enthält, um den zu aktualisierenden Zustand und die Aktualisierungsfunktion zu speichern. scheduleWork()
Funktionen werden verwendet, um React
den Scheduler zu benachrichtigen, dass eine Aufgabe ausgeführt werden muss.
Im React
Quellcode von useState
ist die Funktion eigentlich eine useStateImpl
interne Funktion namens .
Hier ist useStateImpl
der Quellcode:
function useStateImpl<S>(initialState: (() => S) | S): [S, Dispatch<SetStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
Es ist ersichtlich, dass useStateImpl
die Funktion der Funktion darin besteht, den Strom zu erhalten dispatcher
und seine useState
Methode aufzurufen und ein Array zurückzugeben, das erste Element ist der Wert des Zustands und das zweite Element ist eine dispatch
Funktion zum Aktualisieren des Zustands. Die Funktion hier resolveDispatcher
wird verwendet, um die aktuelle zu erhalten dispatcher
, und ihre Implementierung ist wie folgt:
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
Die Funktion versucht zuerst, die Eigenschaften des Objekts abzurufen , das gerade gerendert wird dispatcher
, und wenn sie es nicht bekommen kann, sagt sie
Wenn sich die Komponente derzeit nicht im Rendering-Prozess befindet, wird ein Fehler ausgegeben.
Lassen Sie uns abschließend einen Blick darauf werfen, wie die Methode useState
in einer bestimmten Implementierung implementiert wird. dispatcher
wir useReducer
nehmen
dispatcher
Es wird beispielsweise wie folgt implementiert:
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];
}
Wie Sie sehen können, useReducer
ruft die Methode tatsächlich eine updateReducer
Funktion namens auf, die ein dispatch
Array zurückgibt, das den aktuellen Zustand und die aktuelle Funktion enthält. updateReducer
Die Implementierung von ist komplizierter und erfordert viele Details, daher werde ich sie hier nicht vorstellen.
useEffect-Hook
useEffect
Ist eine Funktion, React
die häufig in Komponenten verwendet wird , um Nebeneffektoperationen in Komponenten auszuführen, wie z. B. den Zugriff auf Remotedaten, das Hinzufügen/Entfernen von Ereignis-Listenern, manuelle Operationen usw. Die Kernfunktion von besteht darin, die Callback-Funktion asynchron auszuführen, nachdem der Rendering-Prozess der Komponente beendet ist, und ihre Implementierung umfasst den asynchronen Rendering-Mechanismus in React.Hook
DOM
useEffect
Das Folgende ist eine Beispielimplementierung von useEffect Hook:
function useEffect(callback, dependencies) {
// 通过调用 useLayoutEffect 或者 useEffect 方法来获取当前的渲染批次
const batch = useContext(BatchContext);
// 根据当前的渲染批次判断是否需要执行回调函数
if (shouldFireEffect(batch, dependencies)) {
callback();
}
// 在组件被卸载时清除当前 effect 的状态信息
return () => clearEffect(batch);
}
In diesem Beispiel useEffect
werden zwei Parameter empfangen: eine Callback-Funktion und ein Array von Abhängigkeiten. Wenn sich ein Wert im Abhängigkeits-Array ändert,
React
useEffect
Die übergebene Callback-Funktion wird beim nächsten Rendern erneut ausgeführt .
useEffect
Die Implementierung der Funktion hängt hauptsächlich vom React
asynchronen Rendering-Mechanismus in ab. Wenn eine Komponente erneut gerendert werden muss, werden React
alle state
Aktualisierungsvorgänge einer Warteschlange hinzugefügt, und diese Aktualisierungsvorgänge werden asynchron nach dem Ende des aktuellen Rendering-Stapels ausgeführt, wodurch mehrere aufeinanderfolgende Aktualisierungsvorgänge im selben Rendering-Stapel vermieden werden.
In useEffect
der Funktion useContext(BatchContext)
holen wir uns durch Aufruf der Methode den aktuellen Rendering-Batch und shouldFireEffect
beurteilen, ob die Callback-Funktion entsprechend der Methode ausgeführt werden muss. Nachdem die Callback-Funktion ausgeführt wurde, müssen wir clearEffect
Methoden verwenden, um die aktuellen effect
Statusinformationen zu löschen, um zu vermeiden, dass nachfolgende Rendering-Batches beeinträchtigt werden.
Zusammenfassen
Im Allgemeinen React Hooks
ist das Implementierungsprinzip des Systems nicht kompliziert, es hängt hauptsächlich von React
der internen fiber
Datenstruktur und dem Planungssystem ab, um durch diese Mechanismen die Verwaltung und Aktualisierung des Komponentenzustands zu realisieren. Hooks
Es erlaubt uns, Zustands- und andere Merkmale in Funktionskomponenten zu verwenden React
, wodurch Funktionskomponenten mit Klassenkomponenten vergleichbar werden.
Neben useState
, useEffect
etc. gibt es hook
noch andere häufig verwendete . Ihre Implementierungsprinzipien sind im Wesentlichen ähnlich, und sie alle verwenden die Architektur, um Funktionen wie Zustandsverwaltung und Lifecycle-Hooks zu implementieren.React
useContext
Hook
fiber
Das Obige sind hook
einfache Implementierungsbeispiele, sie sind nicht React
die eigentlichen Codes, die in verwendet werden, aber sie können uns helfen, hook
die Kernimplementierung besser zu verstehen.