素材巴巴 > 程序开发 >

大前端 - react -Mobx6(数据流)

程序开发 2023-09-17 07:34:14

代码地址:

1.mobx概述

mobx是什么?mobox是状态管理库。和redux做的事情一样,但是比redux简单。
没有那么多的模版代码。

目前最新版本为 6,版本 4 和版本 5 已不再支持。

在 MobX 6 中不推荐使用装饰器语法,因为它不是 ES 标准,并且标准化过程要花费很长时间,但是通过配置仍然可以启用装饰器语法。

MobX 可以运行在任何支持 ES5 的环境中,包含浏览器和 Node。

MobX 通常和 React 配合使用,但是在 Angular 和 Vue 中也可以使用 MobX。

02-mobx中的核心概念

核心概念

  1. observable:被 MobX 跟踪的状态。
  2. action:允许修改状态的方法,在严格模式下只有 action 方法被允许修改状态。
  3. computed:根据现有状态衍生出来的状态。
  4. flow:执行副作用,它是 generator 函数。可以更改状态值。

3. 工作流程

在这里插入图片描述
工作流程文字描述:
在视图中,通过触发事件,调用actions方法,当调用actions 方法之后,才会去更新状态,当这个状态更新完成之后会去更新基于这个状态的派生状态,派生状态更新完成之后,就会去更新视图了。这就是它的工作流程。

4. 下载

yarn add mobx@6.3.1 mobx-react-lite@3.2.0

5. 案例:驱动之计数器

在组件中显示数值状态,单击[+1]按钮使数值加一,单击[-1]按钮使数值减一。

  1. 创建用于存储状态的 Store
export default class CounterStore{constructor() {this.count = 0}
 } 
 
  1. 创建用于修改状态的方法
