Definitelytyped: Besoin d'exemples React.Children.map() et React.cloneElement()

Créé le 26 oct. 2016  ·  8Commentaires  ·  Source: DefinitelyTyped/DefinitelyTyped

React.Children.map() manque un bon exemple , je ne comprends pas comment le taper :

/*
<CheckboxGroup ...>
  <Checkbox ... />
  <Checkbox ... />
  <Checkbox ... />
</CheckboxGroup>
*/

// Child
class Checkbox extends React.Component<CheckboxProps, void> {
  // ...
}

// Parent
class CheckboxGroup extends React.Component<CheckboxGroupProps, void> {
  // ...

  render() {
    const checkboxes = React.Children.map(this.props.children, checkbox =>
      React.cloneElement(checkbox, {
        name: this.props.name,
        checked: this.props.checkedValues.includes(checkbox.props.value),
        onChange: this.handleCheckboxChange.bind(this)
      })
    );

    return (
      <div>
        {checkboxes}
      </div>
    );
  }
}

(exemple très courant, voir http://stackoverflow.com/a/32371612/990356)

  • Comment taper this.props.children ?
  • Comment taper React.cloneElement() ?
  • Comment taper React.Children.map() ?

La plupart du temps je me retrouve avec l'erreur suivante : Type 'string' is not assignable to type 'ReactElement<any>' , voir #8131

Commentaire le plus utile

Question:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

Solution:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

Tous les 8 commentaires

veuillez envoyer une demande de tirage. Je vais le revoir.

@vvakame je ne peux pas, je ne comprends pas comment c'est censé fonctionner

Moi aussi. s'il vous plaît faire des conversations avec les auteurs de définition.

vous devrez taper-annoter ou taper-assert checkbox explicitement car il n'y a aucune garantie que this.props.children ne contienne pas de valeurs non-ReactElement. par exemple:

React.Children.map(this.props.children, (checkbox: React.ReactElement<CheckboxProps>) => 
    React.cloneElement(checkbox) // should be ok
);

@vsiao merci beaucoup, ça marche !

Question:

const checkboxes = React.Children.map(this.props.children, checkbox =>
  React.cloneElement(checkbox, {
    name: this.props.name,
    checked: this.props.checkedValues.includes(checkbox.props.value),
    onChange: this.handleCheckboxChange.bind(this)
  })
);

Solution:

const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
  React.cloneElement(checkbox, {
    checked: props.checkedValues.includes(checkbox.props.value),
    onChange: handleCheckboxChange
  })
);

@tkrotoff vous pouvez aussi faire ceci :

    React.Children.map(this.props.children, (child: number) => {
      return child + 1
    })

Ceci et la solution suggérée profitent simplement du fait que React.Children.map n'est pas fortement typé. Vous pourriez aussi bien avoir utilisé any au lieu du type Checkbox car il n'y a aucune garantie que ce sera le type des enfants. Cela signifie que vous risquez d'avoir des erreurs d'exécution si quelqu'un utilise mal le composant en passant une chaîne.

Que dis-tu de ça:

class Slot extends React.PureComponent {
  render () {
    return this.props.children
  }
}

const isReactElement = (obj: {}): obj is React.ReactElement<{}> => {
  return obj.hasOwnProperty('type')
}

const isSlot = (obj: {}): obj is Slot => {
  return isReactElement(obj) && obj.type === Slot
}

const getSlots = (children: React.ReactNode) => React.Children.map(children, (child: React.ReactChild): JSX.Element | null => {
  if (isReactElement(child) && isSlot(child)) {
    return child
  }

  return null
})

class ComponentWithSlots extends React.PureComponent {
  render () {
    const [header, footer] = getSlots(this.props.children)

    return (
      <div>
        {header}
        <div>
          <h1>Welcome</h1>
          <p>This is my lovely component with slots</p>
        </div>
        {footer}
      </div>
    )
  }
}

class MyComponent extends React.PureComponent {
  render () {
    return (
      <ComponentWithSlots>
        <Slot>My Header!</Slot>
        <Slot>
          <div>github: @variousauthors</div>
        </Slot>
      </ComponentWithSlots>
    )
  }
}

Ce qui rendra :

My Header!
Welcome
This is my lovely component with slots

github: <strong i="17">@variousauthors</strong>

Cette approche tire parti des informations de type que nous avons, à savoir qu'un ReactChild pourrait être un ReactElement (j'ai utilisé type pour détecter cela, mais vous pourriez être plus prudent si vous vouliez). Nous pouvons également être plus descriptifs et élaborés que Slot . J'ai vu une bibliothèque d'interface utilisateur implémenter un modèle où les classes avaient leurs propres emplacements attachés. Quelque chose comme:

<Dropdown>
  <Dropdown.Header>
    <FancyIcon>My Header!</FancyIcon>
  </Dropdown.Header>
  {dropdownItems}
</Dropdown>

De cette façon, l'utilisateur est clair sur la signification de chaque emplacement. Le reste des enfants (ceux qui ne sont pas analysés en tant qu'emplacements) sont laissés dans une collection appelée children et rendus à la panier, permettant à l'utilisateur de continuer à utiliser children normalement tout en réservant un comportement spécial pour le créneaux personnalisés.

EDIT : React a apparemment une méthode React.isValidElement que vous pouvez utiliser à la place de mon isReactElement .

EDIT : Vous pouvez également saisir la propriété children sur votre composant, afin qu'un utilisateur ne soit autorisé à transmettre des cases à cocher qu'en tant qu'enfants. Cela aidera à éviter ces erreurs d'exécution.

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

Questions connexes

JWT
svipas picture svipas  ·  3Commentaires

tyv picture tyv  ·  3Commentaires

lilling picture lilling  ·  3Commentaires

csharpner picture csharpner  ·  3Commentaires

jgoz picture jgoz  ·  3Commentaires