What is Mobx
A simple and expandable state management tool
install
npm install mobx --save
Core concept
State
State is the data that drives the application, and the change of state will affect the view.
import {observable, autorun} from 'mobx'; var todoStore = observable({ /* Some observed states */ todos: [] });
Derivations (derivative)
Anything that comes from a state and no further interaction is a derivation.
import {observable, autorun} from 'mobx'; var todoStore = observable({ /* Some observed states */ todos: [], /* Derived value */ get completedCount() { return this.todos.filter(todo => todo.completed).length; } });
Note: derived values must be pure functions
Actions
An action is a piece of code that changes state. User events, back-end data push, scheduled events, and so on.
Usage principle
MobX supports one-way data flow, that is, action changes state, which updates all affected views.
1. When the state changes, all derivatives will be automatically updated at the atomic level.
2. All derivatives are synchronized by default. This means that an action, for example, can safely check the calculated value directly after changing the state.
3. The calculated value is delayed to update. Any calculated value that is not in use will not be updated until it is required for side effect (I / O) operations If the view is no longer in use, it is automatically garbage collected.
4. All calculated values should be pure. They should not be used to change state.
for instance:
import { observable,computed, action } from 'mobx'; class ObservableTodoStore { //Define responsive state @observable todos = []; @observable pendingRequests = 0; //Derived value @computed get completedTodosCount() { return this.todos.filter( todo => todo.completed === true ).length; } @computed get report() { if (this.todos.length === 0) return "<none>"; return `Next todo: "${this.todos[0].task}". ` + `Progress: ${this.completedTodosCount}/${this.todos.length}`; } //action @ction addTodo(task) { this.todos.push({ task: task, completed: false, assignee: null }); } } const observableTodoStore = new ObservableTodoStore();
Using decorators@
The decorator will look more friendly. Use Babel preset mobx
npm install --save-dev babel-preset-mobx
Configure in package.json after installation
Resolve asynchronous update state
class Store { //Defined state @observable listData = [] @observable state = "pending"; //Asynchronous behavior changes state, such as requesting data from the server @action async fetchProjects() { this.state = "pending" try { const filteredProjects = await ajaxData(); // After await, modifying the status again requires action: runInAction(() => { this.state = "done" this.listData = filteredProjects }) } catch (error) { runInAction(() => { this.state = "error" }) } } }
runInAction is a utility function. Instead of creating an action for the entire callback, run only the part of the callback that changes the state The advantage of this pattern is that it encourages you not to write actions everywhere, but to modify as many states as possible at the end of the process.
A complete example:
The whole application state management portal:
import React from 'react'; import ReactDOM from 'react-dom'; import { ConfigProvider } from 'antd'; import App from './App'; import zhCN from 'antd/es/locale/zh_CN'; import { Provider } from 'mobx-react'; import stores from '@/stores' ReactDOM.render(<ConfigProvider locale={zhCN}> <Provider {...stores}><App /></Provider> </ConfigProvider>, document.getElementById('root'));
store unified management:
import permissionStore from './permission'; const stores={ permissionStore } export default stores;
Define single file store
import { observable, action, runInAction } from 'mobx'; import $http from '@/utils/http'; class PermissionStore { @observable menus = []; @action async fetchMenus() { try { let menus = await this.handleFetchMenus(); runInAction(() => { this.menus = menus; }) } catch (error) { } } handleFetchMenus() { return $http("/permission/menuList").then(resp => { if (resp && resp.items && resp.items.length) { return resp.items; } }); } } export default new PermissionStore();
Component binding
import React from 'react'; import { observer, inject } from 'mobx-react' @inject('permissionStore');//Import the corresponding store @observer class SideMenu extends React.Component { constructor(props) { super(props); } componentDidMount() { const { permissionStore } = this.props;//Get store from props permissionStore.fetchMenus();//Asynchronous action in store } //Generate menu bar renderMemu = () => { let { menus } = this.props.permissionStore;//Get status. At this time, the data is the updated data status after asynchronously getting from the server return ( ... ) } render() { return ( {this.renderMemu()} ) } } export default SideMenu
mobx involves three core concepts: State, derivatives and Actions. It is very simple and clear to use and can be used quickly. It is a good State management tool. github star has 21K.