一个项目让你学会mobx状态管理
参考链接
本文为开源项目学习总结,原项目参考链接为;todomvc.com/examples/re…
学习阶段,仅供参考,如有侵权,请联系作者删除。
前言
刚学完学习React想要找项目练手却没有合适的怎么办?大项目看不懂,看文档学demo没提升,又找不到既能概括所学的知识又非常适合新手学习的项目?那今天你可算来对地方了,今天我就来和小伙伴们介绍一个非常适合新手学的项目——Todolist。
介绍
那接下来我们就来介绍该项目,首先我们最终要实现的效果是这样的:
在该项目中我们使用到的技术是React与mobx。该最主要的部分就是使用mobx对组件内的状态进行管理。
目前我们实现功能的是:
- 在输入框输入内容再回车可以添加到列表的最后一条
- 点击列表项左边的单选框可以改变该列表项的样式
- 点击列表项右边X按钮可以删除该列表项
- 点击输入框左边箭头可以全选或全不选列表
- 点击列表下面的功能选项可以实现对应功能
搭建项目
首先我们使用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
准备工作到这里就结束了,那接下来我们就该来对这上述的代码进行分析了,我们以我们需要实现的功能来意义分析上述代码。
功能分析
功能一
首先,我们来看看第一个功能是如何实现的,它需要做的是:
- 获取输入框内容
- 将输入内容存在仓库中,更新仓库
该功能功能实现的代码如下:
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. 在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按钮可以删除该列表项,它与功能二实现方式相似,都需要改变仓库的状态,它需要做的就是:
- 在仓库中定义修改list数据源的方法
- 在组件中调用仓库方法修改数据源
该功能实现的代码如下:
// 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融合到项目中,是一个非常不错的过渡项目。有兴趣的小伙伴可以自己动手在开发一遍哦。
转载自:https://juejin.cn/post/7249545974819864637