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)
this.props.children
?React.cloneElement()
?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
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.
Ping @vsiao @thasner @basarat @pspeter3 @beckend
Liste ping/auteurs basée sur :
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.
Commentaire le plus utile
Question:
Solution: