欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框架 React框架 React框架,中间穿插了一些基础知识的回顾
博客主页codeMak1r.小新的博客本文目录
- Todos - Mobx - 综合案例
- 1.渲染列表
- 2.单选功能实现
- 3.全选功能实现
- 4.删除功能实现
- 5.回车新增功能实现
- 6.统计计数功能实现
- 7.Mobx - React 职责划分
本文被专栏【React–从基础到实战】收录
坚持创作✏️,一起学习,码出未来!
项目目录:
src ├─App.jsx ├─index.js ├─store | ├─index.js | └task.Store.js ├─Todo | ├─index.css | └index.jsx
/src/store/task.Store.js
import { makeAutoObservable } from "mobx";
class TaskStore {
constructor() {
makeAutoObservable(this)
}
list = [
{
id: 1,
name: '学习react',
isDone: true
},
{
id: 2,
name: '搞定mobx',
isDone: true
}
]
}
export { TaskStore }
/src/store/index.js
import React, { useContext } from "react";
import { TaskStore } from "./task.Store";
// 1.声明一个rootStore
class RootStore {
constructor() {
this.taskStore = new TaskStore()
}
}
// 2.实例化rootStore注入context
const rootStore = new RootStore()
const context = React.createContext(rootStore)
// 3.导出useStore方法,供组件通过调用该方法使用根实例
const useStore = () => useContext(context)
export { useStore }
/src/Todo/index.js
import { observer } from 'mobx-react-lite'
import { useStore } from '../store'
import './index.css'
function Task() {
const { taskStore } = useStore()
return (
<section className='todoapp'>
<header className='header'>
<h1>todos</h1>
{/* 新增输入框 */}
<input className='new-todo' autoFocus autoComplete='off' placeholder='What needs to be done?' />
</header>
<section className='main'>
{/* 全选 */}
<input type="checkbox" id='toggle-all' className='toggle-all' />
<label htmlFor="toggle-all"></label>
<ul className='todo-list'>
{/* completed类名 */}
{
taskStore.list.map((todoObj) => {
return <li key={todoObj.id} className={todoObj.isDone ? 'todo completed' : 'todo'}>
<div className='view'>
<input id={todoObj.id} type="checkbox" className='toggle'
defaultChecked={todoObj.isDone ? true : false} />
<label htmlFor={todoObj.id}>{todoObj.name}</label>
<button className="destroy"></button>
</div>
</li>
})
}
</ul>
</section>
<footer className='footer'>
<span className="todo-count">
任务总数:{2} | 已完成: {1}
</span>
</footer>
</section>
)
}
export default observer(Task)
使用的是Mobx中的响应式数据,用数组的map方法对数据进行遍历,之后渲染在组件中。
首先要给Task组件声明一个自己的数据。(Mobx)
思想:通过Mobx中的store去维护状态,input只需要把event.target.checked交给store让它进行修改
task.Store.js
添加一个修改单选框选中与否的方法(修改对应id的isDone)// 单选操作
singleCheck(id, isDone) {
// 通过id修改对应的isDone
const todoObj = this.list.find(item => item.id === id)
todoObj.isDone = isDone
}
/src/Todo/Task.jsx
组件中,点击单选框触发onChange
事件,调用store中的singleCheck
方法。{/* 单选受控 */}
{/* 通过Mobx中的store去维护状态,input只需要把event.target.checked交给store让它进行修改 */}
<input id={todoObj.id} type="checkbox" className='toggle'
checked={todoObj.isDone}
onChange={event => taskStore.singleCheck(todoObj.id, event.target.checked)}
/>
思想:除了在store中需要定义全选方法,还需要通过Mobx的计算属性定义一个是否所有项都被选中与否的方法,如果所有项都被选中,那么点击全选按钮可以变为全不选;如果不是所有项都被选中,那么点击全选按钮变为全选。
task.Store.js
添加一个全选/全不选方法。// 全选操作
allCheck(checked) {
// 把所有项的isDone属性,都按照传入的最新的值修改
this.list.map(item => {
item.isDone = checked
})
}
task.Store.js
定义计算属性isAllDone
,当所有的项都被选中时,这个属性为true;否则为false。// 计算属性 只有所有子项都是选中的时候,才是选中的状态
get isAllDone() {
return this.list.every(item => item.isDone)
}
constructor() {
- makeAutoObservable(this)
+ makeAutoObservable(this, {
isAllDone: computed
})
}
/src/Todo/Task.jsx
组件中,点击全选框,进行全选与全不选之间的改动{/* 全选 */}
<input type="checkbox" id='toggle-all' className='toggle-all'
checked={taskStore.isAllDone}
onChange={() => taskStore.allCheck(!taskStore.isAllDone)}
/>
思想:在store中定义删除方法,使用filter数组方法,删除对应id的那一组数据
task.Store.js
添加删除的方法// 删除操作
delTask(id) {
this.list = this.list.filter(item => item.id !== id)
}
/src/Todo/Task.jsx
组件中点击删除按钮,删除对应那一行的todo。<button className="destroy" onClick={() => taskStore.delTask(todoObj.id)}></button>
思想:在组件中使用useState-hook,用于临时存放一下新增输入框的value内容。之后,在按下
Enter
之后,调用store中定义的新增方法,实现新增功能。
task.Store.js
添加新增的方法// 新增操作
insertTask(task) {
this.list.push(task)
}
useState
临时存放输入框的value值。// 存放新增的todo
const [taskValue, setTaskValue] = useState('')
// 新增输入框
<input className='new-todo' autoFocus autoComplete='off' placeholder='What needs to be done?'
value={taskValue} onChange={event => setTaskValue(event.target.value)} />
其实也就是受控组件一样的写法,把输入框与taskValue这个临时state绑定。
Enter
实现新增。// 为input添加属性
onKeyUp={event => addTask(event)
// 定义addTask方法
function addTask(event) {
if (event.keyCode !== 13) return
if (taskValue.trim() === '') {
alert('输入不能为空!')
return
}
taskStore.insertTask({
id: nanoid(), // 使用第三方库nanoid自动生成随机的id值
name: taskValue,
isDone: false
})
setTaskValue('')
}
任务总数很简单,其实就是list数组的长度。
{taskStore.list.length}
已完成的数量需要借助Mobx
中的计算属性来完成具体代码如下:
task.Store.js
中定义计算属性isFinishedLength
// 已完成的数量
get isFinishedLength() {
return this.list.filter(item => item.isDone).length
}
constructor() {
makeAutoObservable(this, {
isAllDone: computed,
+ isFinishedLength: computed
})
}
{taskStore.isFinishedLength}