Содержит реализацию шаблона проектирования 'хранилище' и его вариации.
Подключите этот пакет в зависимости:
npm i -S @devim-front/store
Хранилище - это сервис, который использует механизмы библиотеки mobx.
Хранилища являются средством взаимодействия сервисов и компонентов React. Так как сервисы по своей сути - событийно-ориентированный и асинхронный механизм, а дерево React лучше всего работает с цепочкой последовательных и синхронных изменений, следует выделить прослойку между этими архитектурными слоями. Именно для этой цели используются хранилища.
Хранилища сводят асинхронный алгоритм к последовательности состояний, которые используют компоненты React. Для примера рассмотрим процедуру авторизации. Пользователь ввел логин, пароль и отправил форму. Хранилище должно отправить эти данные на сервер, получить оттуда токен авторизации или ошибку, если введённые данные оказались неверны. Начальное состояние (перед отправкой):
{
loading: false,
token: undefined,
error: undefined
}
После того, как пользователь отправил форму, состояние хранилища изменилось:
{
loading: true,
token: undefined,
error: undefined,
}
Опираясь на это состояние (а конкретно на значение loading
), мы можем показать индикатор загрузки. Далее, допустим, авторизация прошла успешно, и сервер вернул токен авторизации. Состояние изменилось:
{
loading: false,
token: 'token',
error: undefined,
}
Теперь, имея указанный токен, мы можем, например, перенаправить пользователя в его личный кабинет, используя компонент Redirect из библиотеки react-router-dom.
Но, допустим, пользователь ввёл неверный пароль. Состояние для этого:
{
loading: false,
token: undefined,
error: Error,
}
В этом случае мы можем показать пользователю соответствующее уведомление.
Если приложение использует хранилища, задача компонентов сводится к тому, чтобы отобразить текущее состояние и пробрасывать действия пользователей на более высокий слой абстракции. Таким образом (и это важно), если в приложении есть слой хранилищ, то внутри компонентов не должно быть асинхронных функций.
Хранилища являются прямыми наследниками сервисов. Всё, что было сказано про сервисы в соответствующей статье, справедливо и для хранилищ. Следовательно, хранилища также делятся на свободные (FreeStore), строгие (StrictStore) и ленивые (LazyStore); и точно так же имеют поддержку событий и механизм dispose
.
Документация находится в этом разделе.
Продолжим наш пример из статьи о сервисах. Чтобы компоненты смогли обрабатывать глобальные ошибки приложения, нужно создать специальное хранилище.
// ErrorStore.ts
import { LazyStore } from '@devim-front/store';
import { observable, action, computed } from 'mobx';
import { ErrorService } from './ErrorService';
export class ErrorStore extends LazyStore {
@observable
public error?: Error;
public get isError() {
return this.error != null;
}
@action
private handleError = (error: Error) => {
this.error = error;
};
@action
reset() {
this.error = undefined;
}
public constructor() {
super();
ErrorService.get().on('error', this.handleError);
}
public dispose() {
super.dispose();
ErrorService.get().off('error', this.handleError);
}
}
Теперь на возникновение глобальной ошибки могут отреагировать компоненты React. Как пример использования хранилища создадим компонент, который перенаправляет пользователя на страницу авторизации, если возникло исключение типа NotAuthorizedError
:
import React, { FC } from 'react';
import { Redirect } from 'react-router-dom';
import { observer } from 'mobx-react';
import { NotAuthorizedError } from './NotAuthorizedError';
import { ErrorStore } from './ErrorStore';
const NotAuthorizedRedirect: FC = () => {
const { error } = ErrorStore.get();
const isRedirect = error instanceof NotAuthorizedError;
if (!isRedirect) {
return null;
}
ErrorStore.get().reset();
return <Redirect to="/sign-in" />;
};
const component = observer(NotAuthorizedRedirect);
export { component as NotAuthorizedRedirect };