Wann sollte ich React.cloneElement vs this.props.children verwenden?

118

Ich bin immer noch ein Neuling bei React und in vielen Beispielen im Internet sehe ich diese Variation beim Rendern von untergeordneten Elementen, die ich verwirrend finde. Normalerweise sehe ich das:

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

Aber dann sehe ich ein Beispiel wie dieses:

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

Jetzt verstehe ich die API, aber die Dokumente machen nicht genau klar, wann ich sie verwenden sollte.

Was macht einer, was der andere nicht kann? Könnte mir das jemand mit besseren Beispielen erklären?

Amit Erandole
quelle
3
youtube.com/watch?v=hEGg-3pIHlE Dieser Typ zeigt, wie er cloneElement verwendet. Schauen Sie sich dies für einige Beispiele an
iurii

Antworten:

69

Bearbeiten:

Schauen Sie sich stattdessen Vennesas Antwort an, was eine bessere Erklärung ist.

Original:

Erstens React.cloneElementfunktioniert das Beispiel nur, wenn Ihr Kind ein einzelnes React-Element ist.

Denn fast alles {this.props.children}ist das, was Sie wollen. Das Klonen ist in einigen fortgeschritteneren Szenarien nützlich, in denen ein übergeordnetes Element ein Element einsendet und die untergeordnete Komponente einige Requisiten für dieses Element ändern oder Dinge wie ref für den Zugriff auf das eigentliche DOM-Element hinzufügen muss.

Im obigen Beispiel weiß das übergeordnete Element, das das untergeordnete Element angibt, nichts über die Schlüsselanforderung für die Komponente. Daher erstellt es eine Kopie des angegebenen Elements und fügt einen Schlüssel hinzu, der auf einer eindeutigen Kennung im Objekt basiert. Weitere Informationen zu den Funktionen des Schlüssels: https://facebook.github.io/react/docs/multiple-components.html

Morten Olsen
quelle
183

props.childrensind nicht die eigentlichen Kinder; Es ist das descriptorder Kinder. Sie haben also eigentlich nichts zu ändern; Sie können keine Requisiten ändern oder Funktionen bearbeiten. du kannst nur read from it. Wenn Sie Änderungen vornehmen müssen Sie erstellen new elementsmit React.CloneElement.

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

Ein Beispiel:

Hauptrenderfunktion einer Komponente wie App.js:

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

Nehmen wir jetzt an, Sie müssen onClickjedem Kind von ein hinzufügen Paragraph. So können Paragraph.jsSie in Ihrem tun:

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

dann können Sie einfach Folgendes tun:

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

Hinweis: Die React.Children.mapFunktion sieht nur die top levelElemente. Sie sieht nichts, was diese Elemente rendern. Dies bedeutet, dass Sie die direkten Requisiten für Kinder bereitstellen (hier die <Sentence />Elemente). Wenn Sie möchten, dass die Requisiten weiter weitergegeben werden, nehmen wir an, Sie haben ein <div></div>inneres <Sentence />Element, das die onClickRequisite verwenden möchte. In diesem Fall können Sie das verwenden, Context APIum dies zu tun. Machen Sie den ParagraphAnbieter und die SentenceElemente zum Verbraucher.

Vennesa
quelle
11
Dies ist eine klare Antwort mit einem Beispiel aus der Praxis. Es braucht mehr Upvotes.
SeaWarrior404
1
Stimme @ SeaWarrior404 zu - Ich würde vermuten, dass das OP versucht hat, über eine Sammlung und nicht über ein einzelnes Kind zu iterieren, da seine Benutzeroberfläche "Benutzer" / Plural als Titel hat. Die Verwendung React.Children.mapin Verbindung mit, React.cloneElementwie @vennesa hervorhebt, ist sehr mächtig
jakeforaker
23

In der Tat React.cloneElementist nicht streng mit verbunden this.props.children.

Dies ist immer dann nützlich, wenn Sie React Elements ( PropTypes.element) klonen müssen, um Requisiten hinzuzufügen / zu überschreiben, ohne dass der Elternteil Kenntnisse über diese Komponenteninternale haben soll (z. B. Anhängen von Ereignishandlern oder Zuweisen von key/ refAttributen).

Auch Reaktionselemente sind unveränderlich .

React.cloneElement (Element, [Requisiten], [... Kinder]) entspricht fast: <element.type {...element.props} {...props}>{children}</element.type>


Die childrenRequisite in React wird jedoch speziell für die Eindämmung (auch als Komposition bezeichnet ), die Kopplung mit der React.ChildrenAPI und für React.cloneElementKomponenten verwendet , die Requisiten verwenden. Kinder können intern mehr Logik (z. B. Zustandsübergänge, Ereignisse, DOM-Messungen usw.) verarbeiten, während der Rendering-Teil an ausgegeben wird Überall dort, wo es verwendet wird, sind React Router <switch/>oder Compound-Komponenten <select/>einige gute Beispiele.

Eine letzte erwähnenswerte Sache ist, dass Reaktionselemente nicht auf Requisiten beschränkt sind.

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

Sie können , was Requisiten , die Sinn macht, ist der Schlüssel war ein guter Vertrag für die Komponente zu definieren, so dass die Verbraucher davon kann aus den zugrunde liegenden Implementierungsdetails entkoppelt werden, unabhängig davon , ob es mit React.Children, React.cloneElementoder sogar React.createContext.

Xlee
quelle