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
undefined
zurü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)} /> ) })