Mobx: библиотека глобальных сторов (state manager)
- пятница, 14 июля 2023 г. в 00:00:17
Mobx — это библиотека, дающая разработчикам инструмент для глобального использования переменных и методов между разными компонентами.
Mobx простая и понятная в использовании библиотека, использующая в своей реализации Context API и, по сравнению с Redux, требующая минимум шаблонного кода для инициализации стора.
Mobx сторы хорошо масштабируются и для каждого стора можно определить его область видимости, помещая соответствующие компоненты внутрь провайдеров стора.
Глобальный стор упрощает передачу параметров между компонентами, изменение которых вызывает ререндер активного интерфейса.
Также в сторах удобно хранить общие методы — будь то api‑запросы или парсеры данных — которые используются в разных компонентах, но которые сложно передавать передавать между ними по дереву компонентов.
Наглядно поток передачи параметров между компонентами без и с Mobx показан на слайде:
Mobx стор состоит из двух частей — самого стора с данными и провайдера этого стора.
Провайдер отвечает за хранение стора между ререндерами и за инкапсуляцию компонентов, которые будут использовать этот стор. Также через компонент провайдера передаются исходные значения для стора. А в файле с провайдером объявляется кастомный хук для получения сохраненного стора в компоненте.
Стор в сущности функция‑генератор, которая возвращает объект. Свойства и методы этого объекта будут доступны во всех компонентах внутри провайдера, и при изменениях этих свойств будет происходить ререндер виртуального DOM.
Файловую архитектуру лучше разграничить так, что после объявления провайдера и стора, файл провайдера изменяться не будет, но из него мы только будем импортировать компонент провайдера и хук возвращающий сохраненный в контексте стор.
Изменяться и дополняться новыми атрибутами, таким образом, будет только объект стора, находящийся в отдельном файле, но помните, что фактически в компоненты из него напрямую ничего импортироваться не будет.
Для того чтобы начать использовать Mobx в react-приложении его нужно установить:
npm i mobx mobx-react-lite
Затем чтобы объявить стор, создадим в корне проекта папку stores, и в ней папку для нового стора - AppStore. В этой папке создадим два файла - для провайдера и для обьекта-стора соответственно. Также можно добавить в папку index.js, чтобы задать импорт провайдера из папки AppStore по дефолту.
Файловая структура стора, таким образом, будет выглядеть так:
/stores
/AppStore
AppStoreProvider.jsx
AppStore.js
index.js
Давайте обьявим провайдер и стор, в котором будет глобальная переменная test и метод для ее изменения toggleTest:
AppStoreProvider.jsx
import { createContext, useContext } from 'react';
import { observer, useLocalObservable } from 'mobx-react-lite';
import { createAppStore } from './AppStore';
const Context = createContext(null);
export const AppStoreProvider = observer(({ children, ...props }) => {
const store = useLocalObservable(() => createAppStore(props));
return <Context.Provider value={store}>{children}</Context.Provider>;
});
export const useAppStore = () => {
const store = useContext(Context);
if (!store) throw new Error('Use App store within provider!');
return store;
};
AppStore.js
export const createAppStore = (props) => {
return {
test: props.test || 'Hello world',
toggleTest: function () {
this.test = this.test === 'Hi!' ? 'How are you?' : 'Hi!';
},
};
};
После создания провайдера и стора нужно обернуть компоненты, использующие стор, в провайдер. Это нужно для доступа к объектам хранилища.
Сделать это можно где угодно, главное, чтобы компонент, который будет использовать стор имел на каком то уровне своим предком компонент провайдера. В большинстве приложений лучше оборачивать компоненты в провайдер на уровне корневого компонента приложения:
import React, {} from 'react';
import {AppStoreProvider} from '~store/AppStore'; // index.jsx
import {MyComponent} from './MyComponent';
export const App = () => {
return (
<AppStoreProvider>
<MyComponent />
</AppStoreProvider>
);
}
Также, здесь мы можем передать исходные значения для стора:
Затем мы можем использовать стор в компоненте.
Для того, чтобы компонент ререндерился при изменении стора, его самого нужно обернуть в функцию observer из библиотеки mobx‑react‑lite.
Сохраненный стор получают из кастомного хука useAppStore:
import React from 'react';
import {observer} from 'mobx-react-lite';
import {useAppStore} from '~store/AppStore'; // index.jsx
export const MyComponent = observer(() => {
const appStore = useAppStore();
return (
<>
<h1>{appStore.test}</h1>
<button onClick={() => appStore.toggleTest()}>Toggle</button>
</>
);
});
Также с помощью Mobx можно создать локальное хранилище для отдельного компонента. Доступ к небу будет только у этого компонента. Это удобно, если логику нескольких useState нужно вынести за область компонента. Также в локальное хранилище можно вынести некоторые методы, чтобы разгрузить тело компонента. Для добавления локального хранилища его нужно инициализировать в компоненте:
const localStore = useLocalStore();
И объявить само хранилище в отдельном файле файле:
import { useLocalObservable } from 'mobx-react-lite';
const createLocalStore = (props) => {
return {
hello: props.hello || 'Hello world',
toggleHello: function () {
this.hello = this.hello !== 'Hi!' ? 'How are you?' : 'Hi!';
},
};
};
export const useLocalStore = (props = {}) => {
return useLocalObservable(() => createLocalStore(props));
};
На примере видно, как просто обьявить mobx стор и вызывать его в компоненте.
Определенно, преимуществом Mobx по сравнентю с Redux является простота - как в обьявлении так и в поддержании сторов. Цепочка вызова в Mobx простая - обьявляете переменную или метод в сторе и достаете ее из хука в компоненте - не нужно иметь дело ни с какими редисерами и мидлварами.
Так что используйте Mobx и избегайте редукса головного мозга :)
Ссылка на документацию:
https://mobx.js.org/react-integration.html
спасибо