React proptype array with shape

246

Existe-t-il un moyen intégré d'utiliser des proptypes pour garantir qu'un tableau d'objets transmis à un composant est en réalité un tableau d'objets d'une forme spécifique?

Peut-être quelque chose comme ça?

annotationRanges: PropTypes.array(PropTypes.shape({
    start: PropTypes.number.isRequired,
    end: PropTypes.number.isRequired,
})),

Suis-je en train de manquer quelque chose de super évident ici? On dirait que ce serait très recherché.

majorBummer
la source

Réponses:

372

Vous pouvez utiliser React.PropTypes.shape()comme argument pour React.PropTypes.arrayOf():

// an array of a particular shape.
ReactComponent.propTypes = {
   arrayWithShape: React.PropTypes.arrayOf(React.PropTypes.shape({
     color: React.PropTypes.string.isRequired,
     fontSize: React.PropTypes.number.isRequired,
   })).isRequired,
}

Voir la section Validation des accessoires de la documentation.

METTRE À JOUR

À partir de react v15.5, l'utilisation React.PropTypesest obsolète et le package autonome prop-typesdoit être utilisé à la place:

// an array of a particular shape.
import PropTypes from 'prop-types'; // ES6 
var PropTypes = require('prop-types'); // ES5 with npm
ReactComponent.propTypes = {
   arrayWithShape: PropTypes.arrayOf(PropTypes.shape({
     color: PropTypes.string.isRequired,
     fontSize: PropTypes.number.isRequired,
   })).isRequired,
}
Pierre Criulanscy
la source
17
Il convient de souligner l'utilisation de .isRequiredsur chaque propriété de React.PropTypes.shape. Je suis arrivé ici parce que je suppose à tort que l'utilisation .isRequiredsur React.PropTypes.arrayOf, je ne l' ai pas besoin à l' intérieur. Pour obtenir une validation complète de la couverture, j'ai fini par l'appliquer directement React.PropTypes.shape.
gfullam
1
Oui, je faisais exactement la même chose que vous, mais c'est beaucoup plus puissant d'avoir la possibilité de marquer uniquement comme requis les clés que vous souhaitez. Explicite est toujours mieux qu'implicite pour moi au fait.
Pierre Criulanscy
Cet exemple n'échoue pas correctement pour moi. Si le if arrayWithShapeest [] (un tableau vide), il n'échoue pas. si arrayWithShapeest {} (un objet), il échoue. Si arrayWithShape est [{dumb: 'something'}](un tableau sans les bons accessoires), il échoue. J'en ai besoin pour échouer la validation s'il arrayWithShapes'agit d'un tableau vide. Je veux seulement qu'il passe si c'est un tableau non vide avec des objets qui ont des accessoires coloret fontsize. Qu'est-ce que je rate?
sdc
50

Oui, vous devez utiliser PropTypes.arrayOfau lieu de PropTypes.arraydans le code, vous pouvez faire quelque chose comme ceci:

import PropTypes from 'prop-types';

MyComponent.propTypes = {
  annotationRanges: PropTypes.arrayOf(
    PropTypes.shape({
      start: PropTypes.string.isRequired,
      end: PropTypes.number.isRequired
    }).isRequired
  ).isRequired
}

Aussi pour plus de détails sur les proptypes , visitez Typechecking With PropTypes ici

Alireza
la source
3
Quelle est la raison de l'ajout de .isRequired à l'objet PropTypes.shape?
makovkastar
@makovkastar Parce que sans cela, [undefined]passerait la validation
user123
6

Il y a une importation abrégée ES6, vous pouvez faire référence. Plus lisible et facile à taper.

import React, { Component } from 'react';
import { arrayOf, shape, number } from 'prop-types';

class ExampleComponent extends Component {
  static propTypes = {
    annotationRanges: arrayOf(shape({
      start: number,
      end: number,
    })).isRequired,
  }

  static defaultProps = {
     annotationRanges: [],
  }
}
Moewiz
la source
1
Veuillez consulter Comment écrire une bonne réponse . Les réponses uniquement codées sont déconseillées car elles n'expliquent pas comment elles résolvent le problème dans la question. Vous devez mettre à jour votre réponse pour expliquer ce que cela fait et comment il améliore les réponses votées que cette question a déjà.
FluffyKitten
1

Si je dois définir plusieurs fois les mêmes proptypes pour une forme particulière, j'aime les résumer dans un fichier proptypes de sorte que si la forme de l'objet change, je n'ai qu'à changer le code au même endroit. Cela aide à assécher un peu la base de code.

Exemple:

// Inside my proptypes.js file
import PT from 'prop-types';

export const product = {
  id: PT.number.isRequired,
  title: PT.string.isRequired,
  sku: PT.string.isRequired,
  description: PT.string.isRequired,
};


// Inside my component file
import PT from 'prop-types';
import { product } from './proptypes;


List.propTypes = {
  productList: PT.arrayOf(product)
}
Yo Wakita
la source
1

C'était aussi ma solution pour me protéger contre un tableau vide:

import React, { Component } from 'react';
import { arrayOf, shape, string, number } from 'prop-types';

ReactComponent.propTypes = {
  arrayWithShape: (props, propName, componentName) => {
    const arrayWithShape = props[propName]
    PropTypes.checkPropTypes({ arrayWithShape:
        arrayOf(
          shape({
            color: string.isRequired,
            fontSize: number.isRequired,
          }).isRequired
      ).isRequired
    }, {arrayWithShape}, 'prop', componentName);
    if(arrayWithShape.length < 1){
      return new Error(`${propName} is empty`)
    }
  }
}
sdc
la source