0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p><strong>В этой статье мы разберемся, почему использование status enum - или конечного автомата - поможет вашему приложению избежать ошибок, с которыми вы можете столкнуться, используя логические значения.</strong></p>
1
<p><strong>В этой статье мы разберемся, почему использование status enum - или конечного автомата - поможет вашему приложению избежать ошибок, с которыми вы можете столкнуться, используя логические значения.</strong></p>
2
<p><em>Это адаптированный перевод статьи<a>Stop using isLoading boolean</a>Кента Додса, JS-разработчика и преподавателя программирования. Повествование ведётся от лица автора оригинала.</em></p>
2
<p><em>Это адаптированный перевод статьи<a>Stop using isLoading boolean</a>Кента Додса, JS-разработчика и преподавателя программирования. Повествование ведётся от лица автора оригинала.</em></p>
3
<h2>Содержание</h2>
3
<h2>Содержание</h2>
4
<ul><li><a>Про isLoading</a></li>
4
<ul><li><a>Про isLoading</a></li>
5
<li><a>Конечный автомат</a></li>
5
<li><a>Конечный автомат</a></li>
6
<li><a>Вывод</a></li>
6
<li><a>Вывод</a></li>
7
</ul><h2>Про isLoading</h2>
7
</ul><h2>Про isLoading</h2>
8
<p>isLoading (и подобные ему выражения: isRejected, isIdle, isResolved и другие) создают больше проблем, чем решают. Продемонстрирую это на примере эксперимента с<a>API геолокации</a>. Весь код ниже написан на React, но его можно адаптировать к любому фреймворку или языку.</p>
8
<p>isLoading (и подобные ему выражения: isRejected, isIdle, isResolved и другие) создают больше проблем, чем решают. Продемонстрирую это на примере эксперимента с<a>API геолокации</a>. Весь код ниже написан на React, но его можно адаптировать к любому фреймворку или языку.</p>
9
<p>Это классический пример использования логических значений в API геолокации - его используют многие разработчики приложений, которые пишут на JS и других языках. У этого кода есть проблема:</p>
9
<p>Это классический пример использования логических значений в API геолокации - его используют многие разработчики приложений, которые пишут на JS и других языках. У этого кода есть проблема:</p>
10
<p>Если вы видите проблему - отлично. Если нет, разберем еще один пример. Представьте, что пользователь садится в машину и едет по городу. При этом его геолокация меняется, но приложение не успевает ее отследить - например, из-за отсутствия интернета, или невозможности установки текущего положения. Если код построен по тому же принципу, что фрагмент выше, пользователь не увидит ошибки, а приложение будет показывать ему неактуальную геолокацию.</p>
10
<p>Если вы видите проблему - отлично. Если нет, разберем еще один пример. Представьте, что пользователь садится в машину и едет по городу. При этом его геолокация меняется, но приложение не успевает ее отследить - например, из-за отсутствия интернета, или невозможности установки текущего положения. Если код построен по тому же принципу, что фрагмент выше, пользователь не увидит ошибки, а приложение будет показывать ему неактуальную геолокацию.</p>
11
<p>Если показывать геопозицию пользователя только в случае, когда она определена, возникнет противоположная проблема - пользователь видит только сообщения об ошибке, даже если следующие запросы по определению геолокации выполняются успешно.</p>
11
<p>Если показывать геопозицию пользователя только в случае, когда она определена, возникнет противоположная проблема - пользователь видит только сообщения об ошибке, даже если следующие запросы по определению геолокации выполняются успешно.</p>
12
<p><em>Есть несколько решений этой проблемы:</em></p>
12
<p><em>Есть несколько решений этой проблемы:</em></p>
13
<ol><li>Убедиться, что приложение всегда показывает местоположение и ошибку.</li>
13
<ol><li>Убедиться, что приложение всегда показывает местоположение и ошибку.</li>
14
<li>Очистить поле error, если данные о геопозиция получены успешно, или очистить поле position, когда произошла ошибка.</li>
14
<li>Очистить поле error, если данные о геопозиция получены успешно, или очистить поле position, когда произошла ошибка.</li>
15
<li>Вернуть дополнительное свойство, которое определяет текущий статус информации о геопозиции.</li>
15
<li>Вернуть дополнительное свойство, которое определяет текущий статус информации о геопозиции.</li>
16
</ol><p>Большинство приложений разрабатывается таким образом, чтобы пользователь не смог сделать что-то неправильно, даже если ему захочется. Или, по крайней мере, так, чтобы ему было удобнее поступать правильно. Поэтому первый вариант решение проблемы можно сразу исключить.</p>
16
</ol><p>Большинство приложений разрабатывается таким образом, чтобы пользователь не смог сделать что-то неправильно, даже если ему захочется. Или, по крайней мере, так, чтобы ему было удобнее поступать правильно. Поэтому первый вариант решение проблемы можно сразу исключить.</p>
17
<p>Второй вариант решения тоже не идеален: устройства некоторых пользователей могут передавать последние данные о геолокации, даже если произошла ошибка.</p>
17
<p>Второй вариант решения тоже не идеален: устройства некоторых пользователей могут передавать последние данные о геолокации, даже если произошла ошибка.</p>
18
<p>Остается третий вариант. Попробуем реализовать его:</p>
18
<p>Остается третий вариант. Попробуем реализовать его:</p>
19
<p>В этом фрагменте появилась еще одна dispatch, которая поможет нам отличить idle и pending. В данном случае разницы между ними нет, но, в некоторых других ситуациях, нужно разграничивать эти два конечных состояния. Это важный нюанс, на который стоит обратить внимание.</p>
19
<p>В этом фрагменте появилась еще одна dispatch, которая поможет нам отличить idle и pending. В данном случае разницы между ними нет, но, в некоторых других ситуациях, нужно разграничивать эти два конечных состояния. Это важный нюанс, на который стоит обратить внимание.</p>
20
<p>Теперь вместо логических значений мы используем переменную status:</p>
20
<p>Теперь вместо логических значений мы используем переменную status:</p>
21
<p>Использование переменной status вместо isLoading помогает точно узнать, в каком состоянии находится процесс определения геолокации в любой момент времени.</p>
21
<p>Использование переменной status вместо isLoading помогает точно узнать, в каком состоянии находится процесс определения геолокации в любой момент времени.</p>
22
<p>Если вы хотите избавиться от выражений вида variable === 'string' в if, сделайте следующее:</p>
22
<p>Если вы хотите избавиться от выражений вида variable === 'string' в if, сделайте следующее:</p>
23
<p>Здесь возникает пространство для дискуссий - переменные можно хранить в<a>состоянии редьюсера</a>, а не выводить их значения. Однако такой подход делает код уязвимым для<a>невыполнимых состояний</a>.</p>
23
<p>Здесь возникает пространство для дискуссий - переменные можно хранить в<a>состоянии редьюсера</a>, а не выводить их значения. Однако такой подход делает код уязвимым для<a>невыполнимых состояний</a>.</p>
24
<p>Если вы действительно хотите, чтобы вашим пользователям не приходилось использовать variable === 'string', убедитесь, что вы придерживаетесь status в своем состоянии. Это поможет гарантировать, что существует только одно возможное значение конечного состояния. После этого вы можете выводить логические состояния:</p>
24
<p>Если вы действительно хотите, чтобы вашим пользователям не приходилось использовать variable === 'string', убедитесь, что вы придерживаетесь status в своем состоянии. Это поможет гарантировать, что существует только одно возможное значение конечного состояния. После этого вы можете выводить логические состояния:</p>
25
<h2>Конечный автомат</h2>
25
<h2>Конечный автомат</h2>
26
<p><a>XState</a>- это удобная библиотека для реализации<a>конечных автоматов</a>в коде. Посмотрим, как она работает на реальном примере:</p>
26
<p><a>XState</a>- это удобная библиотека для реализации<a>конечных автоматов</a>в коде. Посмотрим, как она работает на реальном примере:</p>
27
<p>Если вы не знакомы с<a>конечным автоматом</a>или с библиотекой XState, возможно, код в этом разделе покажется вам сложным. Любая абстракция становится понятнее со временем, если уделять ей достаточно внимания.</p>
27
<p>Если вы не знакомы с<a>конечным автоматом</a>или с библиотекой XState, возможно, код в этом разделе покажется вам сложным. Любая абстракция становится понятнее со временем, если уделять ей достаточно внимания.</p>
28
<blockquote><h3>Читайте также:</h3>
28
<blockquote><h3>Читайте также:</h3>
29
<p>Как спроектировать<a>правильный конечный автомат</a>на REST</p>
29
<p>Как спроектировать<a>правильный конечный автомат</a>на REST</p>
30
</blockquote><p>В примере выше можно отметить несколько моментов. Во-первых, в нем есть специальное состояние для случаев, когда определение геолокации не поддерживается - это состояние называется терминальным. Оно подходит и для нашего примера - если определение геолокации не поддерживается, невозможно перейти в какое-либо другое состояние. Конечный автомат в текущей реализации гарантирует, что такого никогда не произойдет.</p>
30
</blockquote><p>В примере выше можно отметить несколько моментов. Во-первых, в нем есть специальное состояние для случаев, когда определение геолокации не поддерживается - это состояние называется терминальным. Оно подходит и для нашего примера - если определение геолокации не поддерживается, невозможно перейти в какое-либо другое состояние. Конечный автомат в текущей реализации гарантирует, что такого никогда не произойдет.</p>
31
<p>Во-вторых, в коде больше нет переменной status, которую нужно поддерживать - теперь это лишь часть конечного значения состояния конечного автомата. Другими словами, теперь status встроен в конечный автомат.</p>
31
<p>Во-вторых, в коде больше нет переменной status, которую нужно поддерживать - теперь это лишь часть конечного значения состояния конечного автомата. Другими словами, теперь status встроен в конечный автомат.</p>
32
<p>Вот как мы будем это использовать:</p>
32
<p>Вот как мы будем это использовать:</p>
33
<p>Если вам понравился API выше, вы можете сохранить себе и этот:</p>
33
<p>Если вам понравился API выше, вы можете сохранить себе и этот:</p>
34
<p>Если вам сложно работать с конечным автоматом, то можно найти пример редьюсера, который будет проще и понятнее. Но если вы знакомы с этой абстракцией, изучите<a>реализацию Дэвида Хуршида</a>, автора XState. Он полностью отказывается от useEffect - вместо этого он интегрирует логику подписки в конечный автомат. Это означает, что конечный автомат не зависит от того, какой фреймворк используется в пользовательском интерфейсе.</p>
34
<p>Если вам сложно работать с конечным автоматом, то можно найти пример редьюсера, который будет проще и понятнее. Но если вы знакомы с этой абстракцией, изучите<a>реализацию Дэвида Хуршида</a>, автора XState. Он полностью отказывается от useEffect - вместо этого он интегрирует логику подписки в конечный автомат. Это означает, что конечный автомат не зависит от того, какой фреймворк используется в пользовательском интерфейсе.</p>
35
<h2>Вывод</h2>
35
<h2>Вывод</h2>
36
<p>Этот текст - не столько о пользе status enum и конечных автоматов, сколько о вреде логических значений. Потому что они не могут представлять все фактические состояния, в которых может находиться ваш код в любой момент времени.</p>
36
<p>Этот текст - не столько о пользе status enum и конечных автоматов, сколько о вреде логических значений. Потому что они не могут представлять все фактические состояния, в которых может находиться ваш код в любой момент времени.</p>