Команда JavaScript for Devs подготовила перевод статьи, в которой разработчик с восьмилетним опытом работы с React делится неожиданным открытием: Solid.js оказался проще, логичнее и… приятнее в использовании. Меньше перерендеров, ближе к нативному вебу, честное поведение API и настоящие веб-компоненты — кажется, у React появился достойный конкурент.
Прежде чем перейти к сути статьи, немного предыстории: я работаю с React почти восемь лет и любил каждую секунду. На нём я делал Open source, приложения и всё, что между этими крайностями.
Недавно я присоединился к команде TanStack, чтобы работать над TanStack Devtools, и у них Solid.js принят в качестве базы для всех проектов с UI. Я решил собраться с духом и выучить Solid.js. В технических выборах я стараюсь быть непредвзятым, так что подошёл к делу с открытым взглядом и желанием учиться новому!
Изучаю реактивность Solid.js
Я месяц работаю с Solid и всё ещё новичок, но должен признать: самым трудным для понимания оказалась именно реактивность. В мире React вы привыкли к такой модели:
вы создаёте компонент со стейтом и пропсами
стейт и пропсы меняются
компонент перерендеривается
Всё довольно просто! При изменении стейта или пропсов компонент ререндерится. Но в Solid этот подход перевёрнут с ног на голову: перерендеры происходят только тогда, когда вы явно этого хотите — через встроенную реактивность (например, сигналы). То есть если вы хотите, чтобы ваш компонент перерендерился из-за изменения пропса, вам нужно явно прописать «слушатель» — через createMemo или createStore. И только тогда компонент будет перерендерён. В отличие от React, у Solid философия такая: «Я отрендерился и больше этого делать не буду, как бы ни менялись данные, пока ты мне прямо не скажешь».
Звучит ужасно для человека из мира React: если у вас куча пропсов, которые меняются, пришлось бы обернуть их все в какой-нибудь «хук», чтобы сделать их реактивными, верно?
На самом деле нет. Пропсы по умолчанию не реактивные, но становятся таковыми, если это сигналы. То есть если вы создаёте состояние в родителе на базе сигнала и передаёте его в дочерний компонент, такой проп реактивен. На практике вы получаете почти идентичный React API, только без лишних перерендеров.
Поработав с этим и помучившись, пытаясь заставить что-то перерендериться, я понял важную вещь об архитектуре Solid.js, которая даёт серьёзное преимущество перед React:
Гораздо проще добиться перерендеринга тогда, когда он вам нужен, чем добиваться того, чтобы он не происходил, когда он не нужен!!

JSX ближе к платформе!
Если вы ещё не знали: помимо TanStack я плотно вовлечён в экосистему Remix/React Router, и один из важнейших принципов, который я оттуда вынес, — «используйте платформу». По сути это сводится к: «Если есть веб-API, пользуйтесь им, а не изобретайте свои велосипеды и абстракции средствами конкретного фреймворка». Так вот, Solid.js ощущается куда ближе к платформе — объясню на примерах.
Вы когда-нибудь работали с иконками в проекте? Приходилось идти в что-то вроде lucide-react, находить подходящую иконку, копировать её и вставлять в код React — а если у вас не было какого-нибудь изощрённого пайплайна, который превращает иконки в спрайт-листы или что-то подобное, то, скорее всего, приходилось проходиться по каждому SVG и менять атрибут class на className!
Так вот: в Solid нет особых ключевых слов для JSX. Пропсы HTML-элементов необязательно писать в camelCase — можно, но не нужно. Нет «запрещённых» атрибутов вроде class или for, что держит вас ближе к самой платформе. Диалект JSX у Solid ощущается куда приятнее, чем у React, а новичкам он помогает учиться работать с платформой по настоящей спецификации HTML, а не по «придуманной» React — и это мне очень по душе!

