Originally posted by andres-kovalev January 29, 2026
Часто возникают ситуации, когда нужно объединить свойства двух компонентов (стиль одного и логику другого, стили двух компонентов, и тд). В большинстве случаев это можно сделать простой композицией.
<Box>
<Title>Title</Title>
</Box>
Но это увеличивает размер DOM дерева, что на больших интерфейсах может приводить к проблемам производительности, особенно когда такие комбинации используются часто.
Эта проблема достаточно изящно решается с помощью пропа Component, который уже есть в VKUI:
<Box Component={Title}>Title</Box>
Но у этого подхода есть ограничения:
- работает только для двух компонентов
- может приводить к коллизии пропов
Обе проблемы можно решить выносом суррогатного компонента, например так:
// объединяем три компонента
const Surrogate = ({ className, style, getRootRef }) => <Component1 Component={Component2} className=... />;
<Component3 Component={Surrogate} />
Минус такого подхода - создание множества "мусорных" суррогатных компонентов когда необходимость объединения возникает во многих местах но комбинации не повторяются.
Технически, API пропа позволяет сделать и так:
<Component3 Component={({ className, style, getRootRef }) => (
<Component1 Component={Component2} ... />
)} />
Так гораздо лучше. Но фактически это ошибка - такой код создает безымянный компонент при каждом рендере, что приводит к тому, что все поддерево будет ремаунтиться каждый раз.
К сожалению, многие этого не знают и делают так, и даже опытные и знающие ребята рекомендуют такой подход
Предложение:
Что если "починить" последний вариант через добавление отдельного пропа (render) для таких сценариев? Он может работать по аналогии с Component, но более гибко, позволяя не ремаунтить поддерево и даже уменьшить размер vDOM.
<Component3 render={({ className, style, getRootRef }) => (
<Component1 Component={Component2} ... />
)} />
Новый API может работать параллельно с существующим и на первых порах поддерживать только часть свойств:
const Component = ({ render, ...restProps }) => {
const className = ...;
const style = ...;
if (render) return render({ ...restProps, className, style });
...
}
Многие библиотеки реализуют такой API (например, https://base-ui.com/).
В качестве альтернативы некоторые либы (например, https://www.radix-ui.com/) используют свойство asChild, которое позволяет смиксовать два компонента:
<Box asChild>
<Title>Title</Title>
</Box>
Но по аналогии с пропом Component этот метод не дает такой гибкости, как render (не позволяет динамически манипулировать пропами) и требует чтобы апи объединяемых компонентов соответствовало определенным правилам. render() в свою очередь позволяет производить любые манипуляции, по сути расширяя логику рендера компонентов:
<Box render={
({ children }) => Children.length(children) ? <Title>children</Title> : <EmptyIcon />
}>
{content}
</Box>
```</div>
Discussed in #9411
Originally posted by andres-kovalev January 29, 2026
Часто возникают ситуации, когда нужно объединить свойства двух компонентов (стиль одного и логику другого, стили двух компонентов, и тд). В большинстве случаев это можно сделать простой композицией.
Но это увеличивает размер DOM дерева, что на больших интерфейсах может приводить к проблемам производительности, особенно когда такие комбинации используются часто.
Эта проблема достаточно изящно решается с помощью пропа Component, который уже есть в VKUI:
Но у этого подхода есть ограничения:
Обе проблемы можно решить выносом суррогатного компонента, например так:
Минус такого подхода - создание множества "мусорных" суррогатных компонентов когда необходимость объединения возникает во многих местах но комбинации не повторяются.
Технически, API пропа позволяет сделать и так:
Так гораздо лучше. Но фактически это ошибка - такой код создает безымянный компонент при каждом рендере, что приводит к тому, что все поддерево будет ремаунтиться каждый раз.
К сожалению, многие этого не знают и делают так, и даже опытные и знающие ребята рекомендуют такой подход
Предложение:
Что если "починить" последний вариант через добавление отдельного пропа (render) для таких сценариев? Он может работать по аналогии с Component, но более гибко, позволяя не ремаунтить поддерево и даже уменьшить размер vDOM.
Новый API может работать параллельно с существующим и на первых порах поддерживать только часть свойств:
Многие библиотеки реализуют такой API (например, https://base-ui.com/).
В качестве альтернативы некоторые либы (например, https://www.radix-ui.com/) используют свойство asChild, которое позволяет смиксовать два компонента:
Но по аналогии с пропом Component этот метод не дает такой гибкости, как render (не позволяет динамически манипулировать пропами) и требует чтобы апи объединяемых компонентов соответствовало определенным правилам. render() в свою очередь позволяет производить любые манипуляции, по сути расширяя логику рендера компонентов: