MobX used for state management, simple and efficient. This article will introduce how to get started on React, including:
- Understand MobX concepts
- Prepare React apps from scratch
- MobX React.FC writing method
- MobX React.Component writing method
You can experience it online: https://ikuokuo.github.io/start-react , the code is at: https://github.com/ikuokuo/start-react .
concept
First, ui
is generated state
through fn
ui = fn(state)
In React, fn
is the component, state
rendered according to its own 061cafc52542e1.
If state
is shared, how about one status update and multiple components responding? At this time, you can use MobX
.
The data flow of MobX
ui
↙ ↖
action → state
ui
trigger action
, update state
, redraw ui
. Attention is one-way.
To learn more, please read MobX subject . Here are the main steps for implementation:
Define data storage class
Data Store
- The member attribute is
state
and the member function isaction
- Use
mobx
mark asobservable
- The member attribute is
Definition
Stores Provider
- Method one
React.Context
:createContext
packageStore
instance,ui
useContext
use - Method 2
mobx-react.Provider
: directly package theStore
instance and provide it toProvider
,ui
inject
- Method one
Implement
ui
component- With
mobx
labeledobserver
- Get
stores
, directly quotestate
- To update
state
, indirectly callaction
- With
The project structure consists of multiple stores
directories, which define various types of store
state
action
. The asynchronous operation is also very simple. To learn more, please read:
Prepare
React App
yarn create react-app start-react --template typescript
cd start-react
React Router
Routing library for easy navigation of samples.
yarn add react-router-dom
Antd
Component library in order to lay out the UI.
yarn add antd @ant-design/icons
yarn add @craco/craco -D
yarn add craco-less
craco.config.js
equipped 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: { '@': path.resolve(__dirname, './src') },
},
};
ESLint
VSCode installs the ESLint Prettier extension. Initialize eslint
:
$ npx eslint --init
✔ How would you like to use ESLint? · style
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ How would you like to define a style for your project? · guide
✔ Which style guide do you want to follow? · airbnb
✔ What format do you want your config file to be in? · JavaScript
Configure .eslintrc.js
.eslintignore
.vscode/settings.json
, see the code for details. And added package.json
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern node_modules/"
},
Execute yarn lint
pass and yarn start
run.
At this point, the React Antd application is ready. The initial template is as follows, you can see the first submission:
MobX
yarn add mobx mobx-react
mobx-react
contains mobx-react-lite
, so there is no need to install it.
- If you only use React.FC (HOOK), use
mobx-react-lite
. - If you want to use React.Component (Class), use
mobx-react
.
mobx-react-lite and React.FC
Define Data Stores
makeAutoObservable
After defining the data storage model, 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;
React.Context Stores
React.Context
can easily deliver 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;
Create a useStores
of Hook
to simplify the call.
hooks/useStores.ts
:
import React from 'react';
import stores from '../stores';
const useStores = () => React.useContext(stores);
export default useStores;
Pane component, using Stores
The components are observer
, and useStores
refers to 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';
type PaneProps = 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);
mobx-react and React.Component
Define Data Stores
makeObservable + decorators
The decorator MobX 6
, but it can still be used.
First, enables the decorator syntax . TypeScript
is enabled in tsconfig.json
"experimentalDecorators": true,
"useDefineForClassFields": true,
After defining the data storage model, call makeObservable(this)
in the constructor. It is MobX 6
, but it must be called for the compatibility of the decorator.
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;
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;
Parent component, providing Stores
The parent component adds mobx-react.Provider
, and the attribute 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;
Pane component, injected into Stores
The components are observer
, and inject
injected with 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';
type PaneProps = 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;
At last
MobX
document can be browsed to understand what it contains. The core concepts not covered are Computeds , Reactions .
Which MobX and React
one, to explain the React
in usage and attention to points, see: React integrated , React optimization .
GoCoding personal practice experience sharing, please follow the official account!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。