Dob项目实战从零构建一个完整的TodoMVC应用 【免费下载链接】dobLight and fast state management tool using proxy.项目地址: https://gitcode.com/gh_mirrors/do/dob想要掌握现代前端状态管理技术吗Dob作为一个轻量级且快速的状态管理工具使用Proxy技术实现响应式编程让状态管理变得简单而高效。本文将带你从零开始使用Dob构建一个完整的TodoMVC应用深入理解这个强大的状态管理工具。什么是Dob状态管理工具Dob是一个基于JavaScript Proxy实现的轻量级状态管理库它提供了类似MobX的响应式编程体验但更加轻量和简单。通过Dob你可以轻松实现数据的自动追踪和响应式更新让前端状态管理变得异常简单。Dob的核心特性包括基于ES6 Proxy实现无需额外配置支持TypeScript提供完整的类型安全轻量级设计体积小巧与React完美集成开始构建TodoMVC应用环境准备首先我们需要创建一个新的React项目并安装Dob相关依赖# 创建React应用 npx create-react-app dob-todomvc --template typescript # 进入项目目录 cd dob-todomvc # 安装Dob和dob-react npm install dob dob-react项目结构设计一个良好的项目结构是成功的一半。我们的TodoMVC应用将采用以下结构src/ ├── stores/ # 状态存储 │ ├── todo.store.ts │ └── filter.store.ts ├── actions/ # 业务逻辑 │ └── todo.action.ts ├── components/ # 组件 │ ├── TodoInput.tsx │ ├── TodoList.tsx │ ├── TodoItem.tsx │ └── Footer.tsx └── App.tsx创建状态存储让我们从定义Todo的状态存储开始。在src/stores/todo.store.ts中import { observable } from dob export interface Todo { id: number text: string completed: boolean } observable export class TodoStore { todos: Todo[] [] nextId 1 }实现业务逻辑接下来在src/actions/todo.action.ts中定义操作Todo的业务逻辑import { Action, inject } from dob import { Todo, TodoStore } from ../stores/todo.store export class TodoAction { inject(TodoStore) todoStore!: TodoStore Action addTodo(text: string) { this.todoStore.todos.push({ id: this.todoStore.nextId, text, completed: false }) } Action toggleTodo(id: number) { const todo this.todoStore.todos.find(t t.id id) if (todo) { todo.completed !todo.completed } } Action deleteTodo(id: number) { const index this.todoStore.todos.findIndex(t t.id id) if (index -1) { this.todoStore.todos.splice(index, 1) } } Action editTodo(id: number, newText: string) { const todo this.todoStore.todos.find(t t.id id) if (todo) { todo.text newText } } Action clearCompleted() { this.todoStore.todos this.todoStore.todos.filter(t !t.completed) } }创建过滤状态存储为了支持TodoMVC的过滤功能我们还需要一个过滤状态存储// src/stores/filter.store.ts import { observable } from dob export type FilterType all | active | completed observable export class FilterStore { currentFilter: FilterType all }构建React组件现在让我们创建React组件。首先创建Todo输入组件// src/components/TodoInput.tsx import React, { useState } from react import { Connect } from dob-react import { TodoAction } from ../actions/todo.action interface Props { TodoAction: TodoAction } const TodoInput: React.FCProps ({ TodoAction }) { const [inputValue, setInputValue] useState() const handleSubmit (e: React.FormEvent) { e.preventDefault() if (inputValue.trim()) { TodoAction.addTodo(inputValue.trim()) setInputValue() } } return ( form onSubmit{handleSubmit} input typetext value{inputValue} onChange{(e) setInputValue(e.target.value)} placeholderWhat needs to be done? autoFocus / /form ) } export default Connect(TodoInput)创建Todo列表组件// src/components/TodoList.tsx import React from react import { Connect } from dob-react import { TodoStore } from ../stores/todo.store import { FilterStore } from ../stores/filter.store import TodoItem from ./TodoItem interface Props { TodoStore: TodoStore FilterStore: FilterStore } const TodoList: React.FCProps ({ TodoStore, FilterStore }) { const getFilteredTodos () { switch (FilterStore.currentFilter) { case active: return TodoStore.todos.filter(todo !todo.completed) case completed: return TodoStore.todos.filter(todo todo.completed) default: return TodoStore.todos } } const todos getFilteredTodos() return ( ul {todos.map(todo ( TodoItem key{todo.id} todo{todo} / ))} /ul ) } export default Connect(TodoList)实现Todo项组件// src/components/TodoItem.tsx import React, { useState } from react import { Connect } from dob-react import { TodoAction } from ../actions/todo.action import { Todo } from ../stores/todo.store interface Props { todo: Todo TodoAction: TodoAction } const TodoItem: React.FCProps ({ todo, TodoAction }) { const [editing, setEditing] useState(false) const [editText, setEditText] useState(todo.text) const handleDoubleClick () { setEditing(true) setEditText(todo.text) } const handleSave () { if (editText.trim()) { TodoAction.editTodo(todo.id, editText.trim()) } else { TodoAction.deleteTodo(todo.id) } setEditing(false) } const handleKeyDown (e: React.KeyboardEvent) { if (e.key Enter) { handleSave() } else if (e.key Escape) { setEditing(false) setEditText(todo.text) } } if (editing) { return ( li input typetext value{editText} onChange{(e) setEditText(e.target.value)} onBlur{handleSave} onKeyDown{handleKeyDown} autoFocus / /li ) } return ( li input typecheckbox checked{todo.completed} onChange{() TodoAction.toggleTodo(todo.id)} / span onDoubleClick{handleDoubleClick} style{{ textDecoration: todo.completed ? line-through : none }} {todo.text} /span button onClick{() TodoAction.deleteTodo(todo.id)}×/button /li ) } export default Connect(TodoItem)创建页脚组件// src/components/Footer.tsx import React from react import { Connect } from dob-react import { TodoStore } from ../stores/todo.store import { FilterStore, FilterType } from ../stores/filter.store import { TodoAction } from ../actions/todo.action interface Props { TodoStore: TodoStore FilterStore: FilterStore TodoAction: TodoAction } const Footer: React.FCProps ({ TodoStore, FilterStore, TodoAction }) { const activeCount TodoStore.todos.filter(todo !todo.completed).length const completedCount TodoStore.todos.length - activeCount const handleFilterChange (filter: FilterType) { FilterStore.currentFilter filter } return ( footer span{activeCount} items left/span div button onClick{() handleFilterChange(all)} style{{ fontWeight: FilterStore.currentFilter all ? bold : normal }} All /button button onClick{() handleFilterChange(active)} style{{ fontWeight: FilterStore.currentFilter active ? bold : normal }} Active /button button onClick{() handleFilterChange(completed)} style{{ fontWeight: FilterStore.currentFilter completed ? bold : normal }} Completed /button /div {completedCount 0 ( button onClick{() TodoAction.clearCompleted()} Clear completed /button )} /footer ) } export default Connect(Footer)集成所有组件现在让我们在src/App.tsx中集成所有组件import React from react import { Provider, combineStores } from dob-react import { TodoStore } from ./stores/todo.store import { FilterStore } from ./stores/filter.store import { TodoAction } from ./actions/todo.action import TodoInput from ./components/TodoInput import TodoList from ./components/TodoList import Footer from ./components/Footer const App: React.FC () { return ( Provider {...combineStores({ TodoStore, FilterStore, TodoAction })} div classNametodoapp header h1todos/h1 /header section TodoInput / TodoList / Footer / /section /div /Provider ) } export default AppDob的核心原理解析Proxy响应式机制Dob的核心在于使用ES6 Proxy来拦截对象的读写操作。当你在Dob的observable对象上读取属性时Dob会自动追踪这个依赖关系当属性发生变化时所有依赖它的观察者都会被自动通知。查看Dob的核心实现文件src/observer.ts 可以看到Dob如何通过Proxy实现响应式// 简化的Proxy实现 dynamicObject new Proxy(obj, { get(target, key, receiver) { // 追踪依赖 bindCurrentReaction(target, key) return Reflect.get(target, key, receiver) }, set(target, key, value, receiver) { const result Reflect.set(target, key, value, receiver) // 触发更新 queueRunReactions(target, key) return result } })依赖注入系统Dob内置了依赖注入系统通过inject装饰器可以轻松地在Action中注入Store。这有助于实现关注点分离使代码更加清晰和可维护。查看依赖注入的实现src/index.tsxAction装饰器Action装饰器用于标记那些会修改状态的方法。这有助于Dob在开发模式下进行调试和追踪状态变化。高级特性探索调试功能Dob提供了强大的调试功能你可以通过以下方式启用调试import { startDebug, stopDebug } from dob // 开始调试 startDebug() // 停止调试 stopDebug()查看调试实现src/debug.ts严格模式Dob支持严格模式确保所有状态修改都在Action中进行import { useStrict, cancelStrict } from dob // 启用严格模式 useStrict() // 取消严格模式 cancelStrict()内置集合类型支持Dob原生支持JavaScript的内置集合类型包括Map、Set、WeakMap和WeakSet。这些支持可以在 src/built-ins/ 目录中找到。最佳实践建议1. 保持Store的纯净Store应该只包含数据和计算属性业务逻辑应该放在Action中// 好的实践 observable class UserStore { name age 0 get isAdult() { return this.age 18 } } class UserAction { inject(UserStore) userStore!: UserStore Action updateName(name: string) { this.userStore.name name } }2. 使用依赖注入避免直接实例化Store使用Dob的依赖注入系统// 正确做法 class UserAction { inject(UserStore) userStore!: UserStore } // 错误做法 class UserAction { userStore new UserStore() // 避免这样做 }3. 合理组织项目结构采用清晰的项目结构有助于维护大型应用src/ ├── stores/ # 所有状态存储 ├── actions/ # 所有业务逻辑 ├── components/ # UI组件 ├── services/ # 外部服务 └── utils/ # 工具函数性能优化技巧1. 避免不必要的重新渲染使用React.memo或shouldComponentUpdate来防止不必要的组件重新渲染。2. 使用计算属性将复杂的计算逻辑放在Store的计算属性中Dob会自动缓存结果observable class TodoStore { todos: Todo[] [] get completedCount() { return this.todos.filter(todo todo.completed).length } get activeCount() { return this.todos.length - this.completedCount } }3. 批量更新Dob会自动批量处理在同一个Action中的状态更新确保高效的渲染。常见问题解答Q: Dob和Redux有什么区别A: Dob使用Proxy实现响应式编程而Redux使用纯函数和不可变数据。Dob的API更加简洁学习曲线更平缓。Q: Dob支持TypeScript吗A: 是的Dob完全支持TypeScript并提供完整的类型定义。Q: Dob的性能如何A: Dob使用Proxy实现性能优秀。对于大多数应用场景性能差异可以忽略不计。Q: 如何在服务端渲染中使用DobA: Dob支持服务端渲染你可以在服务器端创建Store实例然后将其传递给客户端。总结通过这个完整的TodoMVC应用构建过程你已经掌握了Dob状态管理工具的核心概念和使用方法。Dob以其简洁的API、优秀的TypeScript支持和出色的性能成为了现代前端开发中一个优秀的状态管理选择。记住Dob的核心优势在于简单易用基于Proxy的响应式API类型安全完整的TypeScript支持轻量高效小巧的体积优秀的性能生态完善与React完美集成现在你已经具备了使用Dob构建复杂前端应用的能力快去实践吧想要了解更多Dob的高级特性和最佳实践可以参考项目中的 docs/basic.tsx 文件和源代码实现。【免费下载链接】dobLight and fast state management tool using proxy.项目地址: https://gitcode.com/gh_mirrors/do/dob创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考