Упрощение работы с Redux-Observable.

Redux-Observable код, который все исправляет.

Единственный совет для успеха Redux-Observable.

Если вы какое-то время работали с Redux-Observable, вы, вероятно, сталкивались с ситуацией, когда вам нужно отправить что-то в начало конвейера, а затем сделать что-то еще.

Это обычная проблема, но не сразу бросающаяся в глаза. Поскольку Redux-Observable v1 автоматически отправляет все, что попадает в конвейер, это означает, что вам нужно разделить конвейер, чтобы выполнить свое первое действие, а затем переключиться на другой наблюдаемый, который продолжает исходный конвейер.

Разделение трубопровода

Выглядит это примерно так:

При использовании этого метода вам придется разделить конвейер очень сложным способом, который не очевиден для новичков. Это действительно работает во всех случаях использования, и именно так я настраивал буквально все мои проекты Redux-Observable до этого момента. Я даже говорю о разделении конвейера в Redux-Observable решит ваши проблемы состояния.

В Redux-Observable есть несколько причуд, и разделение конвейера (как показано в этом примере) является одним из самых больших, влияющих на новичков. К сожалению, это тоже , который Redux-Observable должен упростить.

Я постоянно вижу вопросы о разделении конвейера (или о недостатке знаний о том, как это сделать), которые задают в официальном чате Gitter Redux-Observable, и друг задал мне тот же вопрос сегодня, на второй день использования Redux-Observable.

Антипаттерн

Redux-Observable автоматически отправляет подписчику любое действие, которое не выполняется. Из-за этого я придумал другой шаблон для решения той же проблемы в своей статье: Лучшая практика Redux-Observable - это анти-шаблон.

Мое решение для разделения конвейера - это метод dispatch от Redux. Я также требую, чтобы вы не позволяли действиям проходить через конвейер, чтобы убедиться, что вы не отправляете иногда автоматически, а иногда и вручную.

Вот как это выглядит:

Вы сразу должны будете сказать, что это серьезное улучшение. Мало того, что сохраняется последовательное выполнение, но, по логике, это должно иметь большой смысл для людей.

Это также уменьшает глубину перехода на табуляцию и упрощает визуализацию последовательности событий, которые выполняются по порядку. Это действительно отличное решение, и я не смог найти ситуацию, в которой оно сломалось бы.

Следует отметить, что этот метод зависит от синхронного выполнения побочного эффекта. Вызов dispatch в tap - это побочный эффект. Когда вы его вызываете, перед выполнением следующего оператора должна выполняться связка кода редуктора и другие эпики. Это может быть, а может и не быть очевидным сразу. Поскольку Redux выполняет редюсеры синхронно, вот почему это работает так же, как и раньше.

Я считаю, что для большинства людей отправка вручную имеет больше смысла по сравнению с автоматической отправкой. Это более интуитивно понятно, но официально не санкционировано. Фактически, главный разработчик Джей Фелпс назвал это антипаттерном.

Но это не значит ничего плохого. Джей пояснил в Твиттере, что я использую библиотеку не так, как она была задумана, а не то, что я делаю что-то сломанное.

Метод Эверта Боу

Кто такой Эверт и что это за метод? Эверт Боу - участник Redux-Observable и производственный пользователь библиотеки.

После демонстрации Эверту моего метода анти-паттерна на ReactConf 2019 он придумал другое решение, использующее автоматическую отправку:

Ключ к его решению - startWith и endWith. Глядя на этот конкретный пример, он значительно упростил вывод рассчитанных по времени действий. Он даже выделяется точно так же, как и версия с анти-паттерном.

Некоторые предостережения:

  • Вы теряете последовательное выполнение операторов конвейера. startWith должен быть размещен под любыми конвейерами, вычисляющими текущее значение.
  • Вы должны знать, что startWith существует вообще и выполняется первым в конвейере, когда он подписан, перед любыми другими операторами, включая тот, который передает значение.
  • Если вам нужно state$ в endWith, вам нужно будет вернуть оператор concatMap с массивом действий. concatMap принимает функцию обратного вызова, которая гарантирует, что у вас есть state$ в этот момент времени, а не тогда, когда была создана внутренняя наблюдаемая.

Метод Эверта поразил меня. Раньше я использовал startWith и endWith, но никогда не думал об их использовании в этом конкретном сценарии. Это будет огромным подспорьем, когда я проведу рефакторинг существующих проектов, для которых dispatch недоступен.

Вы можете больше!

startWith и endWith принимают несколько аргументов. Каждый выводится отдельно, как если бы вы использовали наблюдаемое of:

Как и в моем примечании выше, имейте в виду, что endWith принимает значение, а не обратный вызов. Чтобы получать самые актуальные значения при запуске, используйте вместо этого concatMap или аналогичный. Я не могу это подчеркнуть, поскольку это вызовет Heisenbugs, если вы не будете осторожны.

Заключение

Какое из этих решений лучше всего работает в ваших проектах? Какие решения вы придумали для решения этой же проблемы?

Я все еще не уверен, будет ли метод Эверта работать в каждом сценарии, но я собираюсь поэкспериментировать с ним и посмотреть. Здесь определенно есть потенциал, но в суперсложных эпосах (вроде тех, которые я, кажется, пишу довольно часто), разделение конвейера или dispatch может быть единственным выходом.

Я призываю вас прокомментировать свои мысли и опыт по этой теме, чтобы мы действительно могли улучшить опыт разработчиков Redux-Observable.

Больше Чтений

Если вам понравилось то, что вы прочитали, ознакомьтесь с другими моими статьями на похожие интересные темы: