@J_K

Как правильно работать со сложной структурой данных в React state?

Всем привет,
суть моего вопроса в том, как правильно работать со state в реакте?
Начну немного издалека. Мое знакомство с миром MVVM началось с knockoutjs - эта поразительная библиотека показала, как легко и быстро обеспечить двухнаправленное обновление данных, достаточно было обеспечить модель и привязку данных к отображению, а все остальное она делала сама. Потом был AngularJS - который делал то же самое, но более структурированно, впрочем, внеся больше хаоса из-за сложностей самих структур. Следующий шаг - Vuejs, и тут, казалось, нет предела совершенству. Впечатление немного портила невозможность изменения данных в обе стороны - props компонента менять не рекомендуется, и приходилось всегда возвращаться к исходной модели и делать изменения там, но это терпимое неудобство. И вот теперь React. Мое решение перейти на него было вызвано чистейшим любопытством - React гораздо популярнее всех других библиотек, и захотелось выяснить, почему.

Поначалу все было просто, однако настоящим камнем преткновения оказался state - и мне пока что не удалось найти внятных объяснений, почему он сделан неизменяемым. Но факт остается фактом - чтобы поменять что-то на странице, надо поменять что-то в стейте и это что-то должно быть полем объекта state. Однако же, если на странице мы хотим иметь массив из 20 элементов, то мы должны их всех добавить в state по одному, как поля, иначе при изменении одной буквы в одном объекте придется менять весь массив, что представляется весьма неэффективным.

Теперь другой пример - дерево. Например, у меня есть меню и я хочу открывать и закрывать его элементы. И каждый элемент может иметь 1-2 вложенных элемента. Эта структура очень часто встречается в развитых приложениях типа дашборда. Но state не позволяет изменить один объект, если этот объект не является частью самого state, поэтому чтобы поменять флажок isOpen размером в один бит, придется пересоздавать заново весь объект дерева.

Некоторые предлагают представлять дерево в виде плоской структуры: https://medium.com/@davidtranwd/implement-tree-vie...

Автор статьи уверяет, что работать с плоской структурой легче - так как легче обновлять данные и легче дебажить такую структуру. С первым вопросом все ясно - действительно, непросто найти вложенный объект, нужно рекурсивно проходить все дерево (ну или не рекурсивно, или не все - в зависимости от выбранного алгоритма поиска, однако, это действительно дополнительный код). И кстати, в его примере все равно придется пересоздавать все дерево целиком. А вот со вторым моментом он, по-моему, загнул. Во-первых, даже создать такую структуру для дерева непросто - нужно делать это очень внимательно (прописывая значения path), ошибиться ничего не стоит. Можно сделать делать меню в виде дерева, и потом его переводить в плоскую структуру, но это опять-таки дополнительный код, а значит, дополнительные баги! А теперь представим, что нам бы хотелось иметь вначале все-таки дерево, но ради удобства работы со state мы переводим его в массив и обратно, OMG...

Встает резонный вопрос - стоит ли овчинка выделки? Ради чего все это, может кто-нибудь внятно и по-человечески объяснить? Мне всегда казалось, что фреймворки нужны лишь для того, чтобы сделать процесс разработки как можно более быстрым и простым, однако React перевернул это мое представление. Некоторые вообще считают, что работать в реакте со сложными структурами нельзя и не нужно: https://stackoverflow.com/questions/43040721/how-t...

Автор ответа считает, что это здорово - помещать все объекты прямо в стейт и менять только отдельный объект, а не весь стейт целиком. Ну, допустим. А теперь представим себе, что нам надо сделать визуальный дизайнер веб-сайта (реальная задача, которую мне пришлось решать в этом году - была успешно реализована с помощью Vue, причем декларативным образом - то есть для отображения DOM не было написано ни строчки кода). Значит, согласно этому мнению, мы берем все объекты на странице и кладем их просто в стейт. При этом каждый элемент должен иметь внутри ссылку на родительский объект (или его идентификатор), чтобы можно было нормально построить DOM, и теперь представьте, насколько сложным будет алгоритм рендеринга, который придется делать вручную, потому что нормальная, логичная - и вложенная, да - структура в стейте не рекомендуется. Нам придется брать каждый элемент, находить для него его детей и потом рекурсивно проходить все сначала.

Дальше, представим, во что превращается сам стейт. Простейшая веб-страница, между прочим, может легко содержать 30-50 элементов, и все это предлагается помещать в стейт плоским образом.

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

Просветите, пожалуйста! Очень интересует мнение опытных товарищей.
Всем спасибо.
  • Вопрос задан
  • 193 просмотра
Пригласить эксперта
Ответы на вопрос 1
Robur
@Robur
Знаю больше чем это необходимо
Зачем стейт сделан так как сделан - хорошо описано в доках и всевозможных гайдах.

Однако же, если на странице мы хотим иметь массив из 20 элементов, то мы должны их всех добавить в state по одному, как поля, иначе при изменении одной буквы в одном объекте придется менять весь массив, что представляется весьма неэффективным.


По какому критерию "неэффективности"? как вы это померяли, какие-то цифры есть? В современных аппах столько всего происходит что создать массив из 20 элементов ничего не значит. Заметьте что элементы массива вам не надо пересоздавать, только сам массив в котором 20 каких-нибудь ссылок. Сложить две строки в одну может быть затратнее.

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

Для хранения данных "вообще" есть сторы уровня приложения, откройте для себя mobx - он позволяет хранить объекты любого уровня сложности, и при этом обновлять компоненты на сколько угодно малой области изменений. В примере выше, если у вас есть массив из 20 объектов, и вы поменяли какое-то поле в одном из них - то при желании можно сделать так чтобы перерендерился и обновился только тот div который это поле рисует и ничего больше. Если вы пришли с Vue то вам будет это совсем близко.

насчет "сложные структуры и легко сделать ошибку" - возьмите тайпскрипт и забудьте о 99% опечаток.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы