React+Mobx|综合项目实践(附项目源码、地址)

在这里插入图片描述

欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框架 React框架 React框架,中间穿插了一些基础知识的回顾
博客主页codeMak1r.小新的博客

本文目录

  • Todos - Mobx - 综合案例
    • 1.渲染列表
    • 2.单选功能实现
    • 3.全选功能实现
    • 4.删除功能实现
    • 5.回车新增功能实现
    • 6.统计计数功能实现
    • 7.Mobx - React 职责划分

本文被专栏【React–从基础到实战】收录

坚持创作✏️,一起学习,码出未来‍!

Todos - Mobx - 综合案例

React+Mobx|综合项目实践(附项目源码、地址)_第1张图片

项目演示地址:https://react-course-series.gitee.io/mobx_react/
React+Mobx|综合项目实践(附项目源码、地址)_第2张图片

  1. 渲染列表数据
  2. 单选功能
  3. 全选功能
  4. 删除功能
  5. 回车新增功能
  6. 统计计数功能

项目目录:

src
├─App.jsx
├─index.js
├─store
|   ├─index.js
|   └task.Store.js
├─Todo
|  ├─index.css
|  └index.jsx

1.渲染列表

/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方法对数据进行遍历,之后渲染在组件中。

2.单选功能实现

首先要给Task组件声明一个自己的数据。(Mobx)

思想:通过Mobx中的store去维护状态,input只需要把event.target.checked交给store让它进行修改

  1. task.Store.js添加一个修改单选框选中与否的方法(修改对应id的isDone)
// 单选操作
singleCheck(id, isDone) {
  // 通过id修改对应的isDone
  const todoObj = this.list.find(item => item.id === id)
  todoObj.isDone = isDone
}
  1. /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)}
/>

3.全选功能实现

思想:除了在store中需要定义全选方法,还需要通过Mobx的计算属性定义一个是否所有项都被选中与否的方法,如果所有项都被选中,那么点击全选按钮可以变为全不选;如果不是所有项都被选中,那么点击全选按钮变为全选。

  1. task.Store.js添加一个全选/全不选方法。
// 全选操作
allCheck(checked) {
  // 把所有项的isDone属性,都按照传入的最新的值修改
  this.list.map(item => {
    item.isDone = checked
  })
}
  1. task.Store.js定义计算属性isAllDone,当所有的项都被选中时,这个属性为true;否则为false。
// 计算属性 只有所有子项都是选中的时候,才是选中的状态
get isAllDone() {
	return this.list.every(item => item.isDone)
}
constructor() {
- makeAutoObservable(this)
+ makeAutoObservable(this, {
    isAllDone: computed
  })
}
  1. /src/Todo/Task.jsx组件中,点击全选框,进行全选与全不选之间的改动
{/* 全选 */}
<input type="checkbox" id='toggle-all' className='toggle-all'
	checked={taskStore.isAllDone}
	onChange={() => taskStore.allCheck(!taskStore.isAllDone)}
/>

4.删除功能实现

思想:在store中定义删除方法,使用filter数组方法,删除对应id的那一组数据

  1. task.Store.js添加删除的方法
// 删除操作
delTask(id) {
  this.list = this.list.filter(item => item.id !== id)
}
  1. /src/Todo/Task.jsx组件中点击删除按钮,删除对应那一行的todo。
<button className="destroy" onClick={() => taskStore.delTask(todoObj.id)}></button>

5.回车新增功能实现

思想:在组件中使用useState-hook,用于临时存放一下新增输入框的value内容。之后,在按下Enter之后,调用store中定义的新增方法,实现新增功能。

  1. task.Store.js添加新增的方法
// 新增操作
insertTask(task) {
  this.list.push(task)
}
  1. 在组件中,使用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绑定。

  1. 按下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('')
  }

6.统计计数功能实现

任务总数很简单,其实就是list数组的长度。

{taskStore.list.length}

已完成的数量需要借助Mobx中的计算属性来完成具体代码如下:

  1. task.Store.js中定义计算属性isFinishedLength
// 已完成的数量
get isFinishedLength() {
	return this.list.filter(item => item.isDone).length
}
constructor() {
  makeAutoObservable(this, {
    isAllDone: computed,
  + isFinishedLength: computed
  })
}
  1. 渲染
{taskStore.isFinishedLength}

7.Mobx - React 职责划分

你可能感兴趣的:(React--从基础到实战,前端,javascript,react.js)