export default class CounterStore{constructor() {this.count = 0}increment() {this.count + =1}decrement() {this.count -=1}} 
 
  1. 让 MobX 可以追踪状态的变化

 // makeObservable: 
 // 第一个参数是this,这个this指的是当前类的实例对象。 
 // 第2个参数:配置对象。在这个对象中可以指定哪些是属性,哪些是状态。
 import { action, makeObservable, observable } from "mobx"export default class CounterStore {constructor() {this.count = 0makeObservable(this, {// 标记为状态count: observable,// 标记为更改状态的方法increment: action,decrement: action})}increment() {this.count += 1}decrement() {this.count -= 1}}
 
  1. 创建 Store 类的实例对象并将实例对象传递给组件
// App.js
 import Counter from "./Counter"
 import CounterStore from "../store/Counter"const counterStore = new CounterStore()function App() {return 
 }export default App
 
  1. 在组件中通过 Store 实例对象获取状态以及操作状态的方法
   function Counter({ counterStore }) {return ()}export default Counter
 
  1. 当组件中使用到的 MobX 管理的状态发生变化后,使视图更新。通过 observer 方法包裹组件实现目的
   import { observer } from "mobx-react-lite"function Counter() { }export default observer(Counter)
 
  1. 简化组件代码(会报错,因为this指向问题)
 function Counter({ counterStore }) {const { count, increment, decrement } = counterStorereturn ()}
 
  1. 当代码简化后,修改状态的方法中的 this 指向出现了问题,通过 action.bound 强制绑定 this,使 this 指向 Store 实例对象
import { action, makeObservable, observable } from "mobx"export default class CounterStore {constructor() {this.count = 0makeObservable(this, {// 标记为状态count: observable,// 标记为actionincrement: action.bound,decrement: action.bound})}increment() {this.count += 1}decrement() {this.count -= 1}
 }
 
  1. 总结:状态变化更新视图的必要条件

    1. 状态必须被标记为 observable
    2. 更改状态的方法必须被标记为 action
    3. 组件必须通过 observer 方法包裹
  2. 创建RootStore实现全局状态共享
    1.在应用中可存在多个 Store,多个 Store 最终要通过 RootStore 管理,在每个组件都需要获取到 RootStore。
    2.实现全局状态共享

// store/index.jsimport { createContext, useContext } from "react"import CounterStore from "./Counter"class RootStore {constructor() {this.counterStore = new CounterStore()}}const rootStore = new RootStore()const RootStoreContext = createContext()export const RootStoreProvider = ({ children }) => {return ({children})}export const useRootStore = () => {return useContext(RootStoreContext)}
 
   // App.jsimport { RootStoreProvider } from "../store"import Counter from "./Counter"function App() {return ()}export default App
 
// Counter.jsimport { observer } from "mobx-react-lite"import { useRootStore } from "../store"function Counter() {const { counterStore } = useRootStore()const { count, increment, decrement } = counterStorereturn ()}// 数据变化重新渲染组件export default observer(Counter)
 

6. 案例驱动之 Todo

6.1 创建 Store

  1. 创建用于管理 Todo 任务的 Store

    import { makeObservable, observable } from "mobx"export default class Todo {constructor(todo) {this.id = todo.idthis.title = todo.titlethis.isCompleted = todo.isCompleted || falsethis.isEditing = falsemakeObservable(this, {title: observable,isCompleted: observable,isEditing: observable})}
     }
     
  2. 创建用于管理 Todo 任务列表的 Store

    import { makeObservable, observable } from "mobx"export default class TodoStore {constructor() {this.todos = []makeObservable(this, {todos: observable})}
     }
     

6.2 添加任务

  1. 创建向 todo 任务列表中添加 todo 任务的方法

    import { action, makeObservable, observable } from "mobx"
     import Todo from "./Todo"export default class TodoStore {constructor() {this.todos = []makeObservable(this, {todos: observable,addTodo: action.bound})}addTodo(title) {this.todos.push(new Todo({ title, id: this.generateTodoId() }))}generateTodoId() {if (!this.todos.length) return 1return this.todos.reduce((id, todo) => (id < todo.id ? todo.id : id), 0) + 1}
     }
     
  2. 在组件中实现添加任务的逻辑

    import { useState } from "react"
     import { useRootStore } from "../../store"function Header() {const [title, setTitle] = useState("")const { todoStore } = useRootStore()const { addTodo } = todoStorereturn (
    setTitle(e.target.value)}onKeyUp={e => {if (e.key !== "Enter") returnaddTodo(title)setTitle("")}}/>
    ) }export default Header

6.3 显示任务列表

import { observer } from "mobx-react-lite"
 import { useRootStore } from "../../store"
 import Todo from "./Todo"function Main() {const { todoStore } = useRootStore()const { todos } = todoStorereturn (
    {todos.map(todo => ())}
) }export default observer(Main)
function Todo({ todo }) {return (
  • ) }export default Todo

    6.4 加载远端任务

    1. 下载 json-server:yarn add json-server@0.16.3

    2. 创建 db.json

      {"todos": [{"id": 1,"title": "吃饭","isCompleted": false},{"id": 2,"title": "睡觉","isCompleted": false},{"id": 3,"title": "打豆豆","isCompleted": false}]
       }
       
    3. 在 package.json 文件中添加启动命令

      "scripts": {"json-server": "json-server --watch ./db.json --port 3001"}
       
    4. 启动 json-server:npm run json-server

    5. 在 todoStore 中添加加载任务列表的方法

      import axios from "axios"
       import { flow, makeObservable, observable } from "mobx"
       import Todo from "./Todo"export default class TodoStore {constructor() {this.todos = []makeObservable(this, {todos: observable,loadTodos: flow})this.loadTodos()}*loadTodos() {let response = yield axios.get("http://localhost:3001/todos")response.data.forEach(todo => this.todos.push(new Todo(todo)))}
       }
       

    6.5 更改任务状态

    1. 在 Todo 类中添加修改任务是否已经完成的方法

      export default class Todo {constructor() {makeObservable(this, {modifyTodoIsCompleted: action.bound})}modifyTodoIsCompleted() {this.isCompleted = !this.isCompleted}
       }
       
    2. 创建 TodoCompleted 组件实现逻辑

      import { observer } from "mobx-react-lite"function TodoCompleted({ todo }) {const { isCompleted, modifyTodoIsCompleted } = todoreturn ()
       }export default observer(TodoCompleted)
       
    3. Todo 组件中引用TodoCompleted 组件并根据条件决定是否为 li 添加 completed 类名

      import { observer } from "mobx-react-lite"
       import TodoCompleted from "./TodoCompleted"function Todo({ todo }) {return (
    4. ) }export default observer(Todo)

    6.6 删除任务

    1. todoStore 中添加实现删除任务的方法

      import axios from "axios"
       import { action, makeObservable,  } from "mobx"export default class TodoStore {constructor() {makeObservable(this, {removeTodo: action.bound})}removeTodo(id) {this.todos = this.todos.filter(todo => todo.id !== id)}
       }
       
    2. 创建 TodoDelete 组件实现删除 todo 任务逻辑

      import { useRootStore } from "../../store"function TodoDelete({ id }) {const { todoStore } = useRootStore()const { removeTodo } = todoStorereturn 
    3. Todo 组件调用 TodoDelete 组件并传入 todo ID

      import { observer } from "mobx-react-lite"
       import TodoDelete from "./TodoDelete"function Todo({ todo }) {return (
    4. ) }export default observer(Todo)

    6.7 编辑任务

    1. 在 todoStore 中添加更改任务是否处于编辑状态的方法

      import { action, makeObservable } from "mobx"export default class Todo {constructor(todo) {makeObservable(this, {modifyTodoIsEditing: action.bound,})}modifyTodoIsEditing() {this.isEditing = !this.isEditing}
       }
       
    2. 添加 TodoTitle 组件展示任务标题并为其添加双击事件,当事件发生时将任务更改为可编辑状态

      function TodoTitle({ todo }) {const { title, modifyTodoIsEditing } = todoreturn 
       }export default TodoTitle
       
    3. Todo 组件中调用 TodoTitle 组件,并为 li 添加 editing 类名

      import { observer } from "mobx-react-lite"
       import TodoTitle from "./TodoTitle"
       import classnames from "classnames"function Todo({ todo }) {return (
    4. ) }export default observer(Todo)
    5. 创建 TodoEditing 组件实现编辑 todo 任务标题

      import { useRef, useEffect } from "react"function TodoEditing({ todo }) {const { title, modifyTodoTitle, isEditing } = todoconst ref = useRef(null)useEffect(() => {if (isEditing) ref.current.focus()}, [isEditing])return ( modifyTodoTitle(e.target.value)}/>)
       }export default TodoEditing
       
    6. Todo 组件中调用 TodoEditing 组件并传递 todo 任务

      import { observer } from "mobx-react-lite"
       import TodoTitle from "./TodoTitle"
       import classnames from "classnames"
       import TodoEditing from "./TodoEditing"function Todo({ todo }) {return (
    7. ) }export default observer(Todo)

    6.8 计算未完成任务数量

    1. 在 todoStore 中添加获取未完成任务数量的派生状态

      import axios from "axios"
       import { makeObservable, computed } from "mobx"export default class TodoStore {constructor() {makeObservable(this, {unCompletedTodoCount: computed})}// 派生状态get unCompletedTodoCount() {return this.todos.filter(todo => !todo.isCompleted).length}
       }
       
    2. 创建 UnCompletedTodoCount 组件实现逻辑

      import { observer } from "mobx-react-lite"
       import { useRootStore } from "../../store"function UnCompletedTodoCount() {const { todoStore } = useRootStore()const { unCompletedTodoCount } = todoStorereturn ({unCompletedTodoCount} item left)
       }export default observer(UnCompletedTodoCount)
       
    3. Footer 组件中调用 UnCompletedTodoCount 组件

      import UnCompletedTodoCount from "./UnCompletedTodoCount"function Footer() {return (
      ) }export default Footer

    6.9 任务过滤

    1. todoStore 中添加存储过滤条件的属性以及更改过滤条件的方法

      import axios from "axios"
       import { action, makeObservable, observable, } from "mobx"export default class TodoStore {constructor() {this.filterCondition = "All"makeObservable(this, {modifyFilterCondition: action.bound,filterCondition: observable,})}modifyFilterCondition(filterCondition) {this.filterCondition = filterCondition}
       }
       
    2. 创建 TodoFilter 组件,为过滤按钮添加事件以更改过滤条件,根据过滤条件为按钮添加 selected 类名

      import classNames from "classnames"
       import { observer } from "mobx-react-lite"
       import { useRootStore } from "../../store"function TodoFilter() {const { todoStore } = useRootStore()const { filterCondition, modifyFilterCondition } = todoStorereturn (
      • modifyFilterCondition("All")}className={classNames({ selected: filterCondition === "All" })}>All
      • modifyFilterCondition("Active")}className={classNames({ selected: filterCondition === "Active" })}>Active
      • modifyFilterCondition("Completed")}className={classNames({ selected: filterCondition === "Completed" })}>Completed
      ) }export default observer(TodoFilter)
    3. Footer 组件中调用 TodoFilter 组件

      import TodoFilter from "./TodoFilter"function Footer() {return (
      ) }export default Footer
    4. TodoStore 中添加派生状态,根据条件获取过滤后的 todo 列表

      import axios from "axios"
       import { action, flow, makeObservable, observable, computed } from "mobx"
       import Todo from "./Todo"export default class TodoStore {constructor() {makeObservable(this, {filterTodos: computed})}get filterTodos() {switch (this.filterCondition) {case "Active":return this.todos.filter(todo => !todo.isCompleted)case "Completed":return this.todos.filter(todo => todo.isCompleted)default:return this.todos}}
       }
       
    5. 在 Main 组件获取 filterTodos 派生状态

      import { observer } from "mobx-react-lite"
       import { useRootStore } from "../../store"
       import Todo from "./Todo"function Main() {const { todoStore } = useRootStore()const { filterTodos } = todoStorereturn (
        {filterTodos.map(todo => ())}
      ) }export default observer(Main)

    6.10 清除已完成任务

    1. TodoStore 中添加清除已完成任务的方法

      import axios from "axios"
       import { action, makeObservable, } from "mobx"export default class TodoStore {constructor() {makeObservable(this, {clearCompleted: action.bound})}clearCompleted() {this.todos = this.todos.filter(todo => !todo.isCompleted)}
       }
       
    2. 创建 ClearCompleted 组件实现清除已完成任务功能

      import { useRootStore } from "../../store"function ClearCompleted() {const { todoStore } = useRootStore()const { clearCompleted } = todoStorereturn ()
       }export default ClearCompleted
       
    3. Footer 组件中调用 ClearCompleted 组件

      import ClearCompleted from "./ClearCompleted"function Footer() {return (
      ) }export default Footer

    标签:

    上一篇: nodejs npm gulp使用详细教程 下一篇:
    素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。