React: Warnung für: PropTypes.object.isRequired when prop is `null`

Erstellt am 16. Feb. 2015  ·  37Kommentare  ·  Quelle: facebook/react

Da es sich bei PropTypes um den 'Typ' von Requisiten handelt, ist null ein leeres Objekt, aber praktisch immer noch ein Objekttyp.

Aber es warnt trotzdem:

 Warning: Required prop `profile` was not specified in `Element`. Check the render method of `OtherElement`.

Ich glaube nicht, dass dies passieren sollte.

Es hört auf zu warnen, nachdem es nicht mehr null ist. Ich bin mir ziemlich sicher, dass es nur warnen sollte, wenn es undefined ?

Hilfreichster Kommentar

Ein häufiger Anwendungsfall, den ich sehe, ist das React-Rendering einer Komponente, bevor ein API-Aufruf für Daten abgeschlossen ist. Das erste Rendern würde beispielsweise eine Liste von Elementen rendern ( items: null ). Dann ist der API-Aufruf beendet, und jetzt wird items mit einem Array gefüllt.

Alle 37 Kommentare

null entspricht keinem Wert und ist kein Objekt (leer oder anderweitig). Wenn Sie nicht möchten, dass für null gewarnt wird, dann machen Sie es nicht erforderlich, es hat den gleichen Effekt. Das Testen auf das Vorhandensein eines Schlüssels würde ich nicht empfehlen.

Ich stimme zu. Ich kann mir nicht viele Anwendungsfälle vorstellen, in denen Sie einen Benutzer zwingen möchten, einen Wert anzugeben, aber bereit sind, null als gültigen Wert zu akzeptieren. Aus praktischen Gründen ist die isRequired-Warnung für null ein sinnvolles und erwartetes Verhalten.

verwandt: https://github.com/facebook/react/issues/2166
(Dieses Problem wird in den Suchergebnissen immer noch prominent angezeigt)

Ein häufiger Anwendungsfall, den ich sehe, ist das React-Rendering einer Komponente, bevor ein API-Aufruf für Daten abgeschlossen ist. Das erste Rendern würde beispielsweise eine Liste von Elementen rendern ( items: null ). Dann ist der API-Aufruf beendet, und jetzt wird items mit einem Array gefüllt.

Ich versuche PropTypes.oneOfType([null, PropTypes.object]).isRequired zu tun, also entweder null oder ein Objekt, ist dies gerade nicht möglich?

Laut CHANGELOG soll es seit 15.4.0 möglich sein

Tatsächlich ist es in 15.4.0 genau umgekehrt: Required PropTypes now fail with specific messages for null and undefined.

ich stehe auch vor diesem Problem.
Die Problemumgehung von @Noitidart funktioniert bei mir nicht. Es wirft einen Fehler aus, der sagt:
Failed prop type: The prop Wert is marked as required in Auswählen , but its value is null .

Ich finde es sehr nützlich, eine Eigenschaft zu verlangen, aber auch Nullwerte zuzulassen.

+1 für das Erlauben von null irgendwie.

Wir haben einen Anwendungsfall, bei dem unsere Konfiguration über JSON geladen wird, und es gibt mehrere Label-Konfigurationsoptionen, die eine Zeichenfolge angeben, die angezeigt werden soll, etwa so:

{
  "title": "my title"
}

Wenn also kein Titel angezeigt werden soll, verwenden wir null , um diesen Fall zu kennzeichnen:

{
  "title": null
}

(Das Hinzufügen von parallelen hasTitle: false wäre unerschwinglich, da wir Dutzende dieser Einstellungen haben.)

Bei JSON-Inhalten ist die Verwendung von null eine sehr nützliche Methode, um zwischen nicht definiert ( undefined ) und absichtlich weggelassen ( null ) zu unterscheiden.

Sie können null zulassen, setzen Sie den propType auf nicht erforderlich, da er nicht erforderlich ist :P

@jquense danke das ist super hilfreich! Ich hatte meinen vorherigen Kommentar gelöscht, weil diese SO- Antwort dasselbe sagte.

