Definitelytyped: Butuh contoh React.Children.map() dan React.cloneElement()

Dibuat pada 26 Okt 2016  ·  8Komentar  ·  Sumber: DefinitelyTyped/DefinitelyTyped

React.Children.map() tidak ada contoh yang bagus , saya tidak mengerti cara mengetiknya:

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

(contoh yang sangat umum, lihat http://stackoverflow.com/a/32371612/990356 )

  • Bagaimana cara mengetik this.props.children ?
  • Bagaimana cara mengetik React.cloneElement() ?
  • Bagaimana cara mengetik React.Children.map() ?

Sebagian besar waktu saya berakhir dengan kesalahan berikut: Type 'string' is not assignable to type 'ReactElement<any>' , lihat #8131

Komentar yang paling membantu

Pertanyaan:

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

Larutan:

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

Semua 8 komentar

silakan kirim permintaan tarik. Saya akan mengulasnya.

@vvakame Saya tidak bisa, saya tidak mengerti cara kerjanya

saya juga. silakan membuat percakapan dengan penulis definisi.

Anda harus mengetik-beranotasi atau mengetik-menegaskan checkbox secara eksplisit karena tidak ada jaminan bahwa this.props.children tidak berisi nilai non-ReactElement. Misalnya:

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

@vsiao terima kasih banyak, berhasil!

Pertanyaan:

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

Larutan:

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

@tkrotoff Anda juga bisa melakukan ini:

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

Ini dan solusi yang disarankan hanya memanfaatkan fakta bahwa React.Children.map tidak diketik dengan kuat. Anda mungkin juga telah menggunakan any alih-alih tipe Checkbox karena tidak ada jaminan bahwa itu akan menjadi tipe anak-anak. Ini berarti Anda mungkin mengalami kesalahan runtime jika ada yang salah menggunakan komponen dengan meneruskan string.

Bagaimana dengan ini:

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

Yang akan membuat:

My Header!
Welcome
This is my lovely component with slots

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

Pendekatan ini mengambil keuntungan dari jenis informasi yang kami _do_ miliki, yaitu bahwa ReactChild mungkin menjadi ReactElement (Saya telah menggunakan type untuk mendeteksi ini, tetapi Anda bisa saja lebih berhati-hati jika Anda mau). Kita juga bisa lebih deskriptif dan mengelaborasi bahwa Slot . Saya melihat perpustakaan UI menerapkan pola di mana kelas memiliki slotnya sendiri. Sesuatu seperti:

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

Dengan cara ini pengguna jelas tentang arti dari setiap slot. Anak-anak lainnya (yang tidak diurai sebagai slot) dibiarkan dalam koleksi yang disebut children dan dirender a la cart, memungkinkan pengguna untuk tetap menggunakan children normal sambil memesan perilaku khusus untuk slot kustom.

EDIT: React tampaknya memiliki metode React.isValidElement yang dapat Anda gunakan sebagai pengganti isReactElement kustom saya.

EDIT: Hal lain yang dapat Anda lakukan adalah mengetikkan properti children pada komponen Anda, sehingga pengguna hanya diizinkan untuk memasukkan Kotak Centang sebagai anak-anak. Ini akan membantu menghindari kesalahan runtime tersebut.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat