MobX is for state management, simple and efficient. This article on React explains how to get started, including:

  • Understand MobX concepts
  • Prepare the React application from zero
  • MobX React. FC
  • MobX React.Com ponent of writing

Ikuoku.github. IO /start-react: github.com/ikuokuo/sta… .

concept

First, the UI is generated by state via fn:

ui = fn(state)
Copy the code

In React, fn, the component, renders according to its state.

What if state is shared, one state update, multiple component responses? This is where MobX comes in.

MobX data flows as follows:

UI relentless action → stateCopy the code

The UI triggers action, updates the state, and redraws the UI. Notice it’s one way.

To learn more, read MobX Themes. Here are the main steps of implementation:

  • Define the data store classData Store
    • The member attributes arestate, the member function isaction
    • withmobxMarked asobservable
  • defineStores Provider
    • Methods aReact.Context:createContextpackagingStoreInstance,ui useContextuse
    • Way 2mobx-react.Provider: Direct packagingStoreInstance, provided toProvider.ui injectuse
  • implementationuicomponent
    • withmobxMarked asobserver
    • To obtainstores, direct referencestate
    • If you want to updatestate, indirect callaction

The project structure is multiple stores directory, define state action of various stores, asynchronous operation is also very simple. To learn more, read:

  • Defining a data store
  • Asynchronous actions

To prepare

React App

yarn create react-app start-react --template typescript
cd start-react
Copy the code

React Router

Routing library to navigate the sample.

yarn add react-router-dom
Copy the code

Antd

Component library for laying out the UI.

yarn add antd @ant-design/icons
Copy the code

Advanced configuration,

yarn add @craco/craco -D
yarn add craco-less
Copy the code

Craco.config.js is configured with a dark theme:

const path = require('path');
const CracoLessPlugin = require('craco-less');
const { getThemeVariables } = require('antd/dist/theme');

module.exports = {
  plugins: [{plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: getThemeVariables({
              dark: true.// compact: true,
            }),
            javascriptEnabled: true,},},},},],webpack: {
    alias: { The '@': path.resolve(__dirname, './src')}}};Copy the code

ESLint

VSCode installs the ESLint Prettier extension. Initializing ESLint:

$NPX eslint -init ➤ How would you like to use eslint? DE style ✔ Whattypeof modules does your project use? · EsM ➤ Which framework does your project use? Re-configure your project use TypeScript? · No/Yes ✔ Where does your code run? · Browser ➤ How would you like to define a styleforyour project? ➤ Come to a good foregrounddo you want to follow? · airbnb
✔ What format do you want your config file to be in? JavaScript,Copy the code

To configure.eslintrc.js.eslintignore.vscode /settings.json, see the code. Add to package.json:

"scripts": {
  "lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern node_modules/"
},
Copy the code

Run yarn Lint. Yarn start Runs.

At this point, the React Antd application is ready. The initial template is as follows, with the first commit visible:

MobX

yarn add mobx mobx-react
Copy the code

Mobx-react includes mobx-React-Lite, so you don’t need to install it.

  • If only React.FC (HOOK) is usedmobx-react-liteCan.
  • If React.Component (Class) is usedmobx-reactTo just go.

Mobx – react – lite and react. FC

Define the Data Stores

makeAutoObservable

After defining the data store model, just call makeAutoObservable(this) in the constructor.

stores/Counter.ts:

import { makeAutoObservable } from 'mobx';

class Counter {
  count = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increase() {
    this.count += 1;
  }

  decrease() {
    this.count -= 1; }}export default Counter;
Copy the code

React.Context Stores

React.Context can easily pass Stores.

stores/index.ts:

import React from 'react';

import Counter from './Counter';
import Themes from './Themes';

const stores = React.createContext({
  counter: new Counter(),
  themes: new Themes(),
});

export default stores;
Copy the code

Create a useStores Hook to simplify the call.

hooks/useStores.ts:

import React from 'react';
import stores from '.. /stores';

const useStores = () = > React.useContext(stores);

export default useStores;
Copy the code

Pane components, using Stores

Components are wrapped in observers and useStores reference stores.

Pane.tsx:

import React from 'react';
import { Row, Col, Button, Select } from 'antd';
import { PlusOutlined, MinusOutlined } from '@ant-design/icons';
import { observer } from 'mobx-react-lite';

import useStores from './hooks/useStores';

typePaneProps = React.HTMLProps<HTMLDivElement> & { name? :string;
}

const Pane: React.FC<PaneProps> = ({ name, ... props }) = > {
  const stores = useStores();

  return (
    <div {. props} >
      {name && <h2>{name}</h2>}
      <Row align="middle">
        <Col span="4">Count</Col>
        <Col span="4">{stores.counter.count}</Col>
        <Col>
          <Button
            type="text"
            icon={<PlusOutlined />}
            onClick={() => stores.counter.increase()}
          />
          <Button
            type="text"
            icon={<MinusOutlined />}
            onClick={() => stores.counter.decrease()}
          />
        </Col>
      </Row>{/ *... * /}</div>
  );
};

Pane.defaultProps = { name: undefined };

export default observer(Pane);
Copy the code

Mobx – ponent react with React.Com

Define the Data Stores

makeObservable + decorators

Decorators were dropped in MobX 6, but can still be used.

First, enable the decorator syntax. TypeScript is enabled in tsconfig.json:

"experimentalDecorators": true."useDefineForClassFields": true.Copy the code

After defining the data store model, call makeObservable(this) in the constructor. Not required before MobX 6, but now required for decorator compatibility.

stores/Counter.ts:

import { makeObservable, observable, action } from 'mobx';

class Counter {
  @observable count = 0;

  constructor() {
    makeObservable(this);
  }

  @action
  increase() {
    this.count += 1;
  }

  @action
  decrease() {
    this.count -= 1; }}export default Counter;
Copy the code

Root Stores

Combine multiple Stores.

stores/index.ts:

import Counter from './Counter';
import Themes from './Themes';

export interface Stores {
  counter: Counter;
  themes: Themes;
}

const stores : Stores = {
  counter: new Counter(),
  themes: new Themes(),
};

export default stores;
Copy the code

Parent component that provides Stores

The parent component adds mox-react. Provider and the property extends stores.

index.tsx:

import React from 'react';
import { Provider } from 'mobx-react';
import stores from './stores';

import Pane from './Pane';

const MobXCLS: React.FC = () = > (
  <div>
    <Provider {. stores} >
      <h1>MobX with React.Component</h1>
      <div style={{ display: 'flex' }}>
        <Pane name="Pane 1" style={{ flex: 'auto' }} />
        <Pane name="Pane 2" style={{ flex: 'auto' }} />
      </div>
    </Provider>
  </div>
);

export default MobXCLS;
Copy the code

Pane components that inject Stores

Components are decorated with Observers while injecting stores.

Pane.tsx:

import React from 'react';
import { Row, Col, Button, Select } from 'antd';
import { PlusOutlined, MinusOutlined } from '@ant-design/icons';
import { observer, inject } from 'mobx-react';

import { Stores } from './stores';

typePaneProps = React.HTMLProps<HTMLDivElement> & { name? :string;
};

@inject('counter'.'themes')
@observer
class Pane extends React.Component<PaneProps.unknown> {
  get injected() {
    return this.props as (PaneProps & Stores);
  }

  render() {
    const{ name, ... props } =this.props;
    const { counter, themes } = this.injected;

    return (
      <div {. props} >
        {name && <h2>{name}</h2>}
        <Row align="middle">
          <Col span="4">Count</Col>
          <Col span="4">{counter.count}</Col>
          <Col>
            <Button
              type="text"
              icon={<PlusOutlined />}
              onClick={() => counter.increase()}
            />
            <Button
              type="text"
              icon={<MinusOutlined />}
              onClick={() => counter.decrease()}
            />
          </Col>
        </Row>
        <Row align="middle">
          <Col span="4">Theme</Col>
          <Col span="4">{themes.currentTheme}</Col>
          <Col>
            <Select
              style={{ width: '60px'}}value={themes.currentTheme}
              showArrow={false}
              onSelect={(v)= > themes.setTheme(v)}
            >
              {themes.themes.map((t) => (
                <Select.Option key={t} value={t}>
                  {t}
                </Select.Option>
              ))}
            </Select>
          </Col>
        </Row>
      </div>); }}export default Pane;
Copy the code

The last

You can browse through the MobX documentation to see what’s there. Other core concepts not covered are Computeds and Reactions.

React integration, React Optimization, MobX and React integration

GoCoding personal practice experience sharing, please pay attention to the public account!