@jquense Sie können null UND undefiniert zulassen, aber nicht das eine oder das andere.

Das ist das ganze Problem! Javascript hat diese 2 verschiedenen Konstrukte aus einem bestimmten Grund bereitgestellt, daher ist es eine künstliche Einschränkung, jeden dazu zu zwingen, null === undefined für PropTypes zu behandeln.

Nur weil ich möchte, dass ein PropType null explizit zulässt, bedeutet das nicht, dass ich auch undefined zulassen sollte. Es sind zwei verschiedene Fälle, und die Sprache hat sie absichtlich so entworfen.

Ich habe hier eine PR, um dieses Versehen zu umgehen: https://github.com/facebook/prop-types/pull/90

Ich möchte undefined verbieten, weil dies bedeutet, dass ein Tippfehler vorliegt, und null zulassen, weil dies bedeutet, dass der Aufrufer explizit null . Das ist der Sinn dieser Ausgabe. Ich verstehe, dass dieses Problem geschlossen ist, da es empfohlen wird, einfach auf Flow zu wechseln, was ich untersuchen werde.

@binki Eine Möglichkeit, null zuzulassen, aber nicht undefined besteht darin, Ihre eigene PropType-Validierungsfunktion zu verwenden.

Im Beispiel unten ist nur null oder string erlaubt. Die PropTypes-Bibliothek verwendet intern typeof , um nach Zeichenfolgen zu suchen, also habe ich dasselbe getan. Ein Vorteil besteht darin, dass Sie diese Funktion außerhalb Ihrer Komponente verschieben und bei Bedarf aufrufen können.

static propTypes = {
  id: PropTypes.number.isRequired,
  email: function(props, propName, componentName) {
    const propValue = props[propName] // the actual value of `email` prop
    if (propValue === null) return
    if (typeof propValue === 'string') return
    return new Error(`${componentName} only accepts null or string`)
  }
}

Ich denke, diese Lösung weicht von der Absicht der PropTypes-Bibliothek ab - der Grund, warum ich dies sage, liegt an dem folgenden Code aus der PropTypes-Bibliothek unter https://github.com/facebook/prop-types/blob/master/factoryWithTypeCheckers.js #L189.

Vor der eigentlichen Validierung wird eine Schnellprüfung durchgeführt, bei der mit isRequired festgelegte Eigenschaften automatisch einen Fehler auslösen, wenn der Eigenschaftswert null . Mit anderen Worten, sie glauben, dass eine erforderliche NULL-Eigenschaft falsch ist, während ich es für einen gültigen Anwendungsfall halte, erforderliche NULL-Werte zu haben.

if (props[propName] == null) {
  if (isRequired) {
    if (props[propName] === null) {
      return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
    }
    return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
  }
  return null;
} else {
  return validate(props, propName, componentName, location, propFullName);
}

Ich stimme @jharris4 aus den genannten Gründen zu. null ist nicht dasselbe wie undefined . Standardmäßig wird es als Platzhalter verwendet.

Vom Mozilla-Entwicklernetzwerk:

Der Wert null steht für das absichtliche Fehlen eines Objektwerts.

null ist kein Bezeichner für eine Eigenschaft des globalen Objekts, wie es undefined sein kann. Stattdessen drückt null einen Mangel an Identifikation aus, was darauf hinweist, dass eine Variable auf kein Objekt zeigt. In APIs wird null oft an einer Stelle abgerufen, an der ein Objekt erwartet werden kann, aber kein Objekt relevant ist.

null sollte erlaubt sein, zumindest bis PropTypes.oneOfType([null, PropTypes.string]).isRequired .

@jquense — Das Entfernen von isRequired bedeutet, dass Sie wahrscheinlich einen Standardwert festlegen sollten. Bedeutet dies, dass Sie jetzt einen Standardwert für den Anfangswert in der Komponente _and_ im Reducer festlegen würden, um zu vermeiden, dass null als Wert für eine Requisite zugelassen wird?

