Quando dovrei usare React.cloneElement contro this.props.children?


118

Sono ancora un noob in React e in molti esempi su Internet, vedo questa variazione nel rendering di elementi figlio che trovo confusi. Normalmente vedo questo:

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

Ma poi vedo un esempio come questo:

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

Ora capisco l'API ma i documenti non chiariscono esattamente quando dovrei usarlo.

Allora cosa fa uno che l'altro non può fare? Qualcuno potrebbe spiegarmelo con esempi migliori?


3
youtube.com/watch?v=hEGg-3pIHlE questo ragazzo sta mostrando come usa cloneElement.
Dai

Risposte:


69

Modificare:

Guarda invece la risposta di Vennesa , che è una spiegazione migliore.

Originale:

Prima di tutto, l' React.cloneElementesempio funziona solo se tuo figlio è un singolo elemento React.

Perché quasi tutto {this.props.children}è quello che vuoi. La clonazione è utile in alcuni scenari più avanzati, in cui un genitore invia un elemento e il componente figlio deve modificare alcuni oggetti di scena su quell'elemento o aggiungere cose come ref per accedere all'elemento DOM effettivo.

Nell'esempio sopra, il genitore che dà al figlio non conosce il requisito della chiave per il componente, quindi crea una copia dell'elemento che gli viene dato e aggiunge una chiave basata su un identificatore univoco nell'oggetto. Per maggiori informazioni su cosa fa la chiave: https://facebook.github.io/react/docs/multiple-components.html


183

props.childrennon sono i bambini veri; È descriptoril regno dei bambini. Quindi non hai davvero nulla da cambiare; non puoi cambiare alcun oggetto di scena o modificare alcuna funzionalità; puoi solo read from it. Se è necessario apportare modifiche, è necessario creare new elementsutilizzando React.CloneElement.

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

Un esempio:

funzione di rendering principale di un componente come App.js:

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

ora diciamo che devi aggiungere un onClicka ogni figlio di Paragraph; quindi nel tuo Paragraph.jspuoi fare:

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

quindi semplicemente puoi farlo:

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

Nota: la React.Children.mapfunzione vedrà solo gli top levelelementi, non vede nessuna delle cose che quegli elementi rendono; significa che stai fornendo gli oggetti di scena diretti ai bambini (qui gli <Sentence />elementi). Se hai bisogno che gli oggetti di scena vengano tramandati ulteriormente, diciamo che avrai <div></div>uno degli <Sentence />elementi interni che vogliono usare l' onClickelica, quindi in quel caso puoi usare Context APIper farlo. Rendi il Paragraphfornitore e gli Sentenceelementi come consumatori.


11
Questa è una risposta chiara con un esempio del mondo reale. Ha bisogno di più voti positivi.
SeaWarrior404

1
D'accordo con @ SeaWarrior404 - Immagino che l'OP stesse cercando di iterare su una raccolta piuttosto che su un singolo figlio perché la sua interfaccia utente ha "Users" / plurale come titolo. L'uso React.Children.mapin combinazione con React.cloneElementcome sottolinea @vennesa, è molto potente
jakeforaker

23

In effetti, React.cloneElementnon è strettamente associato a this.props.children.

È utile ogni volta che è necessario clonare gli elementi react ( PropTypes.element) per aggiungere / sovrascrivere gli oggetti di scena, senza che il genitore abbia la conoscenza di quei componenti interni (ad esempio, allegando gestori di eventi o assegnando key/ refattributi).

Anche gli elementi di reazione sono immutabili .

React.cloneElement (element, [props], [... children]) è quasi equivalente a: <element.type {...element.props} {...props}>{children}</element.type>


Tuttavia, l' childrenelica in React è particolarmente utilizzata per il contenimento (ovvero la composizione ), l'accoppiamento con l' React.ChildrenAPI e React.cloneElement, il componente che utilizza props. I bambini possono gestire più logica (ad esempio, transizioni di stato, eventi, misurazioni DOM ecc.) Internamente cedendo la parte di rendering a ovunque sia utilizzato, React Router <switch/>o un componente composto <select/>sono alcuni ottimi esempi.

Un'ultima cosa che vale la pena menzionare è che gli elementi di reazione non sono limitati agli oggetti di scena.

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

Possono essere qualunque oggetti di scena che ha un senso, la chiave era quello di definire un contratto buono per il componente, in modo che i consumatori di esso possono essere disaccoppiati dai sottostanti dettagli di implementazione, a prescindere che si tratti di utilizzare React.Children, React.cloneElemento addirittura React.createContext.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.