Was ist der richtige Proptyp für einen Ref in React?

85

Ich speichere eine Referenz in meinem Redux-Speicher und verwende mapStateToProps, um die Referenz für Komponenten verfügbar zu machen, die Zugriff darauf benötigen.

Die gespeicherte Referenz sieht folgendermaßen aus:

ref={node => this.myRefToBePutInReduxGlobalStore = node}

Was ist der richtige PropType für diese Referenz?

danday74
quelle
8
Da Refs nicht serialisierbar sind, ist es keine gute Idee, sie in den Redux-Store zu stellen. Der an refprop übergebene Wert ist jedoch eine Funktion, bei der das erste Argument auf das DOM-Element oder null verweist. Es ist eine Funktion .
Rishat
5
Sie können nicht propType für verwenden refs, aber Sie können es für verwenden props. Da Sie es zu redux Speicher sind vorbei , dann wird es als dargestellt propwie this.props.myRefToBePutInReduxGlobalStore. myRefToBePutInReduxGlobalStoresollte der Knotentyp sein, PropTypes.nodesollte also für Sie funktionieren
The Reason
Ich denke, es sollte sein, PropType.objectweil ref im Grunde eine Klasseninstanz ist, die ein Objekt ist. Daher , wenn Sie ref - Element als Requisiten passieren würde es sein Objekt Typ
Hriday Modi

Antworten:

96

TL; DR

Wenn Sie eine Referenz eingeben möchten, die nur native DOM-Elemente wie a divoder an erwartet input, lautet die richtige Definition wie folgt:

refProp: PropTypes.oneOfType([
    // Either a function
    PropTypes.func, 
    // Or the instance of a DOM native element (see the note about SSR)
    PropTypes.shape({ current: PropTypes.instanceOf(Element) })
])

Beantworten Sie das im ursprünglichen Beitrag beschriebene Problem

Im Beispiel der OP-Frage muss nicht der Ref-Prop-Typ deklariert werden, sondern das Material, auf das der Ref zeigt, und das von Redux mit übergeben wird mapStateToProps. Der Prop-Typ für ein DOM-Element wäre: myRefToBePutInReduxGlobalStore: PropTypes.instanceOf(Element)(wenn es sich um ein DOM-Element handelt). Obwohl ich würde:

  1. Benennen Sie es um in myElementToBePutInReduxGlobalStore(ein Element ist kein ref)
  2. Vermeiden Sie das Speichern nicht serialisierbarer Daten im Redux-Speicher
  3. Vermeiden Sie es, Elemente in Requisiten zu übergeben, wie von React-Ingenieur Seb Markbage erläutert

Lange Antwort auf die eigentliche Frage

F: Was ist der richtige Proptyp für einen Ref in React?

Beispiel für einen Anwendungsfall:

function FancyInput({ inputRef }) {
    return (
        <div className="fancy">
            Fancy input
            <input ref={inputRef} />
        </div>
    )
}

FancyInput.propTypes = {
    inputRef: ???   // What is the correct prop type here?
}

function App(props) {
    const inputRef = React.useRef()
    useLayoutEffect(function focusWhenStuffChange() {
        inputRef.current?.focus()
    }, [props.stuff])
    return <FancyInput inputRef={inputRef} />
}

Heute gibt es zwei Arten von Refs, um zu reagieren:

  1. Ein Objekt, das so aussieht:, { current: [something] }normalerweise von einem React.createRef()Helfer oder React.useRef()Haken erstellt
  2. Eine Rückruffunktion, die [something]als Argument empfangen wird (wie im OP-Beispiel)

Hinweis: In der Vergangenheit konnten Sie auch eine Zeichenfolgenreferenz verwenden, diese wird jedoch als Legacy betrachtet und aus der Reaktion entfernt

Der zweite Punkt ist recht einfach und erfordert den folgenden Requisitentyp : PropTypes.func.

Die erste Option ist weniger offensichtlich, da Sie möglicherweise den Elementtyp angeben möchten, auf den die Referenz zeigt.

Viele gute Antworten

ref kann auf etwas anderes als ein DOM-Element verweisen.

Wenn Sie völlig flexibel sein möchten:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.any })
])

Das Obige erzwingt nur die Form des Objekts ref w / currentproperty. Es wird jederzeit für jede Art von Ref funktionieren. Für die Verwendung des Requisitentyps, mit dem Inkonsistenzen bei der Entwicklung erkannt werden können , ist dies wahrscheinlich ausreichend. Es ist sehr unwahrscheinlich, dass ein Objekt mit Form { current: [any] }, das an eine refToForwardRequisite übergeben wird, keine tatsächliche Referenz ist.

Allerdings möchten Sie vielleicht, erklären , dass Ihre Komponente nicht erwartet aus jeder Art von ref, sondern nur eine bestimmte Art, gegeben , was es für diese ref benötigt.