Ich habe eine Menge data || '' ( isRequired akzeptiert leere Zeichenfolgen '' , leeres Objekt {} usw.) in meinen Selektoren, während ich auf API-Aufrufe warte Finish null ist die perfekte Lösung, um der Komponente mitzuteilen, dass die Daten kommen. Warten Sie einfach ein bisschen! (aber das kann ich nicht...)
@puiu91 hat Lösung ... Ich werde eine Dienstprogrammfunktion seufz

Ich stimme auch zu, dass es eine Standardmethode geben sollte, um null als Wert zu akzeptieren, aus den gleichen Gründen, die @jharris4 und @Findiglay angegeben haben, aber dies ist nicht mehr der Ort, um die Diskussion fortzusetzen. Dieses Problem ist nicht nur geschlossen, sondern gehört auch zu facebook/prop-types . Ich folge der Pull-Anfrage hier facebook/prop-types#90.

Stoßen. Läuft heute noch darauf ein. Wäre toll, integrierte Unterstützung für so etwas zu haben:

myObj: PropType.object.isRequiredOrNull :)

Ich denke, die Priorität ist hier sehr niedrig. Flow ist der empfohlene Weg. http://flow.org/

@Marujah dein Snippet ist nicht korrekt.

Versuchen Sie, null an die Komponente zu übergeben, und Sie werden sehen, dass Sie die Warnung erhalten:

Warning: Failed prop type: The prop 'theProp' is marked as required in 'TheComponent', but its value is null.

Das Problem ist, dass isRequired ZUERST ausgewertet wird und niemals null oder undefinierte Werte durchlässt.

Der PR zu den Requisitentypen zur Behebung des Problems ist oben verlinkt, wenn Sie daran interessiert sind.

Ach ja! nochmal getestet hast du recht

Die Anforderung, dass ein Wert oder null explizit angegeben werden muss, sollte über PropTypes unbedingt zulässig sein.

Hier ist der Anwendungsfall, auf den ich stoße. Wir haben einige Rückrufe, die von 90% unserer Selektoren benötigt werden. Die wenigen, die sie nicht benötigen, sind sehr spezifische Anwendungsfälle. Wir haben einige neue Entwickler, die ständig vergessen, alle üblichen Rückrufe bereitzustellen.

Ich möchte alle Verwendungen dieser Komponenten dazu zwingen, die bewusste Entscheidung zu treffen, keine spezifischen Rückrufe einzuschließen, anstatt nur ein paar Requisiten zu vergessen.

Ja, wir können unsere eigenen spezifischeren Checks über den Flow hacken, aber das teilt unsere Props-Validierung in zwei Bereiche auf und ist für jemanden, der sich die PropTypes-Definitionen ansieht, ziemlich unintuitiv.

Wollte hier nur meinen Anwendungsfall hinzufügen. Ich habe einen Redux-Speicher mit Daten zusammen mit dem Zeitpunkt, an dem diese Daten abgerufen wurden, ob ein Fehler aufgetreten ist usw. Meine Komponente erfordert eine 'Fehler'-Prop (damit sie dem Benutzer den Fehler anzeigen kann, wenn die Daten nicht abgerufen werden konnten). Dies ist null, wenn die Daten erfolgreich geladen wurden, aber aufgefüllt, wenn ein Fehler auftritt.

Ich übergebe eine Loader-Komponente ( PropTypes.node ) als props , und wenn ich keinen Loader rendern möchte, übergebe ich null .
Afaik, eine render Funktion sollte null anstelle von undefined wenn nichts gerendert wird. Die Übergabe von null als Wert sieht für mich wie der richtige Weg aus.

Ich implementierte die InputNumber-Komponente (Wrapper für <input type="number"> ), also hatte ich propTypes für meine Requisite valuePropTypes.number.isRequired , und als ich meine Komponente verwendet habe, habe ich hat es immer Eigentum übergeben. Aber heute muss ich dort standardmäßig einen Nullable-Link an value übergeben, und meine Komponente fügt eine Warnung hinzu. Die einzige Entscheidung, die ich mir vorstellen kann, ist, propTypes für meine Requisite value in PropTypes.oneOfType([PropTypes.number, PropTypes.string]) zu ändern und defaultProps auf null zu setzen. Aber ich denke, es ist nicht das richtige, da input type=number nur mit Zahlen funktionieren sollte.

