От автора: вы когда-нибудь использовали сложное веб-приложение с множеством функций, модальными окнами или боковыми панелями? В которых вы достигаете идеального состояния с нужной информацией на экране после нескольких кликов по разным страницам, но затем случайно закрываете вкладку? (Или Windows решает обновиться?).
Было бы здорово, если бы был способ вернуться в то состояние, не проделывая тот же утомительный процесс. Или иметь возможность поделиться этим состоянием, чтобы товарищ по команде мог работать над тем же, что и вы.
Эту проблему можно решить с помощью диплинков (deep-link), которые сегодня используются в мобильных приложениях для открытия приложения на определенной странице или в определенном состоянии пользовательского интерфейса. Но почему этого нет во многих веб-приложениях?
Возвращение диплинков в Web
Появление одностраничных приложений (SPA) позволило нам создавать новые user experiences, которые мгновенно интегрировались в Web. Делая больше на стороне клиента с помощью JavaScript, мы можем немедленно реагировать на пользовательские события, от открытия пользовательских диалоговых окон до текстовых редакторов, таких как Google Docs.
Традиционные серверные веб-сайты каждый раз отправляют запрос на получение новой HTML-страницы. Отличным примером является Google, который отправляет запрос на свои серверы с поисковым запросом пользователя в URL-адресе: https://www.google.com/search?q=your+query+here. Что хорошего в этой модели, так это то, что если я отфильтрую результаты за последнюю неделю, я могу поделиться одним и тем же поисковым запросом, просто поделившись URL-адресом: https://www.google.com/search?q=react+js&tbs=qdr:w. И эта парадигма совершенно естественна для веб-пользователей — обмен ссылками был частью всемирной паутины с момента ее изобретения!
Когда появились SPA, нам не нужно было хранить эти данные в URL-адресе, поскольку нам больше не нужно было делать запрос к серверу, чтобы изменить то, что отображается на экране. Но это позволило легко потерять уникальный experience, ссылку, которой можно поделиться.
Настольные и мобильные приложения никогда не имели стандартизированного способа создания ссылки на определенные части приложения, а современные реализации диплинков полагаются на URL-адреса в Интернете. Итак, когда мы создаем веб-приложения, которые больше похожи на нативные приложения, зачем нам отказываться от функциональности диплинков URL-адресов, которая была у нас десятилетиями?
Очень простые диплинки
При создании веб-приложения с несколькими страницами как минимум необходимо изменить URL-адрес при отображении другой страницы, например /login и /home. В экосистеме React, React Router идеально подходит для такой маршрутизации на стороне клиента, а Next.js — отличная полнофункциональная среда React, которая также поддерживает рендеринг на стороне сервера.
Но я говорю о диплинках, вплоть до состояния пользовательского интерфейса после нескольких кликов и ввода с клавиатуры. Это очень полезная функция для веб-приложений, ориентированных на производительность, поскольку она позволяет пользователям вернуться прямо к тому месту, где они находились, даже после закрытия приложения или обмена ссылкой с кем-то еще, чтобы тот мог начать работу без каких-либо проблем.
Вы можете использовать npm пакеты, такие как query-string, и написать базовый React Hook для синхронизации параметров URL-запроса с вашим состоянием, и для этого есть множество руководств, но есть более простое решение.
Изучая современные библиотеки React для управления состоянием, для переписывания архитектуры нашего React-приложения, я наткнулся на крошечную библиотеку состояний Jotai, вдохновленную библиотекой Recoil команды React.
Основное преимущество этой модели заключается в том, что части состояния объявлены независимыми от иерархии компонентов, и ими можно манипулировать из любого места в приложении. Это решает проблему с React Context, вызывающую ненужную повторную визуализацию, которую я ранее обходил с помощью useRef. Вы можете прочитать больше о концепции атомарного состояния в документации Jotai, а более техническую версию — в документации Recoil.
Код
В Jotai есть тип под названием atomWithHash, который синхронизирует атом состояния с хешем URL. Предположим, мы хотим, чтобы открытое состояние модального окна сохранялось в URL-адресе. Начнем с создания атома:
1 2 3 |
import { atomWithHash } from "jotai/utils"; export const modalOpenAtom = atomWithHash("modalOpen", false); |
Затем в самом модальном компоненте мы можем использовать этот атом точно так же, как useState:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { useAtom } from "jotai"; import { modalOpenAtom } from "./atoms"; function ExampleModal() { const [open, setOpen] = useAtom(modalOpenAtom); return ( <Dialog open={open} onClose={() => setOpen(false)} ... /> ) } |
Вот как это выглядит:
И это все! Это так просто. Что замечательно в atomWithHash от Jotai, так это то, что он может хранить любые данные, которые может использовать useState, и автоматически упорядочивает объекты для хранения в URL-адресе. Таким образом, я могу хранить более сложное состояние в URL-адресе, делая его доступным для совместного использования.
В Rowy мы использовали эту технику для реализации пользовательского интерфейса для облачных логов. Мы создаем платформу с открытым исходным кодом, которая упрощает разработку бэкэнда и устраняет разногласия в стандартных рабочих процессах. Таким образом, снижение разногласий при совместном использовании логов было для нас идеальным. Вы можете увидеть это в действии на демонстрации, где я могу связать вас с конкретным логом развертывания:
1 |
https://demo.rowy.io/table/roadmap#modal="cloudLogs"&cloudLogFilters={"type"%3A"build"%2C"timeRange"%3A{"type"%3A"days"%2C"value"%3A7}%2C"buildLogExpanded"%3A1} |
Декодирование компонента URL показывает точное состояние, используемое в React:
1 2 3 4 5 |
cloudLogFilters = { "type": "build", "timeRange": { "type": "days", "value": 7 }, "buildLogExpanded": 1 } |
Дополнительный эффект atomWithHash заключается в том, что он по умолчанию отправляет состояние в историю браузера, поэтому пользователь может нажимать кнопки «назад» и «вперед» для перехода между состояниями пользовательского интерфейса.
Это поведение является необязательным и может быть отключено с помощью параметра replaceState:
1 2 3 |
const modalOpenAtom = atomWithHash("modalOpen", false, { replaceState: true, }); |
Спасибо за чтение! Я надеюсь, что это убедило вас показать больше состояния вашего пользовательского интерфейса в URL-адресе, сделав его доступным и уменьшив неудобства для пользователей, особенно потому, что это легко реализовать.
Автор: Sidney Alcantara
Источник: betterprogramming.pub
Редакция: Команда webformyself.
Читайте нас в Telegram, VK, Яндекс.Дзен