API работают именно так, как вы ожидаете!
Пока я работал над @tanstack/devtools и адаптерами для React и Solid, заметил то, чего нет в React: в Solid API ведут себя именно так, как вы и ждёте — и даже больше! Объясню на примере порталов.
Чтобы добавить в devtools «отсоединённый» режим (когда их можно вынести в отдельное окно), мне пришлось использовать порталы, чтобы примонтировать devtools в это отдельное окно. Для этого у нас есть ядро на Solid.js, которое монтируется в приложение на React и при этом должно сохранять ваш контекст и состояние, даже когда его монтируют в отдельном окне. Единственный способ сделать это — воспользоваться createPortal из react-dom. Ниже покажу точный код, который для этого нужен:
export const TanStackDevtools = ({
plugins,
config,
eventBusConfig,
}: TanStackDevtoolsReactInit): ReactElement | null => {
const devToolRef = useRef<HTMLDivElement>(null)
const [pluginContainers, setPluginContainers] = useState<
Record<string, HTMLElement>
>({})
const [titleContainers, setTitleContainers] = useState<
Record<string, HTMLElement>
>({})
const [PluginComponents, setPluginComponents] = useState<
Record<string, JSX.Element>
>({})
const [TitleComponents, setTitleComponents] = useState<
Record<string, JSX.Element>
>({})
const [devtools] = useState(
() =>
new TanStackDevtoolsCore({
config,
eventBusConfig,
plugins: plugins?.map((plugin) => {
return {
...plugin,
render: (e, theme) => {
const target = e.ownerDocument.getElementById(
e.getAttribute('id')!,
)
if (target) {
setPluginContainers((prev) => ({
...prev,
[e.getAttribute('id') as string]: e,
}))
}
convertRender(plugin.render, setPluginComponents, e, theme)
},
}
}),
}),
)
useEffect(() => {
if (devToolRef.current) {
devtools.mount(devToolRef.current)
}
return () => devtools.unmount()
}, [devtools])
return (
<>
<div style={{ position: 'absolute' }} ref={devToolRef} />
{Object.values(pluginContainers).length > 0 &&
Object.values(PluginComponents).length > 0
? Object.entries(pluginContainers).map(([key, pluginContainer]) =>
createPortal(<>{PluginComponents[key]}</>, pluginContainer),
)
: null}
{Object.values(titleContainers).length > 0 &&
Object.values(TitleComponents).length > 0
? Object.entries(titleContainers).map(([key, titleContainer]) =>
createPortal(<>{TitleComponents[key]}</>, titleContainer),
)
: null}
</>
)
}
Вот как это работает:
devtools монтируются с плагинами, предоставленными пользователем
при клике на плагин он добавляется в массив плагинов
для каждого плагина создаётся реализация createPortal, чтобы сохранить контексты под элементом, к которому примонтированы devtools
Почему это вообще нужно? Хотя createPortal — это функция, которая монтирует JSX в указанный элемент, её недостаток в том, что она ДОЛЖНА быть отрендерена в JSX, иначе не работает. То есть вместо того, чтобы сделать что-то вроде:
render: (e, theme) => {
const target = e.ownerDocument.getElementById(
e.getAttribute('id')!,
)
if (target) {
createPortal(<div>hello</div>, target)
}
},
Нам приходится использовать приведённый выше «монструозный» хак: класть это в состояние, подменять туда-сюда и рендерить через JSX. На этом этапе вы, вероятно, задаётесь вопросом, как это выглядит в Solid.js? Вот, пожалуйста:
export default function SolidDevtoolsCore({
config,
plugins,
eventBusConfig,
}: TanStackDevtoolsInit) {
const [devtools] = createSignal(
new TanStackDevtoolsCore({
config,
eventBusConfig,
plugins: plugins?.map((plugin) => ({
...plugin,
render: (el: HTMLDivElement, theme: 'dark' | 'light') =>
<Portal mount={el}>
{typeof plugin.render === 'function' ? plugin.render(el, theme) : plugin.render}
</Portal>
})),
}),
)
let devToolRef: HTMLDivElement | undefined
createEffect(() => {
devtools().setConfig({ config })
})
onMount(() => {
if (devToolRef) {
devtools().mount(devToolRef)
onCleanup(() => {
devtools().unmount()
})
}
})
return <div style={{ position: 'absolute' }} ref={devToolRef} />
}
Веб-компоненты
Недостаточно предыдущего примера? Поговорим о веб-компонентах. Мы пытались интегрировать веб-компоненты в @tanstack/devtools-ui, чтобы любой мог использовать их в любом фреймворке практически без настройки. Это значительно упростила библиотека solid-element из Solid.js, которая превращает любой компонент Solid в веб-компонент — само по себе здорово. Я создал и протестировал компоненты в Solid (это заняло около 30 минут), и пришло время попробовать их в React.
И тут… они вообще не работают в любых версиях младше React 19, потому что React нормально не поддерживает веб-компоненты. А в React 19 любой проп, который вы передаёте веб-компоненту, преобразуется в строку — вам приходится вручную для каждого пропса указывать, что это не строка, чтобы React корректно его передал. А если вы пробуете до React 19 — удачи!
В Solid компоненты просто работают: даже если вы не описали пропсы вручную, всё ведёт себя ожидаемо без дополнительной настройки. Веб-компоненты важны не для всех — я это понимаю. Но, как видно из этого и предыдущего примера, что бы мы ни пробовали сделать, React обычно сопротивляется, а Solid — нет, и просто позволяет это сделать.

