Kapan saya harus menggunakan React.cloneElement vs this.props.children?

118

Saya masih pemula di React dan dalam banyak contoh di internet, saya melihat variasi dalam merender elemen anak yang menurut saya membingungkan. Biasanya saya melihat ini:

class Users extends React.Component {
  render() {
    return (
      <div>
        <h2>Users</h2>
        {this.props.children}
      </div>
    )
  }
}

Tapi kemudian saya melihat contoh seperti ini:

<ReactCSSTransitionGroup
     component="div"
     transitionName="example"
     transitionEnterTimeout={500}
     transitionLeaveTimeout={500}
     >
     {React.cloneElement(this.props.children, {
       key: this.props.location.pathname
      })}
</ReactCSSTransitionGroup>

Sekarang saya mengerti api tetapi dokumen tidak menjelaskan dengan jelas kapan saya harus menggunakannya.

Jadi apa yang dilakukan yang satu dan yang lain tidak bisa? Bisakah seseorang menjelaskan hal ini kepada saya dengan contoh yang lebih baik?

Amit Erandole
sumber
3
youtube.com/watch?v=hEGg-3pIHlE orang ini menunjukkan cara dia menggunakan cloneElement. Lihat ini untuk beberapa contoh
iurii

Jawaban:

69

Edit:

Lihatlah jawaban Vennesa sebagai gantinya, yang merupakan penjelasan yang lebih baik.

Asli:

Pertama-tama, React.cloneElementcontoh hanya berfungsi jika anak Anda adalah satu elemen React.

Karena hampir semuanya {this.props.children}adalah yang Anda inginkan. Kloning berguna dalam beberapa skenario lanjutan, di mana induk mengirimkan elemen dan komponen turunan perlu mengubah beberapa props pada elemen itu atau menambahkan hal-hal seperti ref untuk mengakses elemen DOM yang sebenarnya.

Dalam contoh di atas, orang tua yang memberi anak tidak tahu tentang persyaratan kunci untuk komponen tersebut, oleh karena itu ia membuat salinan dari elemen yang diberikan dan menambahkan kunci berdasarkan beberapa pengenal unik di objek. Untuk info lebih lanjut tentang fungsi kunci: https://facebook.github.io/react/docs/multiple-components.html

Morten Olsen
sumber
183

props.childrenbukan anak-anak yang sebenarnya; Itu adalah descriptoranak-anak. Jadi, sebenarnya Anda tidak perlu mengubah apa pun; Anda tidak dapat mengubah properti apa pun, atau mengedit fungsionalitas apa pun; kamu hanya bisa read from it. Jika Anda perlu membuat modifikasi, Anda harus membuat new elementsmenggunakan React.CloneElement.

https://egghead.io/lessons/react-use-react-cloneelement-to-extend-functionality-of-children-components

Sebuah contoh:

fungsi render utama dari sebuah komponen seperti App.js:

render() {   
    return(
            <Paragraph>
              <Sentence>First</Sentence>
              <Sentence>Second</Sentence>
              <Sentence>Third</Sentence>
            </Paragraph>   
    ) 
}

sekarang katakanlah Anda perlu menambahkan an onClickke setiap anak dari Paragraph; jadi di dalam dirimu Paragraph.jskamu bisa melakukan:

render() {
        return (
          <div>
          {React.Children.map(this.props.children, child => {
            return React.cloneElement(child, {
              onClick: this.props.onClick })   
         })}
         </div>
       ) 
}

maka cukup Anda dapat melakukan ini:

render() {   
  return(
        <Paragraph onClick={this.onClick}>
          <Sentence>First</Sentence>
          <Sentence>Second</Sentence>
          <Sentence>Third</Sentence>
        </Paragraph>   
   ) 
}

Catatan: satu React.Children.mapfungsi hanya akan melihat top levelelemen, tidak melihat salah satu hal yang unsur-unsur render; artinya Anda menyediakan alat peraga langsung kepada anak-anak (di sini <Sentence />elemennya). Jika Anda membutuhkan props untuk diturunkan lebih jauh, katakanlah Anda akan memiliki bagian <div></div>dalam salah satu <Sentence />elemen yang ingin menggunakan onClickprop maka dalam hal ini Anda dapat menggunakan Context APIto untuk melakukannya. Jadikan Paragraphpenyedia dan Sentenceelemen sebagai konsumen.

Vennesa
sumber
11
Ini adalah jawaban yang jelas dengan contoh dunia nyata. Ini membutuhkan lebih banyak suara positif.
SeaWarrior404
1
Setuju dengan @ SeaWarrior404 - Saya kira OP ingin mengulang koleksi daripada satu anak karena antarmuka penggunanya memiliki "Users" / jamak sebagai judulnya. Menggunakan React.Children.mapbersama dengan React.cloneElementseperti yang ditunjukkan @vennesa, sangat kuat
jakeforaker
23

Faktanya, React.cloneElementtidak sepenuhnya terkait dengan this.props.children.

Ini berguna setiap kali Anda perlu mengkloning elemen react ( PropTypes.element) untuk menambah / mengganti props, tanpa ingin orang tua memiliki pengetahuan tentang internal komponen tersebut (misalnya, melampirkan penangan kejadian atau penugasan key/ refatribut).

Juga elemen reaksi tidak dapat diubah .

React.cloneElement (element, [props], [... children]) hampir setara dengan: <element.type {...element.props} {...props}>{children}</element.type>


Namun, childrenprop di React secara khusus digunakan untuk penahanan (alias komposisi ), berpasangan dengan React.ChildrenAPI dan React.cloneElement, komponen yang menggunakan props.children dapat menangani lebih banyak logika (misalnya, transisi status, peristiwa, pengukuran DOM, dll) secara internal sambil menghasilkan bagian rendering ke dimanapun itu digunakan, React Router <switch/>atau komponen gabungan <select/>adalah beberapa contoh yang bagus.

Satu hal terakhir yang perlu disebutkan adalah bahwa elemen react tidak terbatas pada props.children.

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

Mereka bisa menjadi alat peraga apapun yang masuk akal, kuncinya adalah untuk menentukan kontrak baik untuk komponen, sehingga konsumen dapat dipisahkan dari rincian yang mendasari pelaksanaan, terlepas apakah itu menggunakan React.Children, React.cloneElementatau bahkan React.createContext.

Xlee
sumber