B站-MobX 使用全流程
代码,atob('aHR0cHM6Ly9naXRlZS5jb20vaWZlcmNhcmx5L21vYng1')
本地项目,mobx-come,实践步骤:
环境搭建
- 在本地创建react项目
先创建目录 mobx-come ,然后再目录下执行npx create-react-app . template typescript - 按照视频,删除创建项目的src目录,拷贝资源src目录到项目上去,运行,ok
配置装饰器
- 安装装饰器,为什么?
yarn add -D react-app-rewired customize-cra @babel/plugin-proposal-decorators,还有其他的库可以取代这个库吗? - 在根目录创建文件
config-overrides.js
const {override, addDecoratorsLegacy} = require('customize-cra');
module.exports = override(addDecoratorsLegacy());
- 在根目录创建
.babelrc
{
"plugins": [
["@babel/plugin-proposal-decorators",{"legacy": true}]
]
}
- 修改默认启动命令为
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
- 测试装饰器,在index.js文件下添加测试代码
@foo
class Person{}
function foo(target){
target.prototype.show = function (){
console.log("hello, person");
}
}
const p = new Person();
p.show(); // 控制台会打印出 hello, person
跑通mobx
- 安装mobx
yarn add mobx@5 mobx-react@5 - 创建store文件夹
- 创建3个store文件
// mainStore.js
class MainStore{
constructor(rootStore) {
this.rootStore = rootStore;
}
}
// footStore.js
export default MainStore;
class FootStore{
constructor(rootStore) {
this.rootStore = rootStore;
}
}
export default FootStore;
// index.js
import MainStore from "./mainStore";
import FootStore from "./footStore";
class RootStore{
constructor() {
this.FootStore = new FootStore(this);
this.MainStore = new MainStore(this);
}
}
- 关联store与根节点
......
import { Provider } from "mobx-react";
import RootStore from "./store";
createRoot(document.querySelector('#root')).render(
<Provider {...new RootStore()}>
<App/>
</Provider>
)
- 测试mobx结果,在MainStore中写数据
@observable state = {
list: [{
id: 1,
done: false,
name: "吃饭"
}, {
id: 2,
done: false,
name: "睡觉"
}]
}
其中,state有错误警告Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.
搜索,
根据https://stackoverflow.com/的提示,在tsconfig.js文件中增加
"emitDecoratorMetadata": true,
"experimentalDecorators": true
解决报错问题
- 在组件中注入数据类
@inject("MainStore")
@observe()
export default class TodoMain extends Component {
render() {
console.log(this.props.MainStore.state.list); // 成功获取数据
return (.....);
}
}
模拟数据服务器
- 在根目录创建data.json
{
"todos": [
{
"id": 1,
"done": false,
"name": "吃饭"
},
{
"id": 2,
"done": false,
"name": "睡觉"
}
]
}
- 安装json-server,
yarn add json-server - 执行指令,模拟数据服务器,
json-server data.json -p 8888
请求数据
- 获取数据的注解,
@action,如下
class MainStore {
constructor(rootStore) {
this.rootStore = rootStore;
}
@observable state = {
list: [], // 删掉之前的数据,让初始数据为空
};
@action.bound getTodos(){
// 请求网络,获取数据
}
}
- 安装网络请求库
axios,yarn add axios - 封装网络请求,在src下创建目录utils,创建文件request.js,如下
import axios from "axios";
const request = axios.create({
baseURL: "http://localhost:8888/todos",
timeout: 5000,
})
export default request;
- 回到MainStore,完成获取数据的方法
// 获取数据
@action.bound getTodos(){
console.log("dsw","getTodos");
request.get("/").then((res) => {
console.log("dsw", res);
})
}
- 在组件中调用获取数据的方法
componentDidMount() {
this.props.MainStore.getTodos();
}
getTodos中成功打印出数据,说明获取数据的方法,调用方法,都没有问题
- 保存请求到的数据
const {data} = res;
this.state.list = data;
- 在组件中使用数据,渲染数据
const {state} = this.props.MainStore;
const {list} = state || {};
// list就是被渲染的数据,在UI中显示该list
classnames包
- 安装
yarn add classnames - 使用
...
{list.map((item) => (
<li className={classNames({
complete: item.done,
})} key={item.id}>
<div className='view'>
<input className='toggle' type='checkbox' checked={item.done} onChange={() => {
}}/>
<label>{item.name}</label>
<button className='destroy'></button>
</div>
<input className='edit' value='Create a TodoMVC template' onChange={() => {
}}/>
</li>))}
...
修改数据的几种方式
使用严格模式时configure({enforceActions: "observed"}),不能直接在mainStore中修改数据,有几种间接修改的方法
- 通过set的方法,推荐写法
// 获取数据
@action.bound getTodos() {
console.log("dsw", "getTodos");
request.get("/").then((res) => {
this.setTodos(res);
})
}
// 修改数据
@action.bound setTodos(res) {
const {data} = res;
this.state.list = data;
}
- 通过runInActions
// 获取数据
@action.bound getTodos() {
console.log("dsw", "getTodos");
request.get("/").then((res) => {
runInAction(() => {
const {data} = res;
this.state.list = data;
})
})
}
- 通过action方法
// 获取数据
@action.bound getTodos() {
console.log("dsw", "getTodos");
request.get("/").then((res) => {
action("@_@",() => {
const {data} = res;
this.state.list = data;
})();
})
}
删除数据的方式
// 删除数据
@action.bound async delTodos(id){
await request.delete(`/${id}`)
await this.getTodos();
}
更新数据的方式
// 更新数据
@action.bound
async updateTodos(id, key, value) {
await request.patch(`/${id}`, {[key]: value});
await this.getTodos();
}
添加数据的方式
// 添加数据
@action.bound
async addTodos(name){
console.log("dd-addTodos");
await request.post(`/`, {name, done: false});
await this.getTodos();
}
全选与取消全选
// 获取选中状态
@computed get getMainRadioStatus() {
return this.state.list.every((item) => item.done);
}
// 批量改变状态
@action.bound
async updatePerRadioStatus(done){
const promiseAll = this.state.list.map((item) => {
return this.updateTodos(item.id, 'done', done);
})
await Promise.all(promiseAll);
await this.getTodos();
}
其他功能(如,编辑Item,切换tab等,略)
改造为Mobx6的配置
- 安准mobx6
yarn add mobx mobx-react// 让react安装mobx的包
yarn add mobx mobx-react-lite// lite表示用于函数组件的,让react安装mobx的包 - 卸载原有mobx
yarn remove mobx-react - 改造代码