ฉันควรใช้ React.cloneElement กับ this.props.children เมื่อใด


118

ฉันยังคงเป็น noob ที่ React และในหลาย ๆ ตัวอย่างบนอินเทอร์เน็ตฉันเห็นรูปแบบนี้ในการแสดงองค์ประกอบย่อยซึ่งฉันรู้สึกสับสน ปกติฉันจะเห็นสิ่งนี้:

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

แต่แล้วฉันก็เห็นตัวอย่างเช่นนี้:

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

ตอนนี้ฉันเข้าใจ api แล้ว แต่เอกสารไม่ชัดเจนว่าฉันควรจะใช้มันเมื่อไหร่

แล้วสิ่งหนึ่งที่ทำไม่ได้คืออะไร? ใครช่วยอธิบายเรื่องนี้ให้ฉันฟังด้วยตัวอย่างที่ดีกว่านี้ได้ไหม


3
youtube.com/watch?v=hEGg-3pIHlEผู้ชายคนนี้กำลังแสดงให้เห็นว่าเขาใช้ cloneElement อย่างไร ลองดูตัวอย่างบางส่วน
iurii

คำตอบ:


69

แก้ไข:

ดูคำตอบของ Vennesaแทนซึ่งเป็นคำอธิบายที่ดีกว่า

เดิม:

ก่อนอื่นReact.cloneElementตัวอย่างจะใช้ได้เฉพาะในกรณีที่บุตรหลานของคุณเป็นองค์ประกอบ React เดียว

เกือบทุกอย่าง{this.props.children}เป็นสิ่งที่คุณต้องการ การโคลนมีประโยชน์ในสถานการณ์ขั้นสูงบางสถานการณ์โดยที่ผู้ปกครองส่งองค์ประกอบเข้ามาและองค์ประกอบลูกต้องเปลี่ยนอุปกรณ์ประกอบฉากบางอย่างในองค์ประกอบนั้นหรือเพิ่มสิ่งต่างๆเช่นการอ้างอิงเพื่อเข้าถึงองค์ประกอบ DOM จริง

ในตัวอย่างด้านบนพาเรนต์ที่ให้ลูกไม่ทราบเกี่ยวกับข้อกำหนดหลักสำหรับส่วนประกอบดังนั้นจึงสร้างสำเนาขององค์ประกอบที่ได้รับและเพิ่มคีย์ตามตัวระบุเฉพาะบางอย่างในออบเจ็กต์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับคีย์ทำอะไร: https://facebook.github.io/react/docs/multiple-components.html


183

props.childrenไม่ใช่เด็กที่แท้จริง มันเป็นdescriptorของเด็ก ๆ ดังนั้นคุณจึงไม่มีอะไรเปลี่ยนแปลง คุณไม่สามารถเปลี่ยนอุปกรณ์ประกอบฉากหรือแก้ไขการทำงานใด ๆ read from itคุณสามารถเท่านั้น หากคุณต้องการทำการแก้ไขใด ๆ คุณต้องสร้างnew elementsโดยใช้React.CloneElementไฟล์.

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

ตัวอย่าง:

ฟังก์ชั่นการเรนเดอร์หลักของส่วนประกอบเช่นApp.js:

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

สมมติว่าคุณต้องเพิ่มonClickลูกแต่ละคนของParagraph; ดังนั้นParagraph.jsคุณสามารถทำได้:

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

จากนั้นคุณสามารถทำได้ง่ายๆ:

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

หมายเหตุ:React.Children.mapฟังก์ชั่นจะเห็นเฉพาะtop levelองค์ประกอบก็ไม่ได้เห็นใด ๆ ของสิ่งที่ทำให้องค์ประกอบเหล่านั้น; หมายความว่าคุณกำลังจัดหาอุปกรณ์ประกอบฉากโดยตรงให้กับเด็ก ๆ (ที่นี่คือ<Sentence />องค์ประกอบ) หากคุณต้องการอุปกรณ์ประกอบฉากที่จะผ่านลงไปอีกสมมติว่าคุณจะมี<div></div>หนึ่งภายในของ<Sentence />องค์ประกอบที่ต้องการใช้onClickไม้ค้ำยันแล้วในกรณีที่คุณสามารถใช้Context APIที่จะทำมัน ทำให้Paragraphผู้ให้และSentenceองค์ประกอบเป็นผู้บริโภค


11
นี่คือคำตอบที่ชัดเจนพร้อมตัวอย่างโลกแห่งความเป็นจริง ต้องการการโหวตเพิ่มขึ้น
SeaWarrior404

1
เห็นด้วยกับ @ SeaWarrior404 - ฉันเดาว่า OP กำลังมองหาการทำซ้ำในคอลเลกชันมากกว่าลูกคนเดียวเนื่องจากอินเทอร์เฟซผู้ใช้ของเขามี "ผู้ใช้" / พหูพจน์เป็นชื่อ ใช้React.Children.mapร่วมกับReact.cloneElementที่ @vennesa ชี้ให้เห็นมีประสิทธิภาพมาก
jakeforaker

23

ในความเป็นจริงไม่ได้เกี่ยวข้องอย่างเคร่งครัดReact.cloneElementthis.props.children

มีประโยชน์เมื่อใดก็ตามที่คุณต้องการโคลนองค์ประกอบปฏิกิริยา ( PropTypes.element) เพื่อเพิ่ม / ลบล้างอุปกรณ์ประกอบฉากโดยไม่ต้องการให้ผู้ปกครองมีความรู้เกี่ยวกับองค์ประกอบภายใน (เช่นการแนบตัวจัดการเหตุการณ์หรือการกำหนดkey/ refแอตทริบิวต์)

นอกจากนี้ยังตอบสนององค์ประกอบไม่เปลี่ยนรูป

React.cloneElement (องค์ประกอบ [อุปกรณ์ประกอบฉาก] [... เด็ก ๆ ]) เกือบจะเทียบเท่ากับ: <element.type {...element.props} {...props}>{children}</element.type>


อย่างไรก็ตามchildrenprop ใน React ถูกใช้โดยเฉพาะสำหรับการกักกัน (หรือที่เรียกว่าองค์ประกอบ ) จับคู่กับReact.ChildrenAPI และReact.cloneElementส่วนประกอบที่ใช้อุปกรณ์ประกอบฉากเด็ก ๆ สามารถจัดการตรรกะได้มากขึ้น (เช่นการเปลี่ยนสถานะเหตุการณ์การวัด DOM ฯลฯ ) ภายในในขณะที่ให้ส่วนการเรนเดอร์ ทุกที่ที่ใช้ React Router<switch/>หรือส่วนประกอบแบบผสม<select/>ก็เป็นตัวอย่างที่ดี

สิ่งสุดท้ายที่ควรกล่าวถึงคือองค์ประกอบปฏิกิริยาไม่ได้ จำกัด เฉพาะอุปกรณ์ประกอบฉากเด็ก ๆ

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

พวกเขาสามารถเป็นสิ่งที่อุปกรณ์ประกอบฉากที่ทำให้ความรู้สึกที่สำคัญคือการกำหนดสัญญาที่ดีสำหรับองค์ประกอบเพื่อให้ผู้บริโภคของมันสามารถหลุดพ้นจากรายละเอียดการดำเนินพื้นฐานโดยไม่คำนึงถึงไม่ว่าจะเป็นการใช้React.Children, หรือแม้กระทั่งReact.cloneElementReact.createContext

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.