Khi nào tôi nên sử dụng React.cloneElement so với this.props.children?


118

Tôi vẫn là một noob tại React và trong nhiều ví dụ trên internet, tôi thấy sự thay đổi này trong việc hiển thị các phần tử con mà tôi thấy khó hiểu. Thông thường tôi thấy điều này:

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

Nhưng sau đó tôi thấy một ví dụ như thế này:

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

Bây giờ tôi hiểu api nhưng tài liệu không nói rõ chính xác khi nào tôi nên sử dụng nó.

Vậy cái nào làm được cái kia không làm được? Ai đó có thể giải thích điều này cho tôi với các ví dụ tốt hơn không?


3
youtube.com/watch?v=hEGg-3pIHlE anh chàng này đang chỉ cách anh ta sử dụng cloneElement. Hãy kiểm tra này cho một số ví dụ
iurii

Câu trả lời:


69

Biên tập:

Thay vào đó, hãy nhìn vào câu trả lời của Vennesa , đó là một lời giải thích tốt hơn.

Nguyên:

Trước hết, React.cloneElementví dụ này chỉ hoạt động nếu con của bạn là một phần tử React duy nhất.

Vì hầu hết mọi thứ đều {this.props.children}là thứ bạn muốn. Nhân bản hữu ích trong một số trường hợp nâng cao hơn, trong đó cha mẹ gửi một phần tử vào và thành phần con cần thay đổi một số đạo cụ trên phần tử đó hoặc thêm những thứ như ref để truy cập phần tử DOM thực.

Trong ví dụ trên, phần tử cấp cho con không biết về yêu cầu khóa đối với thành phần, do đó, nó tạo một bản sao của phần tử mà nó được cung cấp và thêm khóa dựa trên một số định danh duy nhất trong đối tượng. Để biết thêm thông tin về chức năng của khóa: https://facebook.github.io/react/docs/multiple-components.html


183

props.childrenkhông phải là những đứa trẻ thực sự; Nó là descriptorcủa những đứa trẻ. Vì vậy, bạn thực sự không có bất cứ điều gì để thay đổi; bạn không thể thay đổi bất kỳ đạo cụ nào hoặc chỉnh sửa bất kỳ chức năng nào; bạn chỉ có thể read from it. Nếu bạn cần thực hiện bất kỳ sửa đổi nào, bạn phải tạo new elementsbằng cách sử dụng React.CloneElement.

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

Một ví dụ:

chức năng kết xuất chính của một thành phần như App.js:

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

bây giờ giả sử bạn cần thêm một onClickvào mỗi con của Paragraph; vì vậy Paragraph.jsbạn có thể làm:

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

thì chỉ cần bạn có thể làm điều này:

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

Lưu ý: các React.Children.mapchức năng sẽ chỉ nhìn thấy top levelcác yếu tố, nó không nhìn thấy bất kỳ trong những điều mà những yếu tố hiển thị; nghĩa là bạn đang cung cấp đạo cụ trực tiếp cho trẻ em (ở đây là các <Sentence />yếu tố). Nếu bạn cần các đạo cụ được truyền thêm, giả sử bạn sẽ có <div></div>bên trong một trong những <Sentence />yếu tố muốn sử dụng phương tiện onClickđó thì trong trường hợp đó, bạn có thể sử dụng Context APIđể làm điều đó. Làm cho Paragraphnhà cung cấp và các Sentencephần tử là người tiêu dùng.


11
Đây là một câu trả lời rõ ràng với một ví dụ trong thế giới thực. Nó cần nhiều lượt ủng hộ hơn.
SeaWarrior404

1
Đồng ý với @ SeaWarrior404 - Tôi đoán OP đang tìm cách lặp lại một bộ sưu tập hơn là một phần tử con vì giao diện người dùng của anh ấy có tiêu đề là "Users" / số nhiều. Sử dụng React.Children.mapkết hợp với React.cloneElementnhư @vennesa đã chỉ ra, rất mạnh mẽ
jakeforaker 09/09

23

Trong thực tế, React.cloneElementkhông phải là hoàn toàn liên kết với this.props.children.

Nó hữu ích bất cứ khi nào bạn cần sao chép các phần tử phản ứng ( PropTypes.element) để thêm / ghi đè các đạo cụ mà không muốn cha mẹ có kiến ​​thức về các phần tử bên trong thành phần đó (ví dụ: đính kèm trình xử lý sự kiện hoặc gán key/ refthuộc tính).

Ngoài ra các phần tử phản ứng là bất biến .

React.cloneElement (element, [props], [... children]) gần như tương đương với: <element.type {...element.props} {...props}>{children}</element.type>


Tuy nhiên, childrenprop trong React đặc biệt được sử dụng để chứa (hay còn gọi là thành phần ), ghép nối với React.ChildrenAPI và React.cloneElement, thành phần sử dụng đạo cụ. Bất cứ nơi nào nó được sử dụng, React Router <switch/>hoặc thành phần phức hợp <select/>là một số ví dụ tuyệt vời.

Một điều đáng nói cuối cùng là các yếu tố phản ứng không bị giới hạn ở các đạo cụ. Trẻ em.

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

Họ có thể là bất cứ điều gì đạo cụ có ý nghĩa, chìa khóa là để xác định một hợp đồng tốt cho thành phần, do đó người tiêu dùng của nó có thể được tách riêng từ những chi tiết thực hiện cơ bản, bất kể cho dù đó là sử dụng React.Children, React.cloneElementhoặc thậm chí React.createContext.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.