Хранимые и вычисляемые данные
Состоянием приложения являются данные, сохраняемые в памяти на определённом этапе его работы. Очень важно понимать, что не любые данные и не в любой ситуации имеет смысл куда-либо сохранять.
«Плохие программисты думают о коде. Хорошие программисты думают о структурах данных и их взаимосвязях»
— Линус Торвальдс, создатель Linux.
Хранимые данные
Представьте себе компонент, отображающий некий список с возможностью фильтрации.
Я неоднократно встречал реализации подобных компонентов, предполагающие сохранение отфильтрованного списка в состоянии.
При такой реализации мы получаем два состояния, которые на уровне кода не имеют никакой связи между собой.
Значения, которые мы явным образом сохраняем в некоторое состояние, называются хранимыми (stored).
Но с концептуальной точки зрения данные в таком случае имеют взаимосвязи, а именно: результаты фильтрации напрямую зависят от исходного списка и параметров фильтрации. Если код не отражает эту идею и данные хранятся обособленно, то мы можем, например, в какой-то момент при изменении одного из значений забыть изменить второе, и состояние перестанет быть
Такой подход может быть актуальным при проектировании больших распределённых систем (
Вычисляемые данные
Значения, которые мы можем вычислить на основе уже имеющихся данных, называются, как вы можете догадаться, вычисляемыми (computed/derived).
С помощью вычисления «на лету» мы избавляемся от одного совершенно ненужного состояния.
Оптимизация вычисляемых данных
В процессе отладки может выясниться, что функция фильтрации достаточно ресурсоёмкая и выполнение её в каждом рендере будет неэффективным, появится соблазн всё-таки сохранять результаты её выполнения в состояние из соображений оптимизации.
Такие рассуждения имеют смысл, но ввиду явного наличия дополнительного состояния код становится гораздо менее декларативным и не в полной мере отражает суть решаемой задачи.
На самом деле задача оптимизации в данном случае может быть решена с помощью мемоизации вычислений.
Чисто технически мемоизация тоже создаст некоторое состояние для компонента, но это состояние инкапсулировано внутри функции мемоизации и мы не можем влиять на него напрямую, за счёт чего код гораздо лучше отражает суть задачи и не позволяет нам сделать лишних действий.
Зависимости React-хуков
При проектировании состояния без анализа его концептуальной структуры также можно столкнуться с необходимостью проигнорировать правила для React-хуков, которые
Заключение
Проектировать состояние приложения стоит таким образом, чтобы хранимым был согласованный набор данных, необходимый и достаточный для работы приложения, а все остальные данные, которые делают этот набор избыточным, стоит вычислять «на лету», при необходимости добавляя кеш или мемоизацию.