Kiedy powinienem używać React.cloneElement, a kiedy this.props.children?


118

Nadal jestem noobem w React i w wielu przykładach w Internecie widzę tę różnicę w renderowaniu elementów potomnych, co jest dla mnie mylące. Zwykle widzę to:

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

Ale potem widzę taki przykład:

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

Teraz rozumiem api, ale doktorzy nie wyjaśniają dokładnie, kiedy powinienem go używać.

Więc co robi jedno, czego drugie nie może? Czy ktoś mógłby mi to wyjaśnić lepszymi przykładami?


3
youtube.com/watch?v=hEGg-3pIHlE ten facet pokazuje, jak używa cloneElement. Sprawdź to, aby zobaczyć kilka przykładów
iurii

Odpowiedzi:


69

Edytować:

Spójrz na odpowiedź Vennesa za Zamiast tego, które jest lepsze wyjaśnienie.

Oryginalny:

Po pierwsze, React.cloneElementprzykład działa tylko wtedy, gdy Twoje dziecko jest pojedynczym elementem React.

Bo prawie wszystko {this.props.children}jest tym, czego chcesz. Klonowanie jest przydatne w niektórych bardziej zaawansowanych scenariuszach, w których rodzic wysyła element, a komponent potomny musi zmienić pewne właściwości tego elementu lub dodać takie rzeczy, jak ref, aby uzyskać dostęp do rzeczywistego elementu DOM.

W powyższym przykładzie rodzic, który przekazuje dziecku, nie wie o wymaganiu klucza dla komponentu, dlatego tworzy kopię podanego elementu i dodaje klucz na podstawie jakiegoś unikalnego identyfikatora w obiekcie. Aby uzyskać więcej informacji na temat tego, co robi klucz: https://facebook.github.io/react/docs/multiple-components.html


183

props.childrennie są rzeczywistymi dziećmi; To jest descriptorsprawa dzieci. Więc właściwie nie masz nic do zmiany; nie możesz zmieniać żadnych właściwości ani edytować żadnych funkcji; możesz tylko read from it. Jeśli chcesz wprowadzić jakieś modyfikacje, musisz je utworzyć new elementsza pomocą React.CloneElement.

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

Przykład:

główna funkcja renderowania komponentu, taka jak App.js:

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

teraz powiedzmy, że musisz dodać onClickdo każdego dziecka z Paragraph; więc w swoim Paragraph.jsmożesz zrobić:

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

możesz po prostu zrobić to:

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

Uwaga:React.Children.map funkcja będzie zobaczyć tylko top levelelementy, nie widzi żadnej z rzeczy, że te elementy czynią; co oznacza, że ​​udostępniasz bezpośrednie rekwizyty dzieciom (tutaj <Sentence />elementy). Jeśli chcesz, aby rekwizyty były przekazywane dalej, powiedzmy, że masz <div></div>wewnątrz jeden z <Sentence />elementów, który chce użyć onClickrekwizytu, wtedy w takim przypadku możesz użyć, Context APIaby to zrobić. Niech Paragraphdostawca i Sentenceelementy będą konsumentami.


11
To jasna odpowiedź na przykładzie prawdziwego świata. Potrzebuje więcej głosów poparcia.
SeaWarrior404

1
Zgadzam się z @ SeaWarrior404 - wydaje mi się, że OP szukał iteracji nad kolekcją, a nie pojedynczym dzieckiem, ponieważ jego interfejs użytkownika ma w tytule „Users” / liczba mnoga. Używanie React.Children.mapw połączeniu z React.cloneElementas @vennesa wskazuje, jest bardzo potężne
Jakeforaker

23

W rzeczywistości React.cloneElementnie jest ściśle powiązany z this.props.children.

Jest to przydatne, gdy trzeba sklonować elementy reagujące ( PropTypes.element), aby dodać / nadpisać właściwości, bez potrzeby, aby rodzic miał wiedzę o tych elementach wewnętrznych (np. Dołączanie programów obsługi zdarzeń lub przypisywanie key/ refatrybuty).

Również elementy reakcji są niezmienne .

React.cloneElement (element, [props], [... children]) jest prawie równoważne z: <element.type {...element.props} {...props}>{children}</element.type>


Jednak childrenprop w React jest szczególnie używany do zawierania (aka kompozycji ), parowania z React.ChildrenAPI i React.cloneElementkomponentu, który używa właściwości. Dzieci mogą obsługiwać więcej logiki (np. Przejścia stanów, zdarzenia, pomiary DOM itp.) Wewnętrznie, podczas oddawania części renderującej do Gdziekolwiek jest używany, React Router <switch/>lub komponent złożony <select/>są świetnymi przykładami.

Ostatnią rzeczą, o której warto wspomnieć, jest to, że elementy reagujące nie są ograniczone do rekwizytów dzieci.

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

Mogą być cokolwiek rekwizyty, które ma sens, kluczowe było określenie umowę dobre dla komponentu tak, że konsumenci z niej może być oddzielona od szczegółów implementacji bazowych, niezależnie czy to za pomocą React.Children, React.cloneElementlub nawet React.createContext.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.