Ich versuche PropTypes.oneOfType([null, PropTypes.object]).isRequired zu tun, also entweder null oder ein Objekt, ist dies gerade nicht möglich?

Es erwartet eine Funktion: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Sie sollten also eine Funktion bereitstellen, wie zum Beispiel:

PropTypes.oneOfType([
  () => null,
  PropTypes.object
]).isRequired

Nachdem ich gerade auf diesen Fehler gestoßen bin, habe ich eine Komfortfunktion geschrieben, um ihn zu umgehen:

function nullable(subRequirement) {
  const check = (required, props, key, ...rest) => {
    if (props[key] === null) {
      return null;
    }
    const sub = required ? subRequirement.isRequired : subRequirement;
    return sub(props, key, ...rest);
  };
  const fn = check.bind(null, false);
  fn.isRequired = check.bind(null, true);
  return fn;
}

Verwendung:

static propTypes = {
  someCallbackFunction: nullable(PropTypes.func).isRequired,
};

Es ist möglich (aber ziemlich sinnlos), nullable ohne isRequired . Der Grund, warum ich es mit isRequired kompatibel mache, ist, dass es mit der eslint-Regel react/require-default-props funktioniert.

Mein Anwendungsfall ist eine Reihe von Komponenten, die einer gemeinsamen API entsprechen und von einer einzigen Komponente umschlossen sind, die Rückrufe verarbeitet. null Callbacks bedeuten 'schreibgeschützt', daher übergibt die Wrapper-Komponente manchmal absichtlich null s. Gleichzeitig ist es wichtig, dass jede Eigenschaft an die Unterkomponenten übergeben wird, um sicherzustellen, dass beim Hinzufügen einer neuen Eigenschaft diese nicht übersehen wird. Ich möchte auch nicht defaultProps von null für jede Komponente bereitstellen, die dieser API entspricht; Soweit bekannt, muss der Anrufer einen Wert angegeben haben.

Ich habe den Helfer, den ich zuvor geschrieben habe, genommen und zusammen mit einer Reihe von Tests in ein Paket gepackt, um die Richtigkeit zu beweisen:

npm install --save git+https://github.com/davidje13/prop-types-nullable.git#semver:^1.0.0

Verwendung:

import PropTypes from 'prop-types';
import nullable from 'prop-types-nullable';

[...]

static propTypes = {
  thing: nullable(PropTypes.string).isRequired,
};

Neue Lösung: PropTypes.oneOfType([PropTypes.object]).isRequired

Ich bekomme einen Fehler.
wie repariert man.

WARNUNG in ./~/prop-types/prop-types.js Kritische Abhängigkeiten: 1:482-489 Dies scheint eine vorgefertigte Javascript-Datei zu sein. Dies ist zwar möglich, wird jedoch nicht empfohlen. Versuchen Sie, die Originalquelle anzufordern, um bessere Ergebnisse zu erzielen. @ ./~/prop-types/prop-types.js 1:482-489

Ich versuche PropTypes.oneOfType([null, PropTypes.object]).isRequired zu tun, also entweder null oder ein Objekt, ist dies gerade nicht möglich?

Es erwartet eine Funktion: Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Sie sollten also eine Funktion bereitstellen, wie zum Beispiel:

PropTypes.oneOfType([
  () => null,
  PropTypes.object
]).isRequired

Eigentlich hatte ich einen Fehler, weil 'isRequired' am Ende ist, null und gleichzeitig erforderlich ist, ist nicht kompatibel ...
Das hat bei mir funktioniert:

PropTypes.oneOfType([ 
    PropTypes.string.isRequired, 
    () => null 
])

