MobX学(踩)习(坑)指(日)南(记)
一、引言
最近换工作,新公司的项目中使用React+MobX,但我之前只用过React+Redux,所以呢,只能继续学了...
简单过完一遍mobx文档,觉得核心概念已经懂了,心想“啥都不是,这也不难么”,然后就掉到了坑里,爬了好久才出坑。
特此记录踩坑经验,以期帮助大家不踩同样的坑。
二、配置项目环境
按照官方文档,我使用了以下命令,用cra命令创建了项目,然后修改config配置,让项目支持修饰符,接着安装了mobx、mobx-react,在准备开撸代码的时候发现了问题。
创建项目+安装依赖
// 创建项目
npx create-react-app mobx-app
// 安装依赖
npm i mobx mobx-react
npm i --save-dev @babel/core @babel/plugin-proposal-decorators @babel/preset-env customize-cra react-app-rewired
配置Babel
// .babelrc
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]
}
配置支持修饰符
// config-overrides.js
const { override, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(
addDecoratorsLegacy(),
)
配置lint检验
// jsconfig.json
{
"compilerOptions": {
"jsx": "react",
"baseUrl": ".",
"experimentalDecorators": true,
},
"include": ["src/**/*"]
}
三、开始code
// src/App.js
import TodoListView from './pages/TodoList';
function App() {
return (
<TodoListView/>
);
}
export default App;
// src/pages/TodoList.js
import { observer } from "mobx-react";
import React from "react";
import { TodoList } from "src/store/todo";
const store = new TodoList();
@observer
class TodoListView extends React.Component {
constructor(props) {
super(props);
this.state={
toAddTodoText: ""
}
}
render() {
const { todoList,addTodo,switchTodo } = store;
return(
<div>
<ul>
{todoList.map((todo) => (
<li key={todo.id}>
<h1>{todo.title}</h1>
<input type={"checkbox"} checked={todo.finished} onClick={() => {
switchTodo(todo.id)
}}/>finished
</li>
))}
</ul>
<div>total: {store.todoListLength}</div>
<div>finished: {store.finishedNums}</div>
<div>
<input type={"text"} placeholder="please input a todo title" onChange={(e) => {
this.setState({
toAddTodoText: e.target.value
})
}}/>
<button onClick={() => {
addTodo(this.state.toAddTodoText)
}}>add Todo</button>
</div>
</div>
)
}
}
export default TodoListView;
// src/store/todo.js
const { observable, computed, action } = require("mobx");
class Todo {
constructor(){
makeObservable(this);
}
id = Math.random();
@observable title = "";
@observable finished = false;
}
class TodoList {
@observable todoList = [];
@computed get finishedNums() {
return this.todoList.filter((todo) => todo.finished).length;
}
@computed get todoListLength() {
return this.todoList.length;
}
@action.bound
addTodo(todoTitle) {
const newTodo = new Todo();
newTodo.title = todoTitle;
this.todoList.push(newTodo);
}
@action.bound
switchTodo(id) {
const targetTodo = this.todoList.find((todo) => todo.id === id);
targetTodo.finished = !targetTodo.finished;
}
}
export {
Todo,
TodoList,
}
yarn start启动项目后,在输入框输入一个要新增的todo title,结果发现和预期不一致:UI没有更新,新的todo没有被添加
打开控制台有报错:todo.js:27 Uncaught TypeError: Cannot read properties of undefined (reading 'todoList')
四、问题定位及解决
经过各种定位与排查,最终找到了原因:mobx版本。
还记得我们之前提到的mobx文档吗?目前搜索到的mobx文档主要是5.x版本,而我们npm i mobx的时候,安装的是6.x版本。mobx6.x文档中指出:我们必须使用makeObservable来使得对象可观察,换句话说,如果我们不使用makeObservable或makeAutoObservable的话,mobx就无法观察到我们使用@observable定义的数据,我们就无法正常使用mobx。