React.Children.map()
falta un buen ejemplo , no entiendo cómo escribirlo:
/*
<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>
);
}
}
(ejemplo muy común, consulte http://stackoverflow.com/a/32371612/990356)
this.props.children
?React.cloneElement()
?React.Children.map()
?La mayoría de las veces termino con el siguiente error: Type 'string' is not assignable to type 'ReactElement<any>'
, vea # 8131
envíe una solicitud de extracción. Lo revisaré.
@vvakame No puedo, no entiendo cómo se supone que funciona
Yo también. por favor, entable conversaciones con los autores de definiciones.
Ping @vsiao @thasner @basarat @ pspeter3 @beckend
Lista de ping / autores basada en:
deberá escribir-anotar o escribir-afirmar checkbox
explícitamente porque no hay garantía de que this.props.children
no contenga valores que no sean ReactElement. por ejemplo:
React.Children.map(this.props.children, (checkbox: React.ReactElement<CheckboxProps>) =>
React.cloneElement(checkbox) // should be ok
);
@vsiao gracias mucho, ¡funciona!
Pregunta:
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)
})
);
Solución:
const checkboxes = React.Children.map(props.children, (checkbox: React.ReactElement<CheckboxPropsInternal>) =>
React.cloneElement(checkbox, {
checked: props.checkedValues.includes(checkbox.props.value),
onChange: handleCheckboxChange
})
);
@tkrotoff también puedes hacer esto:
React.Children.map(this.props.children, (child: number) => {
return child + 1
})
Esta y la solución sugerida solo aprovechan el hecho de que React.Children.map
no está fuertemente tipado. También podría haber usado any
lugar del tipo Checkbox
ya que no hay garantía de que ese sea el tipo de los hijos. Esto significa que es probable que tenga errores en tiempo de ejecución si alguien no utiliza el componente al pasar una cadena.
Qué tal esto:
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>
)
}
}
Que rendirá:
My Header!
Welcome
This is my lovely component with slots
github: <strong i="17">@variousauthors</strong>
Este enfoque aprovecha el tipo de información que _ tenemos_, que es que un ReactChild
podría ser un ReactElement
(he usado type
para detectar esto, pero podría ser más cuidado si quisieras). También podemos ser más descriptivos y elaborados que Slot
. Vi una biblioteca de UI implementar un patrón donde las clases tenían sus propias ranuras adjuntas. Algo como:
<Dropdown>
<Dropdown.Header>
<FancyIcon>My Header!</FancyIcon>
</Dropdown.Header>
{dropdownItems}
</Dropdown>
De esta forma, el usuario tiene claro el significado de cada ranura. El resto de los hijos (los que no se han analizado como ranuras) se dejan en una colección llamada children
y se representan a la cart, lo que permite al usuario seguir usando children
normalmente mientras se reserva un comportamiento especial para el ranuras personalizadas.
EDITAR: React aparentemente tiene un método React.isValidElement
que puede usar en lugar de mi isReactElement
.
EDITAR: Otra cosa que puede hacer es escribir la propiedad children
en su componente, de modo que un usuario solo pueda pasar las casillas de verificación como hijos. Esto ayudará a evitar esos errores en tiempo de ejecución.
Comentario más útil
Pregunta:
Solución: