React: Avertissement pour : PropTypes.object.isRequired lorsque prop est « null »

Créé le 16 févr. 2015  ·  37Commentaires  ·  Source: facebook/react

Comme PropTypes concerne le 'type' d'accessoire, null est un objet vide, mais toujours un type d'objet, pratiquement.

Mais il avertit toujours :

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

Je ne pense pas que cela soit censé arriver.

Il arrête d'avertir après qu'il n'est plus null . Je suis sûr qu'il ne devrait avertir que lorsqu'il s'agit de undefined ?

Commentaire le plus utile

Un cas d'utilisation courant que je vois est le rendu d'un composant par React avant la fin d'un appel d'API pour les données. Le premier rendu rendrait, par exemple, une liste d'éléments ( items: null ). Ensuite, l'appel d'API se termine et maintenant items est rempli avec un tableau.

Tous les 37 commentaires

null est l'équivalent d'aucune valeur et n'est pas un objet (vide ou non). Si vous ne voulez pas qu'il avertisse pour null alors ne le rendez pas obligatoire, cela a le même effet. Je ne recommanderais pas de tester la présence d'une clé.

Je suis d'accord. Je ne peux pas penser à de très nombreux cas d'utilisation dans lesquels vous voudriez forcer un utilisateur à spécifier une valeur, mais seriez prêt à accepter null comme valeur valide. À des fins pratiques, l'avertissement isRequired pour null est un comportement raisonnable et attendu.

connexe : https://github.com/facebook/react/issues/2166
(ce problème apparaît toujours en bonne place dans les résultats de recherche)

Un cas d'utilisation courant que je vois est le rendu d'un composant par React avant la fin d'un appel d'API pour les données. Le premier rendu rendrait, par exemple, une liste d'éléments ( items: null ). Ensuite, l'appel d'API se termine et maintenant items est rempli avec un tableau.

J'essaie de faire PropTypes.oneOfType([null, PropTypes.object]).isRequired , donc soit null, soit un objet, n'est-ce pas possible pour le moment ?

D'après le CHANGELOG , puisque 15.4.0 c'est supposé être possible

En fait, c'est l'inverse en 15.4.0 : Required PropTypes now fail with specific messages for null and undefined.

Je suis également confronté à ce problème.
La solution de contournement de @Noitidart ne fonctionne pas pour moi. Il renvoie une erreur en disant :
Failed prop type: The prop valeur is marked as required in Sélectionner , but its value is null .

Je trouve vraiment utile d'exiger une propriété mais aussi d'autoriser les valeurs nulles.

+1 pour avoir autorisé null manière ou d'

Nous avons un cas d'utilisation où notre configuration est chargée via JSON, et il existe plusieurs options de configuration d'étiquette qui spécifient une chaîne qui doit être affichée, quelque chose comme ceci :

{
  "title": "my title"
}

Ainsi, lorsqu'aucun titre ne doit être affiché, nous utilisons null pour désigner ce cas :

{
  "title": null
}

(Ajouter parallèlement hasTitle: false serait prohibitif car nous avons des dizaines de ces paramètres.)

Pour le contenu JSON, l'utilisation de null est un moyen très utile de faire la distinction entre non défini ( undefined ) et délibérément omis ( null ).

vous pouvez autoriser null, définir le propType pour qu'il ne soit pas requis, car il n'est pas requis :P

@jquense merci c'est super utile ! J'avais supprimé mon commentaire précédent car cette réponse SO disait la même chose.

@jquense vous pouvez autoriser null ET indéfini, mais pas l'un ou l'autre.

C'est tout le problème ! Javascript a fourni ces 2 constructions différentes pour une raison, donc forcer tout le monde à traiter null === undefined pour les PropTypes est une limitation artificielle.

Ce n'est pas parce que je veux qu'un PropType autorise explicitement null que je devrais également autoriser undefined. Ce sont deux cas distincts, et le langage les a conçus de cette façon à dessein.

