Definitelytyped: Se necesitan ejemplos de React.Children.map () y React.cloneElement ()

Creado en 26 oct. 2016  ·  8Comentarios  ·  Fuente: DefinitelyTyped/DefinitelyTyped

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)

  • ¿Cómo escribir this.props.children ?
  • ¿Cómo escribir React.cloneElement() ?
  • ¿Cómo escribir 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

Comentario más útil

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

Todos 8 comentarios

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.

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.

¿Fue útil esta página
0 / 5 - 0 calificaciones