likes
comments
collection
share

一个项目让你学会mobx状态管理

作者站长头像
站长
· 阅读数 19

参考链接

本文为开源项目学习总结,原项目参考链接为;todomvc.com/examples/re…

学习阶段,仅供参考,如有侵权,请联系作者删除。

前言

刚学完学习React想要找项目练手却没有合适的怎么办?大项目看不懂,看文档学demo没提升,又找不到既能概括所学的知识又非常适合新手学习的项目?那今天你可算来对地方了,今天我就来和小伙伴们介绍一个非常适合新手学的项目——Todolist。

介绍

那接下来我们就来介绍该项目,首先我们最终要实现的效果是这样的:

一个项目让你学会mobx状态管理

在该项目中我们使用到的技术是React与mobx。该最主要的部分就是使用mobx对组件内的状态进行管理。

目前我们实现功能的是:

  1. 在输入框输入内容再回车可以添加到列表的最后一条
  2. 点击列表项左边的单选框可以改变该列表项的样式
  3. 点击列表项右边X按钮可以删除该列表项
  4. 点击输入框左边箭头可以全选或全不选列表
  5. 点击列表下面的功能选项可以实现对应功能

搭建项目

首先我们使用vite搭建一个React的项目,安装好mobx等依赖。将项目启动起来。将不需要的文件删除。

准备组件

然后我们创建如下两个组件:

Todo组件(页面的输入框与工具栏部分),完整代码如下:

ps:此组件还有一份样式文件,详情在下面完整代码中

import React, { useState } from 'react'
import './index.css'
import { observer } from 'mobx-react-lite'
import TodoList from '../TodeList'
import { useStore } from '../../stroe'
 function Tode() {
  const [keyword, setKeyword] = useState('')
  const {taskStore} = useStore()
  const onKeyUp = (e) => {
    if(e.keyCode == 13) {
      taskStore.addItem({
        id: taskStore.list[taskStore.list.length-1].id + 1,
        name: keyword,
        isDone: false
      })
      setKeyword('')
    }
  }
  const keywordChange = (e) => {
    setKeyword(e.target.value)
  }
  return (
    <div>
        <section className='todoapp'>
            <header className="header">
                <h1>todos</h1>
                <input type="text"
                className='new-todo'
                placeholder='What needs to be done ?'
                autoFocus
                autoComplete='off'
                value={keyword}
                onChange={keywordChange}
                onKeyUp={onKeyUp}
                 />
            </header>
            <TodoList></TodoList>
            <footer className='footer'>
              <span className="todo-count">
                任务总数:{taskStore.allTask},已完成 :{taskStore.completed}
              </span>
            </footer>
        </section>
    </div>
  )
}
export default observer(Tode)

TodoList组件(页面的列表部分),完整代码如下:

import React from 'react'
import { useStore } from '../../stroe'
import { observer } from 'mobx-react-lite'
function TodoList() {
    const { taskStore } = useStore()
    const onChange = (id) => taskStore.checkItem(id)
    const onDel = (id) => taskStore.delItem(id)
    const allChange = (e) =>{
        console.log(e.target.checked);
        taskStore.allCheck(e.target.checked)
    }
    return (
        <section className='main'>
            <input type="checkbox"
            className='toggle-all'
            id="toggle-all"
            checked = {taskStore.isAll}
            onChange={allChange} />
            <label htmlFor="toggle-all"></label>
            <ul className='todo-list'>
                {
                    taskStore.list.map(item => (
                        <li className={`todo ${item.isDone ? 'completed' : ''}`} key={item.id}>
                            <div className="view">
                                <input type="checkbox"
                                className='toggle'
                                checked = {item.isDone}
                                onChange={() => onChange(item.id)}
                                />
                                <label htmlFor="">{item.name}</label>
                                <button className='destroy' onClick={ () => onDel(item.id)}></button>
                            </div>
                        </li>
                    ))
                }
            </ul>
        </section>
    )
}
export default observer(TodoList)

准备仓库

当我们准备完组件后,我们就该来准备仓库了。

首先我们准备一个index文件来将我们的仓库进行整合,代码如下:

import React from 'react';
import TaskStore from './task.Store';
class RootStore {
    //整合模块
    constructor () {
        this.taskStore = new TaskStore()
    }
}
// 实例化根store, 并注入context
const StoreContext = React.createContext( new RootStore())
export const useStore = () => React.useContext(StoreContext)

那接下来我们准备我们的仓库,代码如下:

import { makeAutoObservable, computed} from 'mobx'
class TaskStore {
    list = [
        {
            id: 1,
            name: 'learn react',
            isDone: false
        },
        {
            id: 2,
            name: 'learn vue',
            isDone: false
        }
    ]
    constructor () {
        makeAutoObservable(this, {
            isAll:computed,
            completed: computed,
            allTask: computed
        })
    }
    checkItem (id) {
       const item =  this.list.find((item) => {
            return item.id == id
        })
        item.isDone = !item.isDone
    }
    delItem(id) {
       this.list = this.list.filter(item => item.id !== id)
    }
    allCheck(checked) {
        this.list.forEach(item => {
            item.isDone = checked
        })
    }
    get isAll () {
       return  this.list.every(item => item.isDone)
    }
    addItem (item) {
        this.list.push(item)
    }
    get completed() {
        return this.list.filter(item => item.isDone).length
    }
    get allTask() {
        return this.list.length
    }
}
export default TaskStore

准备工作到这里就结束了,那接下来我们就该来对这上述的代码进行分析了,我们以我们需要实现的功能来意义分析上述代码。

功能分析

功能一

首先,我们来看看第一个功能是如何实现的,它需要做的是:

  1. 获取输入框内容
  2. 将输入内容存在仓库中,更新仓库

该功能功能实现的代码如下:

const [keyword, setKeyword] = useState('') // 输入框数据

// 1. 获取数据并实施更新的方法
const keywordChange = (e) => {
    setKeyword(e.target.value)
}

addItem (item) { // 仓库定义的添加方法
    this.list.push(item)
}
// 2. 将数据添加到仓库的方发
const onKeyUp = (e) => {
    if(e.keyCode == 13) {
        taskStore.addItem({
        id: taskStore.list[taskStore.list.length-1].id + 1,
        name: keyword,
        isDone: false
    })
    setKeyword('')
    }
}

功能二

第二个功能是点击列表项单选框改变列表项样式,它需要做的就是:

  1. 在仓库设置一个管理此状态的值
  2. 在仓库设置修改次状态的值的方法
  3. 在单选框点击事件中调用仓库的值改变列表项的样式

该功能实现的代码如下:

// 1. 在list列表的每一项添加一个 isDone属性管理列表状态
list = [
    {
        ...
        isDone: false
    },
]
// 2. 仓库中定义的修改isDnode的方法
checkItem (id) {
   const item =  this.list.find((item) => {
        return item.id == id
    })
    item.isDone = !item.isDone

}
// 改变样的的点击事件与是否添加样的三元运算符
const onChange = (id) => taskStore.checkItem(id)
<li className={`todo ${item.isDone ? 'completed' : ''}`} key={item.id}>...

功能三

功能三需要实现的是点击列表项右边X按钮可以删除该列表项,它与功能二实现方式相似,都需要改变仓库的状态,它需要做的就是:

  1. 在仓库中定义修改list数据源的方法
  2. 在组件中调用仓库方法修改数据源

该功能实现的代码如下:

// 1. 仓库中定义的修改数据源方法
 delItem(id) {
    this.list = this.list.filter(item => item.id !== id)
}
// 2. 调用仓库方法修改数据修改数据源
const onDel = (id) => taskStore.delItem(id)

功能四

功能四需要实现点击输入框左边箭头可以全选或全不选列表,这个功能需要用到的是isAll作为公共管理状态,来使列表的样式批量改变,它需要做的就是:

在仓库中设置一个isAll计算属性实施的计算出是ture还是flase 在仓库设置修改一键全部isDone状态的方法 在组件中调用仓库方法修改列表样式

该功能实现的代码如下:

// 1. 定义计算属性
constructor () {
    makeAutoObservable(this, {
        isAll:computed,...
    })

}
get isAll () {
   return  this.list.every(item => item.isDone)
}
// 2.定义一键修改属性的样式
allCheck(checked) {
    this.list.forEach(item => {
        item.isDone = checked
    })

}
// 3. 调用仓库方法

 const allChange = (e) =>{
    console.log(e.target.checked);
    taskStore.allCheck(e.target.checked)
}

<input type="checkbox" 
// 根据仓库样式修改列表样式
...

checked = {taskStore.isAll}

onChange={allChange} />

<label htmlFor="toggle-all"></label>

功能五

功能五的实现较为简单,与上述方法相同,我就不在此介绍是如何实现的了,有兴趣的小伙伴可以去试试哦。

完整代码

完整项目代码链接:gitee.com/xiaopanpany…

结语

该项目可以很好的帮我们理解和使用mobx,同时也帮我们很好的将mobx融合到项目中,是一个非常不错的过渡项目。有兴趣的小伙伴可以自己动手在开发一遍哦。