Пытаюсь разобраться с Redux, в каких случаях его применить. Я четко понимаю зачем он нужен, это отличное решение для обмена состоянием между любыми компонентами в приложении и для управления состоянием приложения.
По случаям использования не совсем понятно.
По идее это решение для обмена состоянием между не связанными компонентами, вроде списка товаров в корзине, который нужен и в шапке, и на конкретных страницах, и на странице любого товара, и в списке сопутствующих покупок.
По факту, я вижу что люди его используют как основное хранилище для вьюшек, даже если оно там вообще не нужно. Например, есть страница с результатами поиска фильмов, или просто страница каталога фильмов, и эти данные (что важно, динамические, и их всегда нужно перезагружать при входе на страницу) многие хранят именно в Redux-сторе, а не в локальном состоянии компонента (страницы).
Так вот, как вы определяете, когда вам нужен глобальный стор, а когда локальный на уровне компонента или роута?
>> По идее это решение для обмена состоянием между не связанными компонентами, вроде списка товаров в корзине, который нужен и в шапке, и на конкретных страницах, и на странице любого товара, и в списке сопутствующих покупок.
Для этого сейчас можно также использовать useContext хук. Вопросов становится всё больше!..)
Да, но Redux-интрументы будут утеряны, насколько я понимаю, либо придется вручную их адаптировать. Плюс Redux не дает создать вложенные состояния, насколько я понимаю, в отличие от контекста, которые можно вкладывать друг в друга.
abberati, спасибо! Интересно.
Мне вот тоже как-то уже привычнее и комфортнее работать с Redux.
И в тоже время на Хабре и т.д. продолжают выходить статьи на тему "бросайте Redux - useConrext решит все ваши проблемы"!)
abberati, присоединяюсь к Abr_ya, спасибо за ссылку :+1:
Действительно, отказавшись от инструмента всё-равно в результате получится велосипед. Нет смысла не использовать сразу готовое решение, не говоря про его клевые особенности, которые помогают в разработке.
Поговаривают, что редакс на самом деле немного устарел (для новых проектов — уже написаны тысячи тысяч систем, работающих на редаксе и разработчики со знанием редакса ещё долго будут востребованы). Есть более современные стейт-менеджеры, переосмыслившие опыт редакса — effector (production ready), reatom (только-только вышел в полноценный релиз). Для общего развития стоит попробовать оба.
А благодарность и +1 можно выражать кнопкой «нравится» под комментарием :3
В приложении должен быть один и только один источник правды. На роль такого источника очень хорошо подходят хранилища состояний, предоставляемые такими библиотеками, как redux/mobx/vuex/...
Если в приложении несколько источников правды, то раньше или позже между ними возникнет конфликт, который приведет к трудноотлаживаемым багам.
Говоря совсем простым языком, пока некое состояние модуля/компонента сугубо локально, то есть не влияет ни на что за пределами этого компонента - его можно (а зачастую и нужно) хранить локально, но при этом обязательно абсолютно соблюдать инкапсуляцию этого состояния, ибо как только оно "протекло" во вне, оно перестает быть локальным и становится общим, а там уже и до нескольких источников правды недалеко.
Хранилище состояния же решает эту проблему, становясь тем самым единственным источником правды, которому все могут доверять.
Можете привести пример проблемы при нескольких источниках правды?
Я не понимаю в чем разница в прямой работе с состоянием из компонентов, и через Redux редьюсеры, ведь в любом случае состояние меняется разными компонентами по разным причинам, и разница между Redux и без него только лишь в плоскости поиска точек возникновения изменения состояния.
Скажем, todo-лист можно поменять из 10 компонентов, и без разницы как они это сделают (Redux или без него), состояние всё-равно будет общее, и если закралась ошибка, всё-равно придется дебажить кто вносит ошибку и почему.
Ощущение что речь идет скорее про кривой кодинг, когда может быть разное состояние одной сущности, которое может конфликтовать, но даже представить такой случай не могу при нормальной реализации (т.е. минимум внедряя единые точки изменения состояния в виде сервисов или просто методов). Похоже что Redux решает такие проблемы просто отсекая возможность их допустить на корню. Есть action'ы и редьюсеры, и распишитесь, всё.
Роман Якимчук, ну вот возьмем тот же todo-лист
Вот приходит к нам массив todo'шек с апи, в котором объекты с текстом и статусом
Мы пилим 4 компонента:
- сам список
- отдельный элемент
- форма добавления
- счетчики (сколько всего, сколько выполненных)
кто из них должен владеть состоянием?
может сам список? но что будет, если он не создается пока массив пустой?
а отдельный элемент наверняка будет с возможностью редактирования, а это уже локальное состояние, которое придется как то согласовывать с родительским компонентом список
но это еще пол беды, вся беда начнется с счетчиками, которые не связаны со списком отношением родитель-потомок, счетчикам придется постоянно получать состояние от компонента, которого вообще по хорошему не надо знать. Мало того что появилась сильная связанность, так еще и появилось 2 источника правды - 1 вариант состояния хранит список, другой счетчики, но поддерживать эти состояния в согласованности та еще боль...
а теперь пришел менеджер/заказчик/продакт и говорит такой, а вот тут еще хочу кнопки "отметить все выполненным/невыполненным", и мы идем пилим новый компонент, и организуем еще два слоя связанности - со списком и со счетчиками, ради того чтоб согласовывать общее состояние
с редаксом же будет только 1 связь, компоненты не будут знать друг о друге, только о редаксе, что упростит их перенос (не только в другой проект, просто по дереву компонентов). И состояние у нас будет только в 1 месте - в редаксе. А еще, при изменении статуса у отдельного таска нам легче пересчитать счетчик
>кто из них должен владеть состоянием?
Никто, они все зависят от данных в сторе, одни напрямую, другие через свойства компонента.
>но что будет, если он не создается пока массив пустой?
Будет сообщение что список пуст, а в лучшем варианте, будет виден лоадер на период загрузки данных (если они должны загрузиться)
>а отдельный элемент наверняка будет с возможностью редактирования, а это уже локальное состояние, которое придется как то согласовывать с родительским компонентом список
Здесь есть одно огромное НО, в виде завязки на данные стора, т.е. переиспользовать компоненты будет нельзя, если завязывать редактор напрямую на данные из стора. Если есть редактор текущего пользователя, например, то нельзя ему скормить другую модель и получить на выходе обновленную модель после редактирования. Это делает решение максимально жестким. Поэтому и делаются выбросы данных в родительский компонент через функции обратного вызова. Это создает связь между компонентами, но остается огромное пространство для маневров по вариантам использования компонентов, поэтому это не проблема.
>но это еще пол беды, вся беда начнется с счетчиками, которые не связаны со списком отношением родитель-потомок, счетчикам придется постоянно получать состояние от компонента, которого вообще по хорошему не надо знать.
Со счетчиками вообще не понял, если честно. Просто берем список из стора и делаем фильтр, и выводим число. Источник правды останется один, это стор. Никакой зависимости от компонентов.
>а теперь пришел менеджер/заказчик/продакт и говорит такой, а вот тут еще хочу кнопки "отметить все выполненным/невыполненным", и мы идем пилим новый компонент, и организуем еще два слоя связанности - со списком и со счетчиками, ради того чтоб согласовывать общее состояние
Тогда делаем компонент, который меняет данные в сторе, и остальные компоненты сами обновят свой интерфейс. Зависимости от компонентов тоже нет, только от стора.
Может быть я не понял сообщения, но вообще не вижу проблем при реализации. Данные в сторе общие, связи только на уровне функций обратного вызова (что обеспечивает переиспользуемость компонента и это хорошо, это базовая практика для любых компонентов, см. API компонентов любого UI kit'а). В вашем примере ни счетчик, ни форма создания Todo, ни список друг о друге ничего не должны знать, все только на стор завязыватся. Локальное состояние будет только у редактора конкретного Todo. Можно еще переделать форму создания Todo, чтобы она не на стор завязывалась, а наружу данные выбрасывала через функцию обратного вызова.