React MobX 开始
2021-12-28 19:20
501 查看
MobX 用于状态管理,简单高效。本文将于 React 上介绍如何开始,包括了:
- 了解 MobX 概念
- 从零准备 React 应用
- MobX React.FC 写法
- MobX React.Component 写法
可以在线体验: https://ikuokuo.github.io/start-react ,代码见: https://github.com/ikuokuo/start-react 。
概念
首先,
ui是由
state通过
fn生成:
ui = fn(state)
在 React 里,
fn即组件,依照自己的
state渲染。
如果
state是共享的,一处状态更新,多处组件响应呢?这时就可以用
MobX了。
MobX数据流向如下:
ui ↙ ↖ action → state
ui触发
action,更新
state,重绘
ui。注意是单向的。
了解更多,请阅读 MobX 主旨 。这里讲下实现时的主要步骤:
- 定义数据存储类
Data Store
成员属性为state
,成员函数为action
- 用
mobx
标记为observable
Stores Provider
-
方式一
React.Context:
createContext包装
Store实例,
ui
useContext使用
mobx-react.Provider:直接包装
Store实例,提供给
Provider,
ui
inject使用
ui组件
-
用
mobx标记为
observer
stores,直接引用
state
state,间接调用
action
项目结构上就是多个
stores目录,定义各类
store的
state
action,异步操作也很简单。了解更多,请阅读:
准备
React App
yarn create react-app start-react --template typescript cd start-react
React Router
路由库,以便导航样例。
yarn add react-router-dom
Antd
组件库,以便布局 UI。
yarn add antd @ant-design/icons
高级配置,
yarn add @craco/craco -D yarn add craco-less
craco.config.js配置了深色主题:
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 安装 ESLint Prettier 扩展。初始化
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
配置
.eslintrc.js
.eslintignore
.vscode/settings.json,详见代码。并于
package.json添加:
"scripts": { "lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern node_modules/" },
执行
yarn lint通过,
yarn start运行。
到此, React Antd 应用就准备好了。初始模板如下,可见首个提交:
MobX
yarn add mobx mobx-react
mobx-react包含了
mobx-react-lite,所以不必安装了。
- 如果只用 React.FC (HOOK) 时,用
mobx-react-lite
即可。 - 如果要用 React.Component (Class) 时,用
mobx-react
才行。
mobx-react-lite 与 React.FC
定义 Data Stores
makeAutoObservable
定义数据存储模型后,于构造函数里调用
makeAutoObservable(this)即可。
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可以很简单的传递
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;
创建一个
useStores的
Hook,简化调用。
hooks/useStores.ts:
import React from 'react'; import stores from '../stores'; const useStores = () => React.useContext(stores); export default useStores;
Pane 组件,使用 Stores
组件用
observer包装,
useStores引用
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 与 React.Component
定义 Data Stores
makeObservable + decorators
装饰器在
MobX 6中放弃了,但还可使用。
首先,启用装饰器语法。
TypeScript于
tsconfig.json里启用:
"experimentalDecorators": true, "useDefineForClassFields": true,
定义数据存储模型后,于构造函数里调用
makeObservable(this)。在
MobX 6前不需要,但现在为了装饰器的兼容性必须调用。
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
组合多个
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;
父组件,提供 Stores
父组件添加
mobx-react.Provider,并且属性扩展
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 组件,注入 Stores
组件用
observer装饰,同时
inject注入
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;
最后
MobX文档可以浏览一遍,了解有哪些内容。未涉及的核心概念还有 Computeds, Reactions。
其中
MobX and React一节,详解了于
React中的用法及注意点,见:React 集成,React 优化。
GoCoding 个人实践的经验分享,可关注公众号!
相关文章推荐
- 使用 webpack4 从0开始搭建 react 项目
- [React + Mobx] Mobx and React intro: syncing the UI with the app state using observable and observer
- react生命周期函数使用箭头函数,导致mobx-react问题
- ReactNative-从UI开始
- React 从0开始 消息传递
- React-Native从开始到发布的10个要点
- MobX —— 10分钟极速入门 MobX 与 React
- react native45版本开始后,新建应用会抛出UNpackage xxxx
- React + MobX 状态管理入门及实例
- 在开始 React 之前,JavaScript 这些知识点你学好了吗?
- 翻译 | 开始使用 TypeScript 和 React
- 从 history 开始学习 React Router
- 把react什么的都用起来 【0】预备——开始
- 学习React从接受JSX开始
- react基础-从安装开始
- 开始一个React项目(二) 彻底弄懂webpack-dev-server的热更新
- 从 React 架构开始讲解 useState、useEffect 编程设计
- 关于react 脚手架开始配置
- React Native01-开始 Windows环境安装配置篇
- react项目快速开始