@gugol2 Bitte beachten Sie, dass das, was Sie geschrieben haben, nur die Typprüfung vollständig deaktiviert (Sie können jetzt eine Zahl an diese Requisite übergeben, oder undefined oder irgendetwas anderes); Die von Ihnen bereitgestellte Funktion sollte null wenn die Validierung erfolgreich ist, und nicht null wenn sie fehlschlägt.

Wenn Sie diesen Weg gehen möchten, benötigen Sie mehr wie:

PropTypes.oneOfType([
  PropTypes.string.isRequired,
  (props, key) => props[key] === null ? null : 'Not null'
])

Natürlich könnte man die fies aussehende Hilfsfunktion vordefinieren:

const nullable = (props, key) => props[key] === null ? null : 'Not null'

// ...

PropTypes.oneOfType([PropTypes.string.isRequired, nullable])

Es ist auch bizarr möglich (aber ich würde es wirklich nicht empfehlen!) einfach PropTypes.oneOfType([PropTypes.string.isRequired]) . Dies fühlt sich jedoch wie ein Fehler an und ich würde nicht erwarten, dass Code wie dieser spätere Versionen überlebt. Beachten Sie auch, dass es einer zuvor vorgeschlagenen Methode ähnlich, aber nicht gleich ist, die nicht funktioniert.


Wenn Sie warten können, gibt es eine offene PR, die sich unglaublich langsam bewegt, aber anscheinend immer noch in Betracht gezogen wird.

Und bis der PR zusammengeführt ist, würde ich empfehlen, das von mir erstellte Paket (oder den Code dahinter ) zu verwenden, da Sie auf diese Weise .isRequired am Ende der Zeile einfügen können , was es mit den Linting-Regeln kompatibel macht.

IMHO ist dies das richtige Verhalten, aber es sollte dokumentiert werden.

Ein häufiger Anwendungsfall, den ich sehe, ist das React-Rendering einer Komponente, bevor ein API-Aufruf für Daten abgeschlossen ist. Das erste Rendern würde beispielsweise eine Liste von Elementen rendern ( items: null ). Dann ist der API-Aufruf beendet, und jetzt wird items mit einem Array gefüllt.

Gibt es eine beste Möglichkeit, damit umzugehen? Ich möchte, dass diese Requisite erforderlich ist, ABER sie ist null, bevor ich sie von der API zurückbekomme.

PropTypes.oneOfType([
  PropTypes.string.isRequired,
  (props, key) => props[key] === null ? null : 'Not null'
])

@davidje13 Ich habe ein kleines Problem mit diesem Ansatz. Abdeckungstests haben einen 1/4-Fall, der nie abgedeckt wird.

Nehmen wir an, ich habe eine Komponentenanmeldung, die nur einen Prop-'Namen' hat, der null sein kann, oder eine Zeichenfolge erforderlich:

const Login = ({name}) => {
  return <div>{name}</div>
} 

Seine Proptypen sind also:

Login.propTypes = {
  name: PropTypes.oneOfType([
    PropTypes.string.isRequired,
    (props, key) => (props[key] === null ? null : 'Not null'),
  ]),
};

Wenn ich diese Komponente teste, habe ich wirklich nur 2 Szenarien, null ODER eine erforderliche Zeichenfolge.

render(<Login name={null} />
render(<Login name={'anyName'} />

Aber die Abdeckung sagt mir, dass mein Test nur 75% Abdeckung hat.
Ich frage mich, was der offizielle Ansatz dafür sein wird.

Es hört sich so an, als ob Ihr fehlender Testfall derjenige ist, bei dem er die Requisitenprüfung nicht besteht? dh wenn Sie eine Zahl oder undefiniert oder etwas anderes übergeben, sollte es nicht sein.

Es hört sich so an, als ob Ihr fehlender Testfall derjenige ist, bei dem er die Requisitenprüfung nicht besteht? dh wenn Sie eine Zahl oder undefiniert oder etwas anderes übergeben, sollte es nicht sein.

Nein, das ist es nicht.

Das Übergeben von undefined erweitert die Abdeckung nicht.
Und ich kann sowieso keine Zahl übergeben, es ist kein zulässiger Wert.

Ich kann diesen Fall nicht abdecken.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen