
So starten Sie schnell mit VUE3.0: Einstieg und Einführung
React-Projekten gibt es viele Szenarien, in denen Ref benötigt wird. Verwenden Sie beispielsweise ref Attribut, um den DOM-Knoten und die ClassComponent-Objektinstanz abzurufen. Verwenden Sie useRef Hook React.createRef um das Problem zu lösen, dass setInterval nicht den neuesten Status abrufen kann Methode zum manuellen Erstellen eines Ref Objekts.
Obwohl Ref sehr einfach zu verwenden ist, ist es dennoch unvermeidlich , Ref in tatsächlichen Projekten ref auftreten. Nachdem Sie diesen Artikel gelesen haben, verfügen Sie möglicherweise über ein tieferes Verständnis von Ref .
Erstens ist ref die Abkürzung für reference , also eine Referenz. In der react -Type-Deklarationsdatei finden Sie mehrere Ref-bezogene Typen, die hier aufgelistet sind.
Schnittstelle RefObject<T> { readonly current: T |.
interface MutableRefObject<T> { current: T } Bei Verwendung von useRef Hook wird RefObject/MutableRefObejct eine Objektstruktur von { current: T } zurückgegeben. Der Unterschied besteht darin, dass die aktuelle Eigenschaft von RefObject schreibgeschützt ist , Typescript warnt ⚠️, wenn refObject.current geändert wird.
const ref = useRef<string>(null) ref.current = '' // Fehler
TS: Kann „current“ nicht zugewiesen werden, da es sich um eine schreibgeschützte Eigenschaft handelt.

Sehen Sie sich die Definition der useRef null Methode an. Wenn der eingehende generische Parameter T nicht null enthält, wird RefObject<T> MutableRefObject<T> .
function useRef<T>(initialValue: T): MutableRefObject<T>; function useRef<T>(initialValue: T | null): RefObject<T>;
Wenn Sie also möchten, dass die aktuelle Eigenschaft des erstellten Ref-Objekts geändert werden kann, müssen Sie | null hinzufügen.
const ref = useRef<string |. ref.current = '' // OK,
beim Aufruf der Methode React.createRef() wird auch ein RefObject zurückgegeben.
createRef-
Exportfunktion createRef(): RefObject {
const refObject = {
aktuell: null,
};
if (__DEV__) {
Object.seal(refObject);
}
refObject zurückgeben;
} RefObject/MutableRefObject wurde in Version 16.3 hinzugefügt. Wenn Sie frühere Versionen verwenden, müssen Sie Ref Callback verwenden.
Mit Ref Callback wird eine Rückruffunktion übergeben. Wenn React zurückruft, wird die entsprechende Instanz zurückgegeben und kann für den Aufruf selbst gespeichert werden. Der Typ dieser Rückruffunktion ist RefCallback .
type RefCallback<T> = (instance: T | null) => void;
Beispiel für die Verwendung von RefCallback :
import React from 'react'
Die Exportklasse CustomTextInput erweitert React.Component {
textInput: HTMLInputElement |. null = null;
saveInputRef = (element: HTMLInputElement | null) => {
this.textInput = element;
}
render() {
zurückkehren (
<input type="text" ref={this.saveInputRef} />
);
}
} In der Typdeklaration gibt es auch Ref/LegacyRef-Typen, mit denen allgemein auf den Ref-Typ verwiesen wird. LegacyRef ist eine kompatible Version. In der vorherigen alten Version konnte ref auch eine Zeichenfolge sein.
type Ref<T> = RefCallback<T> |. RefObject<T> |. type LegacyRef<T> = string |. Ref<T>;
Nur wenn Sie die mit Ref verbundenen Typen verstehen, können Sie sich beim Schreiben von Typescript wohler fühlen.
ÜbergabeWenn wir ref für eine JSX-Komponente verwenden, legen wir einen Ref für das ref -Attribut fest. Wir alle wissen, dass die Syntax von jsx von Tools wie Babel in die Form von createElement kompiliert wird.
//jsx
<App ref={ref} id="my-app" ></App>
// kompiliert zu
React.createElement(App, {
Ref: Ref,
ID: „meine-App“
}); Es scheint, dass sich ref nicht von anderen Requisiten unterscheidet, aber wenn Sie versuchen, props.ref innerhalb der Komponente zu drucken, ist es undefined . Und die dev gibt Eingabeaufforderungen.
Der Versuch, darauf zuzugreifen, führt dazu, dass
undefinedzurückgegeben wird. Wenn Sie auf denselben Wert innerhalb der untergeordneten Komponente zugreifen müssen, sollten Sie ihn als andere Requisite übergeben.
Was macht React mit ref? Wie Sie im ReactElement-Quellcode sehen können, ref auch für RESERVED_PROPS key , dass sie speziell verarbeitet und aus Requisiten extrahiert und an Element übergeben werden.
const RESERVED_PROPS = {
Schlüssel: wahr,
Ref: wahr,
__self: wahr,
__Quelle: wahr,
}; ref ist also “props“ , das speziell behandelt wird.
Vor Version 16.8.0 war die Funktionskomponente zustandslos und wurde nur basierend auf den eingehenden Requisiten gerendert. Mit Hook können Sie nicht nur einen internen Status haben, sondern auch Methoden für externe Aufrufe verfügbar machen (dafür sind forwardRef und useImperativeHandle erforderlich).
Wenn Sie ref direkt für eine Function Component verwenden, werden Sie von der Konsole in der Entwicklungsumgebung gewarnt, dass Sie sie mit forwardRef umschließen müssen.
functionInput () {
gib <input /> zurück
}
const ref = useRef()
<Input ref={ref} /> Funktionskomponenten können keine Referenzen erhalten. Versuche, auf diese Referenz zuzugreifen, schlagen fehl. Wollten Sie React.forwardRef() verwenden
forwardRef Sehen Sie sich den Quellcode ReactForwardRef.js an. Falten Sie den __DEV__ bezogenen Code. Es handelt sich lediglich um eine äußerst einfache Komponente höherer Ordnung. Empfangen Sie eine gerenderte Funktionskomponente, verpacken Sie sie, definieren Sie $$typeof als REACT_FORWARD_REF_TYPE und return sie zurück.

Verfolgen Sie den Code und suchen Sie „resolveLazyComponentTag“, wobei $$typeof in das entsprechende WorkTag geparst wird.

Der WorkTag, REACT_FORWARD_REF_TYPE entspricht, ist ForwardRef. Dann tritt ForwardRef in die Logik von updateForwardRef ein.
case ForwardRef: {
child = updateForwardRef(
null,
workInProgress,
Komponente,
gelöstProps,
renderLanes,
);
Kind zurückgeben;
} Diese Methode ruft die renderWithHooks-Methode auf und übergibt ref im fünften Parameter.
nextChildren = renderWithHooks( aktuell, workInProgress, machen, nextProps, ref, // hier renderLanes, );
Verfolgen Sie den Code weiter und geben Sie die renderWithHooks-Methode ein. Sie können sehen, dass ref als zweiter Parameter von Component übergeben wird. An diesem Punkt können wir verstehen, woher der zweite Parameter ref von FuncitonComponent kommt, der von forwardRef umschlossen wird (im Vergleich zum zweiten Parameter des ClassComponent-Konstruktors, der Context ist).

Da wir wissen, wie man Ref übergibt, stellt sich als nächstes die Frage, wie Ref zugewiesen wird.
Der(weisen Sie einen RefCallback zu und unterbrechen Sie den Code commitAttachRef). In dieser Methode wird beurteilt, ob der Ref des Fiber-Knotens function oder ein RefObject und die Instanz ist werden je nach Art verarbeitet. Wenn der Fiber-Knoten eine HostComponent ( tag = 5 ) ist, die ein DOM-Knoten ist, ist die Instanz der DOM-Knoten, und wenn der Fiber-Knoten eine ClassComponent ( tag = 1 ) ist, ist die Instanz die Objektinstanz.
Funktion commitAttachRef(finishedWork) {
var ref = doneWork.ref;
if (ref !== null) {
var InstanzToUse = doneWork.stateNode;
if (typeof ref === 'function') {
ref(instanceToUse);
} anders {
ref.current = exampleToUse;
}
}
} Das Obige ist die Zuweisungslogik von ref in HostComponent und ClassComponent. Für Komponenten vom Typ ForwardRef werden unterschiedliche Codes verwendet, aber das Verhalten ist im Grunde das gleiche. Sie können den imperativeHandleEffect hier sehen.
Als nächstes stöbern wir weiter im React-Quellcode, um zu sehen, wie useRef implementiert wird.
findet den useRef-Laufzeitcode ReactFiberHooks, indem sie den Code verfolgt

Hier gibt es zwei Methoden, mountRef und updateRef . Wie der Name schon sagt, entsprechen sie den Vorgängen auf ref wenn Fiber Knoten mount und update wird.
Funktion updateRef<T>(initialValue: T): {|current: T|} {
const Hook = updateWorkInProgressHook();
return Hook.memoizedState;
}
Funktion mountRef<T>(initialValue: T): {|current: T|} {
const Hook = mountWorkInProgressHook();
const ref = {current: initialValue};
Hook.memoizedState = ref;
return ref;
} Sie können sehen, dass useRef beim mount ein RefObject erstellt und es dem memoizedState des hook zuweist. Beim update wird es herausgenommen und direkt zurückgegeben.
Verschiedene Hooks: useState speichert state Inhalte, useEffect speichert effect , useRef speichert ref Objekte ...
mountWorkInProgressHook und updateWorkInProgressHook werden durch eine verknüpfte Liste von Hooks unterstützt. Wenn die verknüpfte Liste nicht geändert wird, können Sie dies tun Rufen Sie jedes Mal das gleiche memoizedState-Objekt ab, wenn Sie useRef rendern. So einfach ist das.
An diesem Punkt verstehen wir die Logik der Übergabe und Zuweisung ref in React sowie den Quellcode im Zusammenhang mit useRef . Verwenden Sie eine Anwendungsfrage, um die oben genannten Wissenspunkte zu konsolidieren: Innerhalb der Komponente muss innerRef HTMLInputElement verwendet werden. Gleichzeitig ermöglicht es der externen Komponente, auf den DOM zuzugreifen um es umzusetzen?
const Input = forwardRef((props, ref) => {
const innerRef = useRef<HTMLInputElement>(null)
zurückkehren (
<input {...props} ref={???} />
)
}) Überlegen Sie, wie ??? im obigen Code geschrieben werden soll.
============ Antworttrennlinie ==============
Wenn wir die interne Implementierung in Bezug auf Ref verstehen, ist es offensichtlich, dass wir hier einen RefCallback erstellen können kann mehrere verarbeiten. Weisen Sie einfach eine ref zu.
Exportfunktion combinRefs<T = any>(
refs: Array<MutableRefObject<T |. null> |
): React.RefCallback<T> {
Rückgabewert => {
refs.forEach(ref => {
if (typeof ref === 'function') {
ref(Wert);
} else if (ref !== null) {
ref.current = Wert;
}
});
};
}
const Input = forwardRef((props, ref) => {
const innerRef = useRef<HTMLInputElement>(null)
zurückkehren (
<input {...props} ref={combineRefs(ref, innerRef)} />
)
})