Comments 39
Потом, когда оказалось, что под капотом специально для redux в самом react есть контексты, даже если вы не используете redux, и скрывать этот факт стало совсем уж неприлично — контексты документировали. Т.е. открыли для всех аналог global-объявлений.
При этом родной для javascript способ хранения состояния объектов — ну, в самих объектах, считается фу-фу-фу и грязь.
Зато завезли хуки — сегодняшняя их версия выглядит нестрашно, но их нужно давить пока маленькие. Хуки приводят к самому дикому лапшекоду, который только можно представить, т.к. по сути представляют собой хорошо замаскированный goto. Посмотрите на сегодняшний вордпресс и особенно его интернет-магазин woocommerce.
Вместо того, чтобы выносить разработчикам мозг и заставлять их использовать одну конкретную архитектуру приложения, Абрамову и компании не помешало бы оглянуться вокруг и привести своё детище к современным стандартам. Баг про несовместимость реакта со стандартными модулями висит третий год — т.е. вы можете загрузить в браузер что угодно через script type=«module», включая подавляющее большинство компонентов для реакта, но не сам реакт. Уродский и сломанный во всех местах JSX вместе с jsx-компилятором давно пора закопать в пользу нативных js-шаблонов и template — как минимум, браузеры обрабатывают это быстрее. React-dom нужно уравнять по функционалу хотя бы с пятилетней свежести jquery, чтобы последний не тащили зависимостью в каждом первом проекте. Мечты, мечты…
Раз уж такая пьянка, то тоже хапну пару минусов.
Потом, когда оказалось, что под капотом специально для redux в самом react есть контексты, и скрывать этот факт стало совсем уж неприлично — контексты документировали.
Потом, как оказалось, рептилоиды уже давно захватили человечество, и тайком встроили богопротивные контексты в реакт.
При этом родной для javascript способ хранения состояния объектов — ну, в самих объектах, считается фу-фу-фу и грязь.
Хранить-то их там можно без проблем, вопрос лишь в том как вовремя замечать в них изменения? Тут нужно либо использовать протокол "сквозная иммутабельность + не создаем лишний раз новых объектов" (и тогда в пределе получится redux), либо использовать явные подписки на изменения (и тогда в пределе получится rx.js), либо использовать автоматические подписки (и тогда в пределе получится mobx). Все три способа возможны и реактом не запрещаются, а других способов нет.
Уродский и сломанный во всех местах JSX вместе с jsx-компилятором давно пора закопать в пользу нативных js-шаблонов и template — как минимум, браузеры обрабатывают это быстрее.
Это невозможно сделать сохраняя основную идею реакта (метод render). Точнее, возможно — но будет медленнее, а не быстрее.
React-dom нужно уравнять по функционалу хотя бы с пятилетней свежести jquery
Например?..
а других способов нет
Computable и Observable поля были ещё в knockout.js и самом-самом первом angular.js, существовавших до реакта.
Особенно смешно про иммутабельность. Примерно все умеют в Object.freeze, который как раз про иммутабельность, кроме react.js.
Это невозможно сделать сохраняя основную идею реакта (метод render). Точнее, возможно — но будет медленнее, а не быстрее.
HTML тэг template парсится один раз при загрузке браузером. То же самое, гипотетически, возможно с `литералами`. Дальше они клонируются, а не создаются. Это тот самый виртуальный дом, только реализованный движком браузера и быстро, а не через вызовы CreateElement.
Например?..
Ну например один раз при старте приложения повесить один обработчик onChange на все поля ввода определённого класса, а не вешать свой handleChange на каждое поле при создании, а потом уничтожать при удалении из DOM.
Ну например один раз при старте приложения повесить один обработчик onChange на все поля ввода определённого классаЗачем пихать в react то, что решается одной строчкой кода?
if (!e.target.classList.contains(cls)) return;
Computable и Observable поля были ещё в knockout.js и самом-самом первом angular.js, существовавших до реакта.
Ну так идейным наследником knockout как раз mobx и является.
Особенно смешно про иммутабельность. Примерно все умеют в Object.freeze, который как раз про иммутабельность, кроме react.js.
Иммутабельный объект — это объект, свойства которого никогда не меняются. Причина, по которой они не меняются (к нему применили freeze, или их просто не меняют) — не важна.
HTML тэг template парсится один раз при загрузке браузером. То же самое, гипотетически, возможно с литералами
. Дальше они клонируются, а не создаются. Это тот самый виртуальный дом, только реализованный движком браузера и быстро, а не через вызовы CreateElement.
А дальше что? Как обновлять результат такого "рендера"?
в пользу нативных js-шаблонов
Вы имеете ввиду developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals?
PS: спасибо за коммент
Со всем не согласен =)
Хуки в React удобны (раза в два короче классов, лучше читать лапшекод с хуками, чем лапшекод с классами), только построены на той самой $_GLOBALS к сожалению для того, чтобы не ломать код. Если бы поменяли api на что-то вроде
const MyComponent = (props, io) => {
const [value, setValue] = useState(io, 'default value');
};
стало бы лучше, это ЯВНЫЙ способ закрепить что-то на узле virtual dom. Сейчас этот io — объект в react модуле (сразу лазил смотреть, как сделали). Тестировать не удобно и тп.
Контекст нормальный и это не GLOBALS, потому что контекст доступен только в поддереве. Удобный механизм прокидываний props глубоко внутрь (не нравится — кидайте руками и получите по 100500 props на верхнем уровне).
JSX тоже нормальный, если целиком понимать, что внутри это React.createElement(MyComponent, myProps), просто сахар. И я хотел бы такой сахар например в c++ когда нужно делать подобные деревья (scenegraph в играх). К сожалению большая часть народа, которая хочет зп до 150к не понимает этого вообще (мой опыт).
Flux/redux store — это прямой аналог $_GLOBALS, т.е. с точки зрения ООП — самый что ни на есть God object в наихудшем своём виде, когда он by design отвечает вообще за всё приложение.
А вы не могли бы предложить альтернативный способ построения приложений, чтобы можно было более предментно обсуждать?
С JSX, точнее redux, у вас дерево и одностороннее связывание. И довольно часто ближайшим общим предком компонентов, которым нужно общее состояние, является корневой объект. Для компонентов с собственным состоянием начинаются пляски с бубном, все эти UNSAFE_componentWillReceiveProps и попытки определить, кто именно вызвал изменения пропсов — сервер, сам компонент или что-то другое, чтобы не уйти в бесконечный цикл. А ещё такая схема часто вызывает перерендеринг всего, т.к. в реакте мелкое сравнение на изменение пропсов. И не надо рассказывать, что это быстро.
определить, кто именно вызвал изменения пропсов — сервер, сам компонент или что-то другое
С точки зрения менеджера состояний — должно быть ясно из названия вызванного экшена или просто из того в какой функции модели вы находитесь. С точки зрения стандартных глупых компонентов — должно быть пофигу. Специально вводили виртуальный DOM чтобы не заниматься обходом всех пропсов и смотреть какой кусок DOM менять, как бывало в первом AngularJS. Либо ссылки на пропсы поменялись и обновляем всё, либо — нет, и мы ничего не трогаем.
Не вижу связи между глобальными переменными и MVVM. Модель-то нужно точно так же откуда-то получать, что можно сделать теми же самыми способами которыми можно получить стор.
Можно ли жить без ног? Можно, но с ногами удобней. Если они есть, то отказываться от них глупо. Тогда уж отказывайся и от рук, чтобы "свобода" была полной. Имхо.
изменяет view, добавляя декоратор
Но ведь вам в любом случае нужно что-то менять во view, когда вы меняете интерфейс модели...
если обновляются k зависимых полей, метод render вызывается k раз (что не проблема для react)
Давно уже придуман action, который решает именно эту проблему
Component {
props.model
props.onModelChange(fieldName, value)
}
@observer
Component {
props.model
}
Дело вкуса.
Не нравится, что во втором варианте любой (не имеющий отношения к модели) observable props будет форсить компонент к перерисовке.
А откуда у вас в нормальной программе возьмется "не имеющий отношения к модели observable props"? И что, по вашему, должен сделать правильный компонент, когда используемая им при рендере информация изменилась? Неужели проигнорировать это изменение?
Кстати, информация о fieldName
— бесполезная. Реакт просто не умеет обновлять компонент по частям, метод render()
можно вызвать лишь целиком.
информация о fieldName — полезная. onModelChange обычный callback в child-parent communication
Ну да, отличает. Но ведь при любом изменении props Реакт и без mobx перерисует компонент (если это PureComponent или Component без shouldComponentUpdate), так в чем отличие именно mobx?
mobx-react-lite
не меняет view. https://mobx-react.netlify.com/observer-component
Это теперь называется "не меняет"? :-)
Разумеется, сам рендер меняется. Так же как и при использовании нативных контестов, например. Я имел ввиду, что он не добавляет никаких магических декораторов. Это более прозрачный подход и позволяет следить за локальными изменениями в дереве, а не всем компонентам.
Ну да, магических декораторов нет, только теперь есть ещё более магический хук.
Observer component, к слову, в mobx-react был примерно всегда.
Полностью согласен с
не рекомендую использовать его в серьезных проектах
Все дело в инкапсуляции. На мой взгляд это самый серьезный недостаток Redux для крупных проектов. Store один, поэтому
- там лежат и бизнес модели и состояния кнопок, хотя это абсолютно разнородные данные.
- его нельзя сделать разным для разных сборок проекта. Например в веб версии одно поведение, а в десктопной другое.
Я тоже переводил проект с Redux на свою архитектуру (очень похожа на MobX, только тогда его еще не было, поэтому пришлось писать самим). Тоже заметил, что
скорость разработки выросла раза в три за счёт избавления от бойлерплейта
В Redux каждый reducer обрабатывает каждый action
Это зависит от того как вы ваш редьюсер приготовите. Совершенно не обязательно писать его "классически". Redux не навязывает вам того как редьюсер должен быть устроен. Лично я предпочитаю 1 action = 1 handler, а сам reducer как древо hash-map вида [action.type piece]: handler. В таком случае никаких O(n), никаких switch-case.
есть копиривание объектов для достижения иммутабельности
А тут асимптотика равна глубине древа. Т.е. совсем чуть-чуть.
Проблема с производительностью в redux кроется скорее в том, что react-redux-ий connect написан так, что все его instance-ы вызываются на любое изменение store. Это ограничение преодолимо, за счёт написания своего иерархического HoC, вместо react-redux.
Ну и в целом сделать большое приложение с иммутабельным древом производительным стоит кучи геморроя в поддержке кеширования промежуточных вычислений, обеспечения бесперебойной работы React.memo | PureComponent. Это мягко говоря не тривиально и пестрит кучей нюансов. Мало кто умеет это делать правильно. Хуже того — мало кто пытался пробовать.
Возможно ли без Redux?