Компоненты и свойства — Примеры
Пример 1 — Булево значение, включающее часть разметки
Панель принимает флаг showFooter и при истинном значении рендерит два дополнительных элемента; теперь понадобился второй вариант, а обсуждается уже третий. Скажите, чего стоит этот флаг, и позвольте вызывающему самому передать разметку.
function Panel({ title, children, showFooter }) {
return (
<section className="panel">
<h2>{title}</h2>
{children}
{showFooter ? <footer><button>Закрыть</button></footer> : null}
</section>
);
}
Решение
function Panel({ title, children }) {
return (
<section className="panel">
<h2>{title}</h2>
{children}
</section>
);
}
<Panel title="Счета">
<InvoiceTable rows={rows} />
<footer><SaveButton onSave={save} saving={saving} /></footer>
</Panel>
Свойство-флаг заводит возможность внутрь компонента, который в остальном о ней ничего не знает: каждый новый вариант добавляет либо ещё один флаг, либо ещё одну ветку, и компонент накапливает знание о своих вызывающих. Композиция переворачивает картину — панель рендерит то, что ей дали, и отвечает только за рамку. Вызывающий может положить в подвал что угодно: другую кнопку, две кнопки, строку состояния, — и панель при этом вообще не меняется, зато её собственный список свойств перестаёт расти. Границы принадлежат данным, а не визуальному пространству, и свойство, которое существует лишь чтобы включить область, — самый ясный признак того, что граница проведена не там.
Пример 2 — Свойство, протянутое через три слоя, которые его игнорируют
Значение передаётся вниз через раскладку, раздел и карточку, прежде чем кто-либо его прочитает, — и каждый средний компонент теперь принимает свойство, которым не пользуется. Скажите, чего стоит это протягивание, и приблизьте значение к месту, где оно нужно.
function Layout({ user, children }) { return <main>{children}</main>; }
function Section({ user, children }) { return <section>{children}</section>; }
function Card({ user }) { return <h3>{user.name}</h4>; }
<Layout user={user}><Section user={user}><Card user={user} /></Section></Layout>
Решение
function Layout({ children }) { return <main>{children}</main>; }
function Section({ title, children }) {
return <section><h2>{title}</h2>{children}</section>;
}
function Card({ user }) { return <h3>{user.name}</h4>; }
<Layout>
<Section title="Аккаунт"><Card user={user} /></Section>
</Layout>
Когда свойство только передают дальше, каждый промежуточный компонент становится зависимым от возможности, которой не пользуется. Переименование или новое поле приходится тогда применять на каждом слое, и список свойств слоя перестаёт описывать то, что он на самом деле делает. Передача значения из компонента, который им владеет, прямо в компонент, который его читает, полностью убирает эту связанность, и у слоёв остаются только их собственные заботы. Там, где слой должен разместить детей вокруг неизвестного содержимого, наступает случай композиции: раскладка рендерит то, что ей дали, и не нуждается в знании о данных внутри. Три ясных уровня читаются лучше, чем восемь тонких.