Wyszukaj / o blogu

React: kompozycja

Opublikowano sob 29 sierpnia 2020 w reactjs • 2 min read

react-kompozycja

props.children pozwala nam na tworzenie komponentów otwartych na uzupełniania nowym kodem, wystarczy wykorzystać {props.children} w ramach komponentu aby wskazać, w którym miejscu istnieje możliwość uzupełnienia/wstawienia kodu

Komponent otwarty na ew. rozszerzenia o nową treść

function TestComposition(props) {
  let {children} = props;
  return (<div>
      <h1>Test Kompozycji</h1>
      {children}
      <h2>Konice testu kompozycji</h2>
    </div>
    )
}


function App() {
  return (
    <TestComposition>
      <h3>Element będący zagnieżdżoną treścią</h3>
      <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa, eum!</p>
    </TestComposition>
  )
}


ReactDOM.render(
  <App/>,
  document.getElementById("app")
);

W efekcie tego powstanie

<div>

  <h1>Test Kompozycji</h1>

  <h3>Element będący zagnieżdżoną treścią</h3>

  <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Culpa, eum!</p>

  <h2>Konice testu kompozycji</h2>

</div>

props.children może wyrenderować inny komponent przyjęty w propsie.

Powyższy przykład, może wyglądać również w poniższy sposób

function TestComposition(props) {
  let {children} = props;
  return (<div>
      <h1>Test Kompozycji</h1>
      {children}
      <h2>Konice testu kompozycji</h2>
    </div>
    )
}

function ChildComponent() {
  return (
    <h3>Element będący zagnieżdżonym dzieckiem</h3>
  )
}

function App() {
  return (
    <TestComposition children={<ChildComponent/>}/>
  )
}


ReactDOM.render(
  <App/>,
  document.getElementById("app")
);

A co jeśli zależy nam na tym aby dany komponent był w stanie przyjąć wiele innych komponentów lub inaczej rzecz ujmując mieć możliwość wypełnienia wielu luk. W tym przypadku należy zastosować odrębne nazewnictwo dla każdego fragmentu/luki, który ma być uzupełniony a następnie przekazać go w odpowiedni sposób w props.

function TestComposition(props) {
  let {child1, child2} = props;
  return (<div>
      <h1>Test Kompozycji</h1>
      {child1}
      {child2}
      <h2>Konice testu kompozycji</h2>
    </div>
    )
}

function ChildComponent({text}) {
  return (
    <h3>Element będący zagnieżdżonym {text}</h3>
  )
}

function App() {
  return (
    <TestComposition child1={<ChildComponent text='dzieckiem-1'/>} child2={<ChildComponent text='dzieckiem-2'/>}/>
  )
}


ReactDOM.render(
  <App/>,
  document.getElementById("app")
);

W efekcie tego powstanie

<div>
  <h1>Test Kompozycji</h1>

  <h3>Element będący zagnieżdżonym dzieckiem-1</h3>

  <h3>Element będący zagnieżdżonym dzieckiem-2</h3>

  <h2>Konice testu kompozycji</h2>

</div>

Ominięcie prop-drilling wykorzystując kompozycję oraz props.children

Przekazywanie propsów do elementu liściowego z pominięciem pośredników (lub tzw. prop-drilling -> gdzie dane w postaci propsów są przekazywane przez komponenty które, z nich faktycznie nie korzystają) może odbyć się poprzez wykorzystanie props.children. Wymaga to jednak otwartości poprzednich komponentów na możliwość (włączenia) wywołania w nich dzeci.

function TestComposition({children,i}) {

  return (
    <div className='testComposition' key={i}>
      <h2>Beginning o parent component</h2>
      {children}
      <h2>End of parent component</h2>
      <p>--------------------</p>
    </div>
    )
}

function ChildComponent({children}) {
  return (
    <div className='childComponent'>
      <h3>Beginning o child component</h3>
      {children}
      <h3>End of child component</h3>
    </div>
  )
}

function GrandChild({text}) {
  return (
    <h3 className='grandChild'>{text}</h3>
  )
}

function App({grandChildren}) {
  return (
    grandChildren.map((elem,i)=>
      <TestComposition id={i}>
        <ChildComponent>
          <GrandChild text={elem}/>
        </ChildComponent>
      </TestComposition>  
    )
  )
}


ReactDOM.render(
  <App grandChildren = {['Grand Child 1', 'Grand Child 2', 'Grand Child 3']}/>,
  document.getElementById("app")
);

W wyniku tego powstanie:

<div id="app">

  <div id="app"><div class="testComposition">
    <h2>Beginning o parent component</h2>
    <div class="childComponent">
      <h3>Beginning o child component</h3>
        <h3 class="grandChild">Grand Child 1</h3>
      <h3>End of child component</h3>
    </div>
    <h2>End of parent component</h2>
    <p>--------------------</p>
  </div>

  <div class="testComposition">
    <h2>Beginning o parent component</h2>
    <div class="childComponent">
      <h3>Beginning o child component</h3>
        <h3 class="grandChild">Grand Child 2</h3>
      <h3>End of child component</h3>
    </div>
    <h2>End of parent component</h2>
    <p>--------------------</p>
  </div>


  <div class="testComposition">
    <h2>Beginning o parent component</h2>
    <div class="childComponent">
      <h3>Beginning o child component</h3>
        <h3 class="grandChild">Grand Child 3</h3>
      <h3>End of child component</h3>
    </div>
    <h2>End of parent component</h2>
    <p>--------------------</p>
  </div>

</div>

Źródła:

Kompozycja vs dziedziczenie - Wzorce w React #3

Thinking in React: Component Composition

How To Avoid Prop Drilling in React Using Component Composition