Напоследок
Чем больше я работаю с Solid, тем яснее понимаю: мне приходится «бороться» с React по множеству вопросов, по которым не должно быть борьбы. Я не хочу делать громких заявлений, но Solid стал глотком свежего воздуха и показал, каким мог бы быть React — но, вероятно, уже не станет. Экосистема по-прежнему на стороне React, и чтобы это изменить, пришлось бы сдвинуть горы, особенно сейчас, в эпоху ИИ. Лично мне приятнее делать проекты на Solid, чем на React, и если вы решитесь попробовать Solid, думаю, он понравится и вам. У него отличный дизайн, и работать с ним очень приятно, когда понимаешь, как он устроен.
Я вовсе не считаю, что выбирать React — это неправильно, но после знакомства с Solid я точно могу рекомендовать расширить горизонт. С интересом жду, как Solid будет развиваться в ближайшие годы, и очень рад, что познакомился с ним.
Русскоязычное JavaScript сообщество

Друзья! Эту статью перевела команда «JavaScript for Devs» — сообщества, где мы делимся практическими кейсами, инструментами для разработчиков и свежими новостями из мира Frontend. Подписывайтесь, чтобы быть в курсе и ничего не упустить!
Комментарии (12)

KivApple
16.10.2025 11:44Для меня наоборот React интуитивнее, потому что в нём по сути нет компиляторной магии (не считая JSX). В Solid больше магии из-за сигналов и иногда без опыта трудно понять, как именно поведёт себя код.

microspace
16.10.2025 11:44В реакте компонент не перерендеривается когда пропсы меняются.

bini1988
16.10.2025 11:44В React компонент перерендеривантся всегда если обновляется его родитель в не зависимости от того поменялись ли передаваемые ему пропсы или нет. Чтобы убрать лишнее рендеры нужно явно использовать memo или PureComponent.

ioleynikov
16.10.2025 11:44К сожалению я не знаком с Solid.js но хочу сказать пару слов в пользу React. Эта система внесла очень существенное улучшение концепции MVC. Классическая схема предполагает, что модель передает изменения данных в представление и тем самым полностью нарушает принцип независимости компонент. В React представление автоматически отслеживает изменение состояний данных модели при помощи механизма событий и обновляет UI. Аналогично контроллер React следит за событиями UI и представлению нет дела до обработки действий пользователя. Это намного более строго обеспечивает независимость и позволяет разработчику модели полостью абстрагироваться от представлений. Если Solid.js реализует подобный механизм, то это здорово, если нет, то я пока голосую за React.

kkorsun
16.10.2025 11:44Я месяц работаю с Solid
Месяца недостаточно, чтобы наступить на достаточное количество граблей. Примеры в статье детские. Может, с Solid и впрямь очень приятно работать, но после такой статьи не появляется желание попробовать.
Гораздо проще добиться перерендеринга тогда, когда он вам нужен, чем добиваться того, чтобы он не происходил, когда он не нужен!!
В устной речи действительно можно услышать языковой франкенштейн "компонент перерендеривается", но в письменном переводе я бы ожидал либо "ререндеринг", либо "перерисовка".
А по сути процитированного: между Сциллой, когда вы добавите функциональность и забудете явно вызвать ререндер какого-то компонента, и Харибдой, когда у вас UI всегда будет актуальный, но JS немножко поработает под капотом, вы выберете второе. К чему все эти страхи: о ужас, компонент перерисовывается? Это не означает патча DOM, да в большинстве случаев не означает видимой просадки в перформансе. До Fiber да, бывало дело.Вы когда-нибудь работали с иконками в проекте?
SVGR, если нужна динамическая работа с пропсами. Если не нужна, просто импорт svg в компонент средствами сборщика и использование в img или background. Зачем svg class или className, загадка. Ну в самом крайнем случае повесьте на обертку.
А если вы пробуете до React 19 — удачи!
Если конкретный кейс автора решает установка кастомной библиотеки, то это хорошо. Если обновление фреймворка — это плохо.

Andy_Francev
16.10.2025 11:44Библиотека по своей сути прекрасная. Но в прод я-бы её не потащил. Причины две:
Как тут уже писали, экосистема совершенно неразвитая, и за несколько лет, что я за ней слежу, сильных подвижек в этом, увы, совсем не видно.
-
Она так и не получила поддержку никого из «сильных мира сего». В отличии от «большой тройки», главным её двигателем является всего один человек – Райан Карниато. Есть ещё пара-тройка мейнтейнеров и небольшое сообщество. Как думаете, что случится с продуктом, когда Райану надоест?
Так, что, для пет-проектов очень даже неплохо, а вот внедрять это на работе – абсолютно дурацкая идея.
dsrk_dev
Solid прикольный, но у него есть огромный минус по сравнению с реактом. И этот минус — отсутствие экосистемы. Банально ui kit под solid не найти(да, можно использовать чисто css киты, или ненавистный tailwind, но это немного не то)