J'ai un PR pour contourner cet oubli ici : https://github.com/facebook/prop-types/pull/90

Je veux interdire undefined car cela signifie qu'il y a une faute de frappe et autoriser null car cela signifie que l'appelant a explicitement transmis null . C'est le point de cette question. Je comprends que ce problème est clos car il est recommandé de simplement passer au flux, ce que je vais examiner.

@binki Une façon d'autoriser null mais pas undefined est d'utiliser votre propre fonction de validation PropType.

Dans l'exemple ci-dessous, seul null ou string est autorisé. La bibliothèque PropTypes utilise typeof interne pour vérifier les chaînes, j'ai donc fait de même. L'un des avantages est que vous pouvez déplacer cette fonction en dehors de votre composant et l'appeler selon vos besoins.

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`)
  }
}

Je suppose que cette solution s'écarte de l'intention de la bibliothèque PropTypes - la raison pour laquelle je dis cela est due au code ci-dessous de la bibliothèque PropTypes à https://github.com/facebook/prop-types/blob/master/factoryWithTypeCheckers.js #L189.

Avant de valider réellement, une vérification rapide est effectuée dans laquelle les propriétés définies avec isRequired renvoient automatiquement une erreur si la valeur de la propriété est null . En d'autres termes, ils pensent qu'une propriété requise étant nulle est erronée alors que je considère comme un cas d'utilisation valide d'avoir des valeurs nulles requises.

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);
}

Je suis d'accord avec @jharris4 pour les raisons indiquées. null n'est pas la même chose que undefined . Il est standard de l'utiliser comme espace réservé.

Du réseau de développeurs Mozilla :

La valeur null représente l'absence intentionnelle de toute valeur d'objet.

null n'est pas un identifiant pour une propriété de l'objet global, comme peut l'être undefined. Au lieu de cela, null exprime un manque d'identification, indiquant qu'une variable ne pointe vers aucun objet. Dans les API, null est souvent récupéré à un endroit où un objet peut être attendu mais aucun objet n'est pertinent.

null devrait être autorisé, au moins jusqu'à PropTypes.oneOfType([null, PropTypes.string]).isRequired .

@jquense — La suppression de isRequired signifie que vous devriez probablement définir une valeur par défaut. Cela signifie-t-il que vous définiriez maintenant une valeur par défaut pour la valeur initiale dans le composant _et_ dans le réducteur, tout cela pour éviter d'autoriser null comme valeur pour un accessoire ?

J'ai un tas de data || '' ( isRequired accepte une chaîne vide '' , un objet vide {} , etc.) dans mes sélecteurs cause en attendant les appels d'API à terminer null est la chose parfaite pour dire au composant que les données arrivent, attendez un peu ! (mais je ne peux pas faire ça...)
@puiu91 a du bon travail pour le moment... Je vais devoir créer une fonction utilitaire à utiliser dans notre base de code... car il semble que ce problème ne soit pas rouvert de sitôt soupir

Je suis également d'accord qu'il devrait y avoir un moyen standard d'accepter null comme valeur, pour les mêmes raisons que @jharris4 et @Findiglay , mais ce n'est plus l'endroit pour continuer la discussion. Non seulement ce problème est clos, mais il appartient à facebook/prop-types . Je suis la pull request ici facebook/prop-types#90.

Cogner. Toujours en cours d'exécution aujourd'hui. Ce serait génial d'avoir un support intégré pour quelque chose comme:

myObj : PropType.object.isRequiredOrNull :)

Je pense que la priorité à ce sujet est très faible. Flow est la voie à suivre recommandée. http://flow.org/

@Marujah, votre extrait n'est pas correct.

Essayez de passer null au composant, et vous verrez que vous obtiendrez l'avertissement :

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

Le problème est que isRequired est évalué EN PREMIER et qu'il ne laissera jamais passer les valeurs nulles ou indéfinies.

Le PR aux types d'accessoires pour résoudre le problème est lié ci-dessus si vous êtes intéressé.

Ah effectivement ! retesté tu as raison

Exiger qu'une valeur ou null soit spécifiquement fournie doit absolument être autorisé via PropTypes.

Voici le cas d'utilisation que je rencontre. Nous avons des rappels qui sont requis par 90 % de nos sélecteurs. Les rares qui n'en ont pas besoin sont des cas d'utilisation très spécifiques. Nous avons de nouveaux développeurs qui oublient constamment de fournir tous les rappels habituels.

Je veux forcer toutes les utilisations de ces composants à prendre la décision consciente de ne pas inclure de rappels spécifiques, plutôt que quelqu'un oubliant simplement quelques accessoires.

Oui, nous pouvons pirater nos propres vérifications plus spécifiques via le flux, mais cela divise la validation de nos props en deux endroits et est plutôt peu intuitif pour quelqu'un qui jette un coup d'œil aux définitions de propTypes.

Je voulais juste ajouter mon cas d'utilisation ici. J'ai un magasin redux avec des données avec le moment où ces données ont été récupérées, s'il y a eu une erreur, etc. Mon composant nécessite un accessoire « erreur » (afin qu'il puisse afficher l'erreur à l'utilisateur si les données ne peuvent pas être récupérées), qui est nul lorsque les données sont chargées avec succès, mais renseigné lorsqu'il y a une erreur.

Je passe un composant de chargeur ( PropTypes.node ) en tant que props , et quand je ne veux pas rendre un chargeur, je passe null .
Afaik, une fonction render devrait renvoyer null au lieu de undefined lorsqu'elle ne rend rien. Donc, passer null comme valeur semble être la bonne façon de le faire pour moi.

J'implémentais le composant InputNumber (wrapper pour <input type="number"> ), donc j'avais propTypes pour mon prop valuePropTypes.number.isRequired , et quand j'ai utilisé mon composant, j'ai toujours passé la propriété. Mais aujourd'hui, je dois y passer un lien nullable par défaut vers value, et mon composant ajoute un avertissement. La seule décision que je puisse imaginer est de changer propTypes pour mon prop value en PropTypes.oneOfType([PropTypes.number, PropTypes.string]) et de définir le defaultProps comme nul. Mais je pense que ce n'est pas le bon car input type=number ne devrait fonctionner qu'avec des nombres.

J'essaie de faire PropTypes.oneOfType([null, PropTypes.object]).isRequired , donc soit null, soit un objet, n'est-ce pas possible pour le moment ?

Il attend une fonction : Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Donc, vous devez fournir une fonction, comme :

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

Ayant juste rencontré ce bogue, j'ai écrit une fonction de commodité pour le contourner :

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;
}

Usage:

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

Il est possible (mais plutôt inutile) d'utiliser nullable sans isRequired . La raison pour laquelle je le rends compatible avec isRequired est qu'il fonctionnera avec la règle eslint react/require-default-props .

Mon cas d'utilisation est une série de composants conformes à une API commune, enveloppés par un seul composant qui gère les rappels. null rappels null s. Dans le même temps, il est important que chaque propriété soit transmise aux sous-composants pour s'assurer que si une nouvelle propriété est ajoutée, elle ne sera pas manquée. Je ne veux pas non plus fournir defaultProps de null pour chaque composant conforme à cette API ; pour autant qu'ils le sachent, l'appelant doit avoir spécifié une valeur.

J'ai pris l'assistant que j'avais écrit auparavant et je l'ai mis dans un package avec un tas de tests pour prouver l'exactitude :

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

Usage:

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

[...]

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

Nouvelle solution : PropTypes.oneOfType([PropTypes.object]).isRequired

J'obtiens une erreur.
comment réparer.

AVERTISSEMENT dans ./~/prop-types/prop-types.js Dépendances critiques : 1:482-489 Cela semble être un fichier javascript pré-construit. Bien que cela soit possible, ce n'est pas recommandé. Essayez d'exiger la source d'origine pour obtenir de meilleurs résultats. @ ./~/prop-types/prop-types.js 1:482-489

J'essaie de faire PropTypes.oneOfType([null, PropTypes.object]).isRequired , donc soit null, soit un objet, n'est-ce pas possible pour le moment ?

Il attend une fonction : Warning: Invalid argument supplied to oneOfType. Expected an array of check functions, but received null at index 1.

Donc, vous devez fournir une fonction, comme :

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

En fait, j'ai eu une erreur à cause de ce "isRequired" à la fin, être nul et requis en même temps n'est pas compatible...
C'est ce qui a fonctionné pour moi:

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

@gugol2 s'il vous plaît noter que ce que vous avez écrit va simplement désactiver complètement la vérification de type (vous pouvez maintenant passer un nombre à cette prop, ou undefined , ou quoi que ce soit); la fonction que vous fournissez devrait renvoyer null si la validation réussit et non null si elle échoue.

Si vous voulez emprunter cette voie, vous auriez besoin de quelque chose comme :

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

Bien sûr, vous pouvez prédéfinir la fonction d'assistance à l'apparence désagréable :

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

// ...

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

Il est aussi bizarrement possible (mais je ne le recommanderais vraiment pas !) d'utiliser simplement PropTypes.oneOfType([PropTypes.string.isRequired]) . Cela ressemble cependant à un bogue et je ne m'attendrais pas à ce qu'un code comme celui-ci survive aux versions ultérieures. Notez également qu'elle est similaire, mais pas identique, à une méthode suggérée précédemment qui ne fonctionne pas.


Si vous pouvez attendre, il y a un PR ouvert qui avance incroyablement lentement mais apparemment toujours en considération.

Et jusqu'à ce que le PR soit fusionné, je recommanderais d'utiliser le package que j'ai créé (ou le code sous-jacent ) car de cette façon, vous pouvez mettre .isRequired à la fin de la ligne, ce qui le rend compatible avec les règles de linting.

À mon humble avis, c'est un comportement correct, mais il doit être documenté.

Un cas d'utilisation courant que je vois est le rendu d'un composant par React avant la fin d'un appel d'API pour les données. Le premier rendu rendrait, par exemple, une liste d'éléments ( items: null ). Ensuite, l'appel d'API se termine et maintenant items est rempli avec un tableau.

Une meilleure façon de gérer cela? Je veux que cette prop soit requise MAIS elle est nulle avant que je la récupère de l'API.

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

@davidje13 Je rencontre un petit problème avec cette approche. Les tests de couverture ont 1/4 cas qui n'est jamais couvert.

Disons que j'ai un composant Login qui n'a qu'un seul "nom" de prop qui peut être null ou une chaîne requise :

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

Ses proptypes sont donc :

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

Lorsque je teste ce composant, je n'ai vraiment que 2 scénarios, null OU une chaîne requise.

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

Mais la couverture me dit que mon test n'a qu'une couverture de 75 %.
Je me demande quelle sera l'approche officielle pour cela.

Il semble que votre cas de test manquant soit celui où il échoue à la vérification des accessoires ? c'est-à-dire si vous passez un nombre ou undefined ou autre chose, cela ne devrait pas être le cas.

Il semble que votre cas de test manquant soit celui où il échoue à la vérification des accessoires ? c'est-à-dire si vous passez un nombre ou undefined ou autre chose, cela ne devrait pas être le cas.

Non, ce n'est pas ça.

Passer undefined n'étend pas la couverture.
Et je ne peux pas passer un nombre de toute façon, ce n'est pas une valeur autorisée.

Je ne suis pas en mesure de couvrir ce cas.

Cette page vous a été utile?
0 / 5 - 0 notes