Как передать несколько дочерних элементов для компонентов React со слотами

внешний интерфейс Программа перевода самородков Vue.js React.js

Предположим, вам нужно написать повторно используемый компонент. Тем не менее, называетсяchildrenОпора не отвечает этому требованию. Этот компонент должен быть способен приниматьбольше, чем одиндетей, причем размещение этих детей не по соседству, а по заявке.

Вы можете написать это с заголовком, боковой панелью и блоком контента под названиемLayoutс компонент. Или вы пишете с левой и правой динамической боковой панелью.NavBarкомпоненты.

Все вышеперечисленные задачи можно легко выполнить с помощью шаблона «слоты», другими словами, передав JSX в реквизит.

резюме: вы можете передать JSX вЛюбыевместо того, чтобы просто позвонитьchildrenПоддержка компонента не ограничивается встраиванием JSX в тег компонента, чтобы упростить передачу данных, но также сделать компонент более ценным для повторного использования.

Краткий обзор Children in React

Начнем с того, что React позволяет вкладывать теги JSX.childrenпуть к компонентуchildren. Эти элементы (ноль, один или несколько) будут названы в этом компонентеchildrenсуществует в виде реквизита. Имя реакцииchildrenОпора является эквивалентом Angular, трансклюзия там Vue<slot>.

ВотButtonПример компонента, передающего дочерние элементы:

<Button>
  <Icon name="dollars"/>
  <span>BUY NOW</span>
</Button>

Давайте подробно рассмотримButtonРеализация этого компонента и посмотрите, что он делает с детьми:

function Button(props) {
    return (
    <button>
        {props.children}
    </button>
    );
}

ButtonЭффективно используйте то, что вы передали раньше, с помощьюbuttonЭлементы инкапсулированы. Хотя на данный момент в этом нет ничего потрясающего, это практическая способность. Это позволяет принимающему компоненту размещать дочерние элементы в любом месте макета или оборачивать его вclassNameвнутри. Отрендеренный HTML-код будет выглядеть так:

<button>
    <i class="fa fa-dollars"></i>
    <span>BUY NOW</span>
</button>

(Кстати, здесь мы предполагаемIconрендеринг компонентов<i>Этикетка. )

Дети тоже нормальная опора

React использует дочерние элементы довольно круто: вложенные элементы могут быть указаны какchildrenРеквизит, но это не магический и специальный реквизит. Вы можете дать реквизиту указать любые другие элементы. Давайте посмотрим на:

// 这行代码其实 ——
<Button children={<span>Click Me</span>} />

// 相当于以下的代码。
<Button>
  <span>Click Me</span>
</Button>

Таким образом, вы можете не только передать его как обычный реквизитchildren, вы также можете передать код JSX в свойствах. Вы удивлены? Правильно, эта функция не является эксклюзивной для реквизита под названием «дети»!

Использование реквизита с именованными слотами

Что бы вы подумали, если бы я сказал вам, что вы можете передать код JSX любой опоре?

(Ты уже знаешь секрет, не так ли?) Вот пример использования этих реквизитов "slots" - вызов реквизита с 3 реквизитамиLayouts компонент:

<Layout
  left={<Sidebar/>}
  top={<NavBar/>}
  center={<Content/>}
/>

в этом имениLayoutСреди компонентов его можно использовать по желаниюleft,topтак же какcenterЭти три реквизита. Вот простой пример:

function Layout(props) {
  return (
    <div className="layout">
      <div className="top">{props.top}</div>
      <div className="left">{props.left}</div>
      <div className="center">{props.center}</div>
    </div>
  );
}

Только представь,LayoutКод внутри компонента может быть очень сложным, он может иметь множество вложенных элементов.divили имя класса Bootstrap и т. д. Этот компонент также может передавать информацию более подробным компонентам. несмотря ни на чтоLayoutчто нужно сделать, его пользователи просто должны знать, как пройтиleft,topтак же какcenterЭтих трех реквизитов достаточно.

Используйте Children для прямой передачи реквизита

Также есть приятная фича про проходящих детей (независимо от того, используется ли опораchildren): когда вы собираетесь передать дочернюю опору, просто вparentЗатем в области вы можете передать любую информацию, которая вам нужна.

Это какпропустил уровень. Например: вместо того, чтобы передавать «пользователя» компоненту Layout, а затем передавать «пользователя» Layout компоненту NavBar, лучше создать NavBar (с уже установленным пользователем) и передать весь NavBar в Layout . Это помогает избежать проблемы «сверления реквизита», когда вам не нужно помещать реквизит в иерархию нескольких компонентов.

function App({ user }) {
  return (
    <div className="app">
      <Nav>
        <UserAvatar user={user} size="small" />
      </Nav>
      <Body
        sidebar={<UserStats user={user} />}
        content={<Content />}
      />
    </div>
  );
}

// 接收 children 并渲染它(们)
const Nav = ({ children }) => (
  <div className="nav">
    {children}
  </div>
);

// Body 需要一个侧边栏和内容,如果像下面这样写的话,
// 他们可以做任何事
const Body = ({ sidebar, content }) => (
  <div className="body">
    <Sidebar>{sidebar}</Sidebar>
    {content}
  </div>
);

const Sidebar = ({ children }) => (
  <div className="sidebar">
    {children}
  </div>
);

const Content = () => (
  <div className="content">main content here</div>
);

Теперь сравните со следующей записью, и Nav, и Body принимают имяuser, то они несут ответственность за ручную передачу реквизита дочерним элементам. После этого их дети должны быть переданы на более высокий уровень детей...

function App({ user }) {
  return (
    <div className="app">
      <Nav user={user} />
      <Body user={user} />
    </div>
  );
}

const Content = () => <div className="content">main content here</div>;

const Sidebar = ({ user }) => (
  <div className="sidebar">
    <UserStats user={user} />
  </div>
);

const Body = ({ user }) => (
  <div className="body">
    <Sidebar user={user} />
    <Content user={user} />
  </div>
);

const Nav = ({ user }) => (
  <div className="nav">
    <UserAvatar user={user} size="small" />
  </div>
);

Это не так удобно, как раньше, не так ли? Передача реквизита таким образом (также известная как «сверление реквизита») оставляет компоненты увязшими в слишком большом количестве хлопот, которые вам, вероятно, не нужны — не всегда плохо, но вам лучше выяснить, что происходит между ними. Как они связаны. Первое использование дочерних элементов выше позволяет избежать необходимости в более сложных решениях, таких как контекст, Redux или MobX (среди многих других).

Остерегайтесь PureComponent или shouldComponentUpdate

Если вам нужно реализовать компонент с дочерними элементамиshouldComponentUpdate(илиPureComponent), чтобы предотвратить вторичный рендеринг, и дочерние элементы не могут быть визуализированы. Так что обратите на это внимание. На практике компоненты со «слотами», скорее всего, будут небольшими и быстро визуализируются, поэтому настройка производительности вряд ли потребуется.

Но если вы встретитеВ самом делеЕсли вам нужно настроить производительность компонента «слот», вы можете рассмотреть возможность извлечения части кода, производительность которой слишком низкая, поместить ее в отдельный компонент, а затем настроить.

Реакция в обучении иногда может быть болью - есть так много кодовых базов и инструментов! Хотите услышать мое мнение? Это игнорировать все эти кодовые основания и инструменты :) Если вы хотите пошаговое руководство, пожалуйста, прочитайте книгу, которую я написал -Pure React.

Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.