Ich habe eine Sandbox eingerichtet, die einige verschiedene Möglichkeiten zeigt, einen Ref zu deklarieren, auch einige nicht konventionelle, und sie dann mit vielen Requisitentypen zu testen. Sie finden es hier .


Wenn Sie nur einen ref zeigt auf einem nativen Eingabeelement erwarten, nicht jede HTML Element:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(HTMLInputElement) })
])

Wenn Sie nur einen Verweis erwarten, der auf eine React-Klassenkomponente verweist:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(Component) })
])

Wenn Sie nur einen Verweis erwarten, der auf eine Funktionskomponente verweist, mit der eine useImperativeHandleöffentliche Methode verfügbar gemacht wird:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.object })
])

Hinweis: Der obige Requisitentyp ist interessant, da er auch Reaktionskomponenten und native DOM-Elemente abdeckt, da alle das Basis-Javascript erben Object


Es gibt keine gute Möglichkeit, den Requisitentyp für eine Referenz zu deklarieren. Dies hängt von der Verwendung ab. Wenn Ihr Schiedsrichter auf etwas sehr Identifiziertes verweist, kann es sich lohnen, einen bestimmten Requisitentyp hinzuzufügen. Andernfalls reicht es aus, nur die allgemeine Form zu überprüfen.


Hinweis zum serverseitigen Rendern

Wenn Ihr Code auf dem Server ausgeführt werden muss, es sei denn, Sie haben bereits eine DOM-Umgebung mit Polyfill gefüllt , Elementoder ein anderer clientseitiger Typ befindet sich undefinedin NodeJS. Sie können das folgende Shim verwenden, um es zu unterstützen:

Element = typeof Element === 'undefined' ? function(){} : Element

Auf den folgenden React Docs-Seiten finden Sie weitere Informationen zur Verwendung von Refs, sowohl Objekt- als auch Rückrufaktionen , sowie zur Verwendung von useRefHooks

Antwort aktualisiert dank @Rahul Sagore, @Ferenk Kamra, @svnm und @Kamuela Franco

Pandaiolo
quelle
2
Es Elementwird beim serverseitigen Rendern nicht definiert. Irgendeine Lösung dafür?
Rahul Sagore
Guter Punkt. Was ist mit dieser Unterlegscheibe: Element = typeof Element === 'undefined' ? function(){} : Element(vorgeschlagen von Ryan Florence in einer Github-Ausgabe). Wenn es für Sie funktioniert, kann ich es meiner Antwort hinzufügen.
Pandaiolo
Ich habe es herausgefunden und hinzugefügt if (!isBrowser) { global.Element = null; }. Hat für mich gearbeitet. isBrowser = typeof window !== 'undefined';
Rahul Sagore
Gute Antwort. Ich würde es lieben, wenn die TL; DR ganz oben auf der Liste steht.
Kamuela Franco
12

Sehr ähnlich zu @ Pandaiolos Beitrag,

PropTypes.elementType wurde jetzt hinzugefügt

forwardedRef: PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({ current: PropTypes.elementType })
]),

Bei Verwendung von PropTypes> = 15.7.0 PropTypes.elementTypewurde in dieser PR der 10. Februar 2019 hinzugefügt

svnm
quelle
Danke @svnm, ich habe meine Antwort aktualisiert, um dies widerzuspiegeln, was es einfacher macht!
Pandaiolo
1
Am Ende hat das elementTypebei mir nicht funktioniert, also habe ich tatsächlich eine Reihe von Requisitentypen an verschiedenen Arten von Komponenten getestet, auf die ein Schiedsrichter in einem Sandkasten zeigen kann. Hier sind die Ergebnisse: Codesandbox.io/s/loving-benz-w6fbh . Ich bin nicht sicher, ob ich alle Möglichkeiten abgedeckt habe, aber es scheint, dass der richtige Proptyp für das DOM-Element instanceOf(Element)(oder object) ist, für eine Klasse instanceOf(Component)(oder object) und für den spezifischen Anwendungsfall einer Funktionskomponente, die useImperativeHandlees verwendet object. Gedanken?
Pandaiolo
9

Ich überprüfe nur den bevorzugten Weg und da PropType.object nicht sehr wertvoll ist, habe ich Folgendes verwendet:

PropTypes.shape({ current: PropTypes.instanceOf(Element) })
Ferenc Kamras
quelle
1

Ich habe alle oben genannten Antworten überprüft, aber ich bekomme eine Warnung von der Reaktion, also habe ich viel recherchiert und die richtige Antwort erhalten.

import React, { Component } from 'react';

ComponentName.propTypes = {
  reference: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.shape({ current: PropTypes.instanceOf(Component) }),
  ]),
};
Nisharg Shah
quelle