React中使用Mobx管理TodoList

本周对 mobx 进行了学习,写了一个 tosolist demo 练练手~(没写完)

一、Mobx

1.1 介绍

  • mobx 是一个简单的可拓展的状态管理库,无样本代码风格简约
  • 不推荐使用装饰器语法
  • 可以运行在任何支持es5的环境中,包含浏览器和 node

1.2 核心

1.2.1 observable

  • 被 mobx 跟踪的状态

1.2.2 action

  • 通过某个方法去修改状态的话,这个方法必须被标记为 action 方法
  • 只有 action 方法才能修改状态
  • 只有修改状态之后这个视图才进行更新

1.2.3 computed

  • 派生状态

  • 根据现有状态衍生出来的状态

1.2.4 flow

  • 用来标识方法
  • 想要应用当中执行副作用副作用执行完成之后要更改状态
  • 这个方法必须被标志为 flow

1.3 使用

  • mobx:核心库
  • mobx-react-lite:适用于函数组件
  • mobx-react:适用于函数组件和类组件
  • 安装:pnpm i mobx mobx-react-lite

二、功能需求

  • 实现对任务列表的增删改查

三、实现过程

需安装:

发送网络请求:pnpm i axios

模拟返回后端数据:pnpm i json-server

编写样式:pnpm i styled-components

3.1 初始化

  • 任务对象和任务列表都是状态,因此两者都是使用类进行管理

  • store

  • modules

    • todo类
import { makeObservable, observable } from "mobx"
export default class Todo{
  constructor(todo) {
    this.id = todo.id
    // 状态
    this.title = todo.title
    this.isCompleted = todo.isCompleted || false
    this.isEditing = false
    makeObservable(this, {
      title: observable,
      isCompleted: observable,
      isEditing:observable
    })
  }
}
  • todoStore.js
import { makeObservable, observable } from "mobx"
export default class TodoStore{
  constructor() {
    this.todoList=[]
    makeObservable(this, {
      todoList:observable,
          // 更正 this 指向
      addTodo: action.bound,
    })
  }
      // 增加任务
  addTodo(title) {
    // 将任务(title、id)加入`任务列表`中:通过 todo 类生成一个实例任务
    this.todoList.push(new Todo({ title, id: this.createId() }));
  }
  // 创建 id
  createId() {
    // 数组中还没有任务,id 为 1
    if (!this.todoList.length) return 1;
    // 通过 reduce 方法进行遍历
    return this.todoList.reduce((id, todo) => (id < todo.id ? todo.id : id), 0) + 1;
    // return this.todoList.length + 1;
  }
}
  • index.js
import { createContext, useContext } from "react";
import CounterStore from "./CounterStore";
import TodoStore from "./TodoStore";
class RootStore {
  constructor() {
    this.counterStore = new CounterStore();
    this.todoStore = new TodoStore()
  }
}
// 创建一个 rootStore 实例
const rootStore = new RootStore();
// 创建一个上下文对象
const RootStoreContext = createContext();
// 给下层组件提供 rootStore
export const RootStoreProvider = ({ children }) => {
  return <RootStoreContext.Provider value={rootStore}>{children}</RootStoreContext.Provider>;
};
// 导出 RootStore 对象
export const useRootStore = () => {
  return useContext(RootStoreContext)
}

3.2 添加任务

  • todoStore 增加状态
import { makeObservable, observable } from "mobx"
export default class TodoStore{
  constructor() {
    this.todoList=[]
    makeObservable(this, {
      todoList:observable,
          // 更正 this 指向
      addTodo: action.bound,
    })
  }
      // 增加任务
  addTodo(title) {
    // 将任务(title、id)加入`任务列表`中:通过 todo 类生成一个实例任务
    this.todoList.push(new Todo({ title, id: this.createId() }));
  }
  // 创建 id
  createId() {
    // 数组中还没有任务,id 为 1
    if (!this.todoList.length) return 1;
    // 通过 reduce 方法进行遍历,往最大 id 加 1
    return this.todoList.reduce((id, todo) => (id < todo.id ? todo.id : id), 0) + 1;
  }
}
  • 操作任务列表
import React, { memo, useState } from "react";
import { useRootStore } from "../../store";
import { HeaderWrapper } from "./style";

