В данной статье я расскажу и покажу на примерах, как реализовать глобальное хранилище состояния в React или Next, и зачем вообще оно нужно. Очень популярно сейчас реализовывать это на Redux, но на мой взгляд реализация на Redux хуже воспринимается, сложнее для новичков, и требует больше кода.  Мы же будем использовать useGlobalHook, я постоянно использую его при разработке проектов, и на мой взгляд, он очень удобен.  (Сразу скажу, что это не реклама, т.к. я не являюсь автором useGlobalHook, и пишу этот пост исключительно из за того, что он мне нравится. Хочу научить этому способу нескольких своих учеников, а заодно делюсь и с вами). Я не мог отказаться от этого абзаца, так как кто-то может не знать ответ на этот вопрос.  Если вы начинающий разработчик использующий React, то скорее всего уже сталкивались с хуком useState. На всякий случай разберём его использование на простом примере: При нажатии на кнопку с именем, блок с H1 будет перерисован, и будет отображаться выбранное имя. При этом перезагрузки страницы не произойдёт. Это то, для чего нам нужен useState.  Когда мы создаём переменную useState, мы объявляем две переменные - в первой (userName) будет храниться значение, а вторая (setUserName) служит функцией для записи значения в первую переменную. Когда мы меняем значение переменной, перерисовывается та часть проекта, в которой используется эта переменная без перезагрузки страницы. Однако часто бывает, что нам нужна возможность использовать одну и ту же переменную в разных частях проекта, более того - мочь задать ей значение из разных частей проекта, и чтобы при изменении значения переменной, перерендеривалась та часть проекта, в которой используется эта переменная. Например, мы хотим хранить имя пользователя, и отображать его в разных компонентах (в шапке приложения, в модальных окнах, и тд), а так же еще некоторые данные, которые используются в разных местах проекта.  Как же быть? Поскольку пример простой, может показаться хорошей идеей пробрасывание через props, но в реальных проектах вы можете столкнуться с тем, что нужно будет пробрасывать более чем через один компонент, что создаст очень сложную систему.  Должен быть более простой способ! Из всех существующих мне больше нравится useGlobalHook, поэтому перейдём сразу к нему. Первым делом установим npm-пакет use-global-hook Или если вы как я используете yarn, то Далее создадим определённую файловую структуру: В папке src создадим папку store В папке store создадим файл index.js со следующим содержанием: В переменной initialState мы перечисляем абсолютно все переменные, которые мы хотим чтобы были доступны из любой части проекта. А что же там за import * from "./actions"? Дело в том, что изменять значение глобальных переменных мы сможем только через специальные функции, которые мы напишем чуть позже. Такие функции называются actions, поэтому хранить мы их будем в папке actions.  Создайте эту папку в папке src/store, и создайте в ней файл index.js. Для удобства восприятия и модификации кода, мы не будем писать все функции изменения глобального состояния в одном файле. Вместо этого, мы разделим эти функции на логические группы, и создадим для каждой группы отдельный файл в папке actions.  В /src/actions/index.js мы будем импортировать функции из этих файлов. Давайте попытаемся представить реальную ситуацию - авторизация пользователя. Мы должны обратиться к бэкенду, отправив email и пароль, а бэкенд вернёт нам данные пользователя, а именно - его имя и роль. Мы должны будем записать их в наше глобальное хранилище, после чего вывести в определённых компонентах. В какую логическую группу мы можем определить эту функцию? Правильно, система авторизации. Поэтому мы создадим в папке actions файл sign.js Прежде чем писать нашу функцию, мы должны импортировать все функции из файла sign.js в файл src/actions/index.js, а также экспортировать их из этого файла, чтобы в дальнейшем использовать их через useGlobalHook. Вот как мы это делаем: Напишите в файл src/actions/index.js следующее: Хорошо, давайте теперь напишем нашу функцию авторизации, где будет получение данных с бэкенда и изменения глобальных стейтов. Поскольку это функция авторизации (по английски signin) в файле src/actions/sign.js создадим функцию In, и экспортируем её: Обратите внимание на важную вещь! Когда мы объявляем экшены useGlobalHook (т.е. создаём такие функции), мы всегда в них принимаем первым аргументом "store". Через store мы можем взаимодействовать с глобальным хранилищем внутри этой функции следующими способами: Изменять глобальные переменные: Получать значение глобальной переменной (внутри этой функции): Вызывать другую функцию изменения глобального значения (другой экшен): Таким образом мы взаимодействуем с глобальным хранилищем внутри функций-экшенов.  Вне подобных функций мы взаимодействуем с ним другим способом, о котором я сейчас как раз таки и расскажу. Давайте создадим тестовую страницу, на которой мы будем имитировать авторизацию. Смотрите, нам нужно сначала ввести email и пароль, а их следует записать в переменную. Эти данные нам не нужны глобально, поэтому мы будем использовать обычный useState.  Это важно - не нужно запихивать в глобальное хранилище то, что используется только лишь на одной странице, или только лишь в одном компоненте! Каркас готов, теперь мы должны в нём использовать наше глобальное хранилище. Давайте для простоты примера сделаем так: если наша глобальная переменная user_name пуста, мы будем показывать форму авторизации. Если же в ней что-то есть, мы будем показывать надпись "%Имя%, вы успешно авторизовались!". Для доступа к глобальным стейтам и экшенам мы делаем следующее. В любом компоненте, где они нам нужны, мы пишем так: Смотрите, в globalState у нас находятся наши глобальные переменные, а в globalActions наши глобальные функции-экшены. Давайте для начала в нашей странице авторизации создадим условие, о котором я писал выше - если имя пользователя пустое, показываем авторизацию, если нет, то сообщение в которой задействуется эта переменная. Для удобства я деструктурирую из globalState те свойства, которые нам нужны. В данном примере мы будем использовать переменную user_name, давайте её деструктурируем: Всё, мы можем получать значение из глобальной переменной user_name внутри этой страницы! (Чтобы получить значение на другой странице или в другом компоненте, мы делаем то же самое). Давайте напишем условие о котором я писал выше. Теперь наша страница авторизации выглядит так: Мы научились использовать значения глобальных переменных, а теперь давайте научимся вызывать функции-экшены, которые изменяют эти значения. Нам нужно при клике на кнопку "авторизоваться" вызвать глобальную функцию In, которая находится в файле sign. Давайте для удобства деструктурируем функции файла sign из globalActions в переменную sign: Помните как мы импортировали функции из файла sign в store/actions/index.js и экспортировали их оттуда? Поэтому их теперь можно вызывать из globalActions.sign.  Когда у нас будет несколько логических групп (файлов-экшенов), они будут вызываться также - мы создаём отдельный файл в store/actions/, пишем там все функции этой логической группы, далее импортируем их в store/actions/index.js и экспортируем оттуда как выше я объяснял. И у нас получается конструкция вызова следующая:  Чтобы каждый раз не прописывать перед вызовом функции "globalActions.", мы будем деструктурировать группы функций, как я описал выше. Теперь нам нужно по клику на кнопку вызвать функцию In и передать в неё email и password: Обратите внимание на важный аспект! Когда мы объявляли функцию In, первым аргументом в ней был store, а email уже вторым, а password третьим: А когда мы её вызываем, мы указываем email первым аргументом!  Это особенность функций-экшенов useGlobalHook - когда мы их вызываем, мы не передаём первый аргумент store, но в функции всегда первым аргументом мы ожидаем store, чтобы мочь взаимодействовать внутри функции с глобальным хранилищем. Запомните, это очень важно! Итак, наш тестовый пример готов. Вот итоговый код страницы авторизации: Надеюсь логика использования глобальных переменных и функций для их изменения понятна. Если нет - внимательно перечитайте статью ещё раз. Пример получился большой, но в действительности поняв эту систему, пользоваться ей очень легко и удобно. Не редко бывает, что нужен какой то быстрый способ изменить любую глобальную переменную, чтобы не писать функцию для изменения значения именно этой переменной. Для этого я придумал универсальную функцию изменения любой глобальной переменной. Давайте её напишем, и научимся использовать! В файл store/actions/index.js добавьте функцию changeStates, теперь этот файл выглядит вот так: Теперь в любом React-компоненте мы можем изменять значение одной или нескольких глобальных переменных вот таким образом: Примеры рассматриваемые в статье очень простые, но при помощи этих приёмов вы сможете реализовать любую сложную логику, требующую наличия глобального хранилища.  Я специально не отвлекался на лишнее, и показал только то, что необходимо для того чтобы понять, как использовать useGlobalHook. Теперь этот инструмент в ваших руках. Я использовал его в многих серьёзных проектах, и если передо мной встаёт выбор какой менеждер глобального хранилища использовать - я всегда выбираю именно useGlobalHook, он удобен, и хорошо зарекомендовал себя в моих глазах. Это лишь один из вариантов реализации глобального хранилища. Есть еще другие, такие как популярный Redux, MobX, React.Context. Мне из перечисленных полюбился именно useGlobalHook, поэтому я решил поделиться с вами как я его использую, и надеюсь, что кому то эта информация будет полезна. Я не хочу разводить холивар среди любителей других менеджеров состояния на тему "какой круче". Просто попробуйте использовать useGlobalHook, и сравните ощущения. И успехов в разработке ваших проектов.  full-stack разработчик, team-lead, наставник