Quando devo usar React.cloneElement vs this.props.children?


118

Ainda sou um novato no React e em muitos exemplos na internet, vejo essa variação na renderização de elementos filhos que considero confusa. Normalmente eu vejo isso:

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

Mas então vejo um exemplo como este:

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

Agora eu entendo a API, mas os documentos não deixam exatamente claro quando devo usá-la.

Então, o que um faz que o outro não pode? Alguém poderia me explicar isso com melhores exemplos?


3
youtube.com/watch?v=hEGg-3pIHlE esse cara está mostrando como ele usa cloneElement. Veja alguns exemplos
iurii

Respostas:


69

Editar:

Olhe para a resposta de Vennesa em vez disso, que é uma explicação melhor.

Original:

Em primeiro lugar, o React.cloneElementexemplo só funciona se seu filho for um único elemento React.

Pois quase tudo {this.props.children}é o que você deseja. A clonagem é útil em alguns cenários mais avançados, onde um pai envia um elemento e o componente filho precisa alterar alguns adereços nesse elemento ou adicionar coisas como ref para acessar o elemento DOM real.

No exemplo acima, o pai que fornece ao filho não sabe sobre o requisito de chave para o componente, portanto, ele cria uma cópia do elemento que é fornecido e adiciona uma chave com base em algum identificador único no objeto. Para obter mais informações sobre o que a chave faz: https://facebook.github.io/react/docs/multiple-components.html


183

props.childrennão são os filhos reais; É o descriptordos filhos. Então, você não tem realmente nada para mudar; você não pode alterar nenhum adereço ou editar qualquer funcionalidade; você só pode read from it. Se você precisar fazer qualquer modificação, deverá criar new elementsusando React.CloneElement.

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

Um exemplo:

função de renderização principal de um componente, como App.js:

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

agora, digamos que você precise adicionar um onClicka cada filho de Paragraph; então em seu Paragraph.jsvocê pode fazer:

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

então, simplesmente você pode fazer isso:

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

Nota: a React.Children.mapfunção verá apenas os top levelelementos, ela não verá nenhuma das coisas que esses elementos renderizam; o que significa que você está fornecendo os acessórios diretos para as crianças (aqui os <Sentence />elementos). Se você precisar que os adereços sejam passados ​​adiante, digamos que você tenha um <div></div>dentro de um dos <Sentence />elementos que deseja usar o onClickadereço, então, nesse caso, você pode usar o Context APIpara fazê-lo. Faça do Paragraphprovedor e dos Sentenceelementos como consumidor.


11
Esta é uma resposta clara com um exemplo do mundo real. Precisa de mais votos positivos.
SeaWarrior404 de

1
Concordo com @ SeaWarrior404 - Acho que o OP estava procurando iterar em uma coleção em vez de em um único filho, porque sua interface de usuário tem "Usuários" / plural como título. Usar React.Children.mapem conjunto com React.cloneElement@vennesa aponta, é muito poderoso
jakeforaker

23

Na verdade, React.cloneElementnão está estritamente associado this.props.children.

É útil sempre que você precisa clonar os elementos react ( PropTypes.element) para adicionar / sobrescrever props, sem querer que o pai tenha conhecimento sobre os componentes internos (por exemplo, anexar manipuladores de eventos ou atribuir key/ refatributos).

Além disso, os elementos reactivos são imutáveis .

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


No entanto, o childrenprop no React é especialmente usado para contenção (também conhecido como composição ), emparelhamento com React.ChildrenAPI e React.cloneElement, componente que usa props.children pode lidar com mais lógica (por exemplo, transições de estado, eventos, medições de DOM etc) internamente enquanto produz a parte de renderização para onde quer que seja usado, React Router <switch/>ou componente composto <select/>são alguns ótimos exemplos.

Uma última coisa que vale a pena mencionar é que os elementos de reação não se restringem a 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 />
      } />
  );
}

Eles podem ser o que adereços que faz sentido, a chave foi definir um contrato bom para o componente, de modo que os consumidores de que pode ser dissociado dos detalhes de implementação subjacentes, independentemente se ele está usando React.Children, React.cloneElementou até mesmo React.createContext.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.