const TodoHeader = memo(() => {
  const [title, setTitle] = useState("");
  const { todoStore } = useRootStore();
  const { addTodo } = todoStore;
  return (
    <HeaderWrapper>
      <header className='header'>
        <input
          className='input'
          type='text'
          placeholder='what needs to be done'
          autoFocus
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          onKeyUp={(e) => {
            if (e.key !== "Enter") return;
            // 增加任务
            addTodo(title);
            setTitle("");
          }}
        />
      </header>
    </HeaderWrapper>
  );
});

export default TodoHeader;

3.3 展示任务列表

请添加图片描述

  • TodoMain
import React from "react";
import { observer } from "mobx-react-lite";
import { useRootStore } from "../../store";
import TodoItem from "../TodoItem";
import { MainWrapper } from "./style";
const TodoMain = observer(() => {
  const { todoStore } = useRootStore();
  const { todoList } = todoStore;
  return (
    <MainWrapper>
          {todoList.map((item) => (
        <TodoItem todo={item} key={item.id} />
      ))}
  </MainWrapper>
  );
});

export default TodoMain;

  • TodoItem
import { observer } from "mobx-react-lite";
import React from "react";
import { ItemWrapper } from "./style";

const TodoItem = observer((props) => {
  const { todo } = props;
  return (
    <ItemWrapper>
      任务id:{todo.id}&nbsp;&nbsp;&nbsp;任务名称:{todo.title}
      <span className="deleteBtn">delete</span>
    </ItemWrapper>
  );
});

export default TodoItem;

3.4 加载远端任务

  • 开启本地服务器,配置 script
  "json-server": "json-server --watch ./src/data/db.json --port 3001"
  • 使用 flow 标识,获取到任务之后添加到任务列表
import { action, flow, makeObservable, observable } from "mobx";
import Todo from "./Todo";
import axios from "axios";
// 存储一个列表状态
export default class TodoStore {
  constructor() {
    this.todoList = [];
    // 标识状态
    makeObservable(this, {
      loadTodoList: flow,
    });
    this.loadTodoList()
  }
  // 模拟获取服务器端任务
  async loadTodoList() {
    const res = await axios.get("http://localhost:3001/todos");
    res.data.forEach((todo) => {
      this.todoList.push(new Todo(todo));
    });
  }
}

3.5 更改任务是否已完成状态

  • 添加 input 输入框,设置 type='checkbox'
import { observer } from "mobx-react-lite";
import React from "react";
import { ItemWrapper } from "./style";

const TodoItem = observer((props) => {
  const { todo, isCompleted, modifyTodoIsComputed } = props;
  return (
    <ItemWrapper>
      <input type='checkbox' className='toggle' checked={isCompleted} onChange={modifyTodoIsComputed} />
      任务id:{todo.id}&nbsp;&nbsp;&nbsp;任务名称:<span className='title'>{todo.title}</span>
      <span className='deleteBtn'>delete</span>
    </ItemWrapper>
  );
});

export default TodoItem;

  • 改变的是任务的状态,来到 Todo 类
import { action, makeObservable, observable } from "mobx"
// 创建任务列表类
export default class Todo{
  constructor(todo) {
    // 属性:id title isCompleted isEditing
    this.id = todo.id
    // 状态
    this.title = todo.title
    this.isCompleted = todo.isCompleted || false
    this.isEditing = false
    // 标识状态
    makeObservable(this, {
      title: observable,
      isCompleted: observable,
      isEditing: observable,
      modifyTodoIsComputed:action.bound
    })
  }

  // 更改任务是否已完成状态
  modifyTodoIsComputed() {
    this.isCompleted = !this.isCompleted
  }
}

3.6 删除任务

  • 根据 id 进行删除
  // 根据 id 删除任务
  removeTodo(id) {
    console.log(id);
    this.todoList = this.todoList.filter((todo) => todo.id !== id);
  }
  • 点击删除按钮调用删除方法
import { observer } from "mobx-react-lite";
import React from "react";
import { ItemWrapper } from "./style";
import { useRootStore} from '../../store/index'
const TodoItem = observer((props) => {
  const { todo} = props;
  const { isCompleted, modifyTodoIsComputed } = todo
  const { todoStore } = useRootStore()
  const {removeTodo} = todoStore
  return (
    <ItemWrapper>
      <input type='checkbox' className='toggle' checked={isCompleted} onChange={modifyTodoIsComputed} />
      任务id:{todo.id}&nbsp;&nbsp;&nbsp;任务名称:<span className='title'>{todo.title}</span>
      <span className='deleteBtn' onClick={() => removeTodo(todo.id)}>
        delete
      </span>
    </ItemWrapper>
  );
});

export default TodoItem;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值