Обзор библиотеки lens-js и эксперименты с котиками. Данные — это, в действительности, важная часть Вашего будущего приложения или отдельной библиотеки. Важна их структура, целостность, а также и подходы к организации их хранения и обработки. Задача, прямо скажем, не тривиальна, особенно в масштабах корпоративных проектов. Одно из решений — использование менеджера состояния, об одном из которых, тут пойдёт речь. И так, что же такое «Линзы»? Проще всего ответить тезисно - линзы это: принцип организации работы с данными, где те квантуются по отдельным узлам в одном большом направленном графе; агрегатор (редьюсер), который занимается сборкой всех отдельных квантов по всем правилам функциональной парадигмы; интерфейс, который обеспечивает доступ к данным каждого кванта; и последнее, линза обеспечивает целостность данных и их актуальность в Вашем приложении. Тут вот стоит отметить, что мы ещё не говорим о как-либо реализации. Линза — это не детерминированная библиотека. Реализаций линз — множество. Попробуйте их все! Линза представляет собой структуру (направленный граф) из множества контроллеров (узлов), за каждым из которых закреплён адрес в неких данных. Все контроллеры могут что-то записывать и считывать по своему адресу, а также взаимодействовать между собой, воссоздавая конечное состояние приложения. Чем объяснять на пальцах, гораздо проще сделать это на каком-нибудь примере. Будем экспериментировать на котиках. Не волнуйтесь! Ни один котик не пострадает! Следующие примеры взяты из проекта react-lens-cats, разработанного на основе линз. В нём используется библиотека — react-lens. Давайте представим, что несколько котиков решили прокатиться на карусели. Нам нужно организовать их очередь и распределить занятые места между ними. Формально это означает следующее: Нужно реализовать два массива, между которыми котики будут перемещаться. Нужно отследить изменение в данных, чтобы наше приложение могло корректно отобразить актуальное состояние. Пусть структура данных выглядит следующим образом: Давайте создадим наше состояние и объявим линзу в файле lens.ts Пока всё легко и понятно? Но не будем отвлекаться, а то получится как на матане. Как можно заметить, мы экспортируем только константу store, относительно которой и будем работать с состоянием. Это синглтон, детка. Для начала, создадим Lenapark.tsx и попробуем просто получить доступ к свойствам нашего состояния, используя API линзы. Теперь мы можем видеть имена наших котиков. Выражение выглядит пугающе, но в процессе заполнения можно заметить, что благодаря типизации, имена полей предлагаются средой разработки, что весьма удобно. Но постойте, судари! У нас тут что-то не так с кодом! И действительно, массивы circle и  street одинаковы, а код избыточен. Выгоднее реализовать универсальный способ, который отобразит только типизированный массив котиков, откуда бы мы его не передали. А давайте, просто, передавать узел линзы, как параметр некого компонента, который уже и будет отображать элементы массива, вот так: Тогда файл Lunapark.tsx будет выглядеть следующим образом: Всё ещё сложно. Для чего мы постоянно обращаемся к корневой линзе? Нам же не так и важно, где хранятся массивы котиков? Можно пойти дальше и сделать Lenapark.tsx тоже универсальным: Как ловко мы тут всё инкапсулировали... Другое дело! Теперь мы сможем использовать наш Lunapark.tsx в на любом узле линзы, где встречается похожая структура - ILunapark . Таким образом, мы можем создавать целые модели компонентов, которые будут также универсальны, как и рядовые. И действительно, поскольку каждый узел линзы является объектом, адресующим некие данные в глобальном состоянии, то его передача в качестве аргумента ничем не отличатся от передачи простого значения. Однако в случае линз, мы уже получаем механизм отслеживания изменений в узле по средствам useLens. Теперь дело за малым, переместить котиков из одного массива в другой. Давайте в нашем Lunapark.tsx создадим кнопку с обработчиком, где мы и завершим нашу задумку. Обратите внимание, что обработка изменений уже реализована внутри линзы по средствам useLens, т. е. после изменения данных в узлах cats, связанные компоненты будут обновлены. Линзы — это не строго привязанная, к какой-либо технологии, библиотека. Их успешно можно применять там, где не подходят привычные подходы. Например, при создании динамических сцен на BabylonJS или внутреннего состояния Web-компонентов и т. п. Линзы — не аналог Redux или похожих технологий и, как следствие, могут применяться совместно, как абстракция более низкого уровня. Всё дело в воображении… Что, уже? Да. Целью статьи было познакомить читателя с ещё одним подходом для организации состояния приложения. Мы рассмотрели самое-самое главное — потенциал к масштабируемости и области применения. Давайте подытожим! С помощью линз можно: реализовывать состояние приложения; разрабатывать общие компоненты и модели; организовывать событийно-ориентированные подпрограммы; создавать абстракции для работы с другими подходами к управлению состоянием. Wiki по lens-js Проект с котиками на lens-js Пакет react-lens на npm Пакет lens-ts на npm Пакет lens-js на npm Статья про другие линзы Ещё интересный пост про линзы