摘要:而且关联关系只需要定义一次就可以了,不需要重复定义。更新状态主要是用来更新,响应并发送到的引用状态变化。不能够在中传递参数执行有副作用的操作以及调用非纯函数。主要是让容器组件拿到。
Redux-ORM理解之实现Todo List 一、概念
redux-orm及其作用:
redux-orm主要是用来管理我们的state数据,当一个项目比较大,逻辑结构比较复杂,每个数据之间都有联系,此时便需要将这些state进行统一管理,redux-orm就是用来解决这些数据间的关联问题,所以redux-orm就像一个关系型数据库,而每个对象类型就像是数据库中的数据表,并且是以JavaScript的对象形式存储这些数据的。
那么也就是说,当项目的中涉及到的对象类型并不很多,且对象类型之间的关联性不大的时候,并不建议使用redux-orm,如果项目足够简单,连redux也不需要使用到。
在todo list 实现的基本功能有:
选择用户
创建todo
标记todo完成
删除todo
创建tag标签
移除tag标签
所以按照上面的功能,可以将todo list分为三张表,分别是user(用户表)、todo表和tag标签表,这些表就相当于一个实例,每个实例都会有自己的行为属性和方法
User:
属性:id、 name
行为:selectUser
Todo:
属性:id、text(todo内容)、done(标记结束)、user、 tags
行为: createTodo、markDone、deleteTodo
Tag:
属性: name
行为: addTagToTodo、 removeTagFromTodo
State是一个对象,是用来描述应用。在这个todo list中,当需要有一个对象用来描述
Action是把数据从应用传到store的有效载荷,它是store数据的唯一来源。其本质上是JavaScript普通对象,action内必须使用type字符串类型,type表示将要执行的动作,在多数情况下,type被已定义为字符串常量。
Action创建函数就是生成action方法,该方法只是简单的返回一个action。例如,对于添加标签这个action是这样执行的,先创建一个addTagToTodo的方法,该方法接收tag和todo两个参数,然后将其返回为一个对象,其中对象的属性值中必须有一个type
export const addTagToTodo = (todo, tag) => { return { type: ADD_TAG_TO_TODO, payload: { todo, tag, }, }; };
在ORM中定义了一个Model类来将实体类关联起来, 对于Todo这个实体类来说,通过ES6类语法进行定义,并继承了ORM的Model类。
Model需要设置名称才可以识别到对应的数据,以及实体类与其他数据关联的方式。
对于Todo类来说,它跟User只能是一对多,一个User下有多个Todo,而跟tag可以多对多,一个Todo可以有多个tag,通用一个tag可以存在在多个Todo中,所以Model类中的fields主要是用了来定义当前实体类与其他类的关联关系,这些如:fk、many、oneToOne接收两个参数,第一个是被关联的实体类,就是在Model中定义的modelName和操作的类名。 而且关联关系只需要定义一次就可以了,不需要重复定义。
最后要实现实体类间的关联必须将其注册到Schema()方法中并导出,这样才能够真正关联其实体间的关系。当实体类比较多的情况下,可能需要一个多带带的文件来存放这些需要注册的实体类,这样可以使项目模块化更易于管理。
import { Schema, Model, many, fk } from "redux-orm"; import { CREATE_TODO, MARK_DONE, DELETE_TODO, ADD_TAG_TO_TODO, REMOVE_TAG_FROM_TODO, } from "./actions"; export class Todo extends Model { static reducer(state, action, Todo, session) { const { payload, type } = action; switch (type) { case CREATE_TODO: const tagIds = action.payload.tags.split(",").map(str => str.trim()); const props = Object.assign({}, payload, { tags: tagIds, done: false }); Todo.create(props); break; case MARK_DONE: Todo.withId(payload).done = true; break; case DELETE_TODO: Todo.withId(payload).delete(); break; case ADD_TAG_TO_TODO: Todo.withId(payload.todo).tags.add(payload.tag); break; case REMOVE_TAG_FROM_TODO: Todo.withId(payload.todo).tags.remove(payload.tag); break; } } } Todo.modelName = "Todo"; Todo.fields = { tags: many("Tag", "todos"), user: fk("User", "todos"), }; export const schema = new Schema(); schema.register(Todo); export default schema;
Reducers主要是用来更新state,响应actions并发送到store的引用状态变化。
在Redux应用中,所有的state都被保存在一个单一对象中。
reducer是一个纯函数,接收旧的state和action,返回新的state。不能够在reducer中传递参数、执行有副作用的操作以及调用非纯函数。只需单纯地执行计算就可以,其更新是局部的,只有当当前的reducer中的数据发生改变后,reducer才会重新进行计算。
在Redux-ORM中使用特定reducers的模型来操作数据。首先在Model类中先定义一个静态的reducer方法,它会接收所有需要更新的action。如果没有定义reducers的话,ORM会直接使用默认方法去实现更新。
其原理是,在静态的reducer方法中接收四个参数:state(状态)、action(当前操作)、Todo(模型类)、session(ORM的会话实例)。在Todo的reducer中,通过对当前Todo的type进行循环遍历来执行对Todo的增加、删除、修改等操作,而session这个会话实例参数主要是用来访问和查询其他Model,但是不建议在当前的Model修改其他Model中的数据。
在Redux-ORM中的seletors是使用了了第三方插件reselect
selector在ORM中可以计算派生数据,其在整个ORM中一直是有效的,跟reducer一样,只要其接收的参数发生改变就会触发该方法,而且selector是可组合的,可以作为其他seletor的输入
export const todos = createSelector( ormSelector, state => state.selectedUserId, schema.createSelector((orm, userId) => { return orm.Todo.withRefs.filter({ user: userId }).map(todo => { const obj = Object.assign({}, todo.ref); obj.tags = todo.tags.withRefs.map(tag => tag.name); return obj; }); }) );
首先使用createSelector方法创建了todo的选择器,该方法中的第一个参数始终是orm的selector,然后对input selector进行回调,回调是用过schema创建了createSelector方法来计算关联的数据然后并返回。
在todo的seletor中,通过与selectedUserId中进行关联,当被选中的userId发生变化时就会触发该方法,并过滤出该user下的所有Todo数据及该Todo下的tag数据并返回。
当我们将所有的数据都定义好了之后,就需要在视图中去使用
首先,在入口文件导入redux中的createStore、combineReducers、applyMiddleware、Provider还有redux中的createLogger等方法
createStore:该函数主要是用来生成store, store就是保存数据的地方,相当于一个容器,整个项目中只能有一个store
combineReducer:主要是用于Reducer的拆分,其可以将拆分的各个子reducer函数通过该方法合成一个大的Reducer
applyMiddleware、createLogger都是redux的中间件,主要是用来执行异步操作。其中createLogger是redux-logger模块中的方法,是生成redux日志,并打印在控制台,该方法是放在applyMiddleware方法中。
Provider: 主要是让Store容器组件拿到state。
最后,可以使用redux中的connect()方法将UI组件和store容器组件连接起来,主要依靠输入与输出来实现。
输入(mapStateToProps)是将store中的数组转化为UI组件的参数。 其是一个函数,建立一个从state对象到UI组件props对象的映射关系,其执行后返回一个对象,里面的每个键值对就是一个映射
输出(mapDispatchToProps)是用户发出的动作转变成Action对象,从UI组件传出去。它定义哪些用户的操作应该当做Action并传给Store,它个可以是一个函数,也可以是一个对象。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/96365.html
摘要:但还存在一些问题,比如,单向数据流导致的有时数据链过长过繁琐所以才产生了,需要在多地保存同一份数据等等。数据流细粒度的目前来说,我们的的甚至是还是设计得太过简单。 前言 由于笔者对React的了解不深,即便算是学习React的时间,到目前也才刚刚半年,所以错误不足之处还望指正。以下都是基于React 15(可能有些是16),webpack1进行探讨(注:未学习过Vue,Ng,Emb...
摘要:前言最近在学习框架的基本原理,看了一些技术博客以及一些对源码的简单实现,对数据代理数据劫持模板解析变异数组方法双向绑定有了更深的理解。 前言 最近在学习vue框架的基本原理,看了一些技术博客以及一些对vue源码的简单实现,对数据代理、数据劫持、模板解析、变异数组方法、双向绑定有了更深的理解。于是乎,尝试着去实践自己学到的知识,用vue的一些基本原理实现一个简单的todo-list,完成...
摘要:前言在学习组件化开发的时候,自己虽然也能编码实现,但如果不做笔记,只是写代码,学习的效果还不够好。为组件准备好数据之后,就可以开始用它了。新增的代码如下上面是组件新增的代码,用户点击按钮之后,会执行该组件内的函数。 前言 在学习 Vue.js 组件化开发 Todo List 的时候,自己虽然也能编码实现,但如果不做笔记,只是写代码,学习的效果还不够好。只有把自己的实现思路记录下来,遇到...
摘要:网络上大多数文章,也是千篇一律的翻译这句话,可是仅凭这一句话,我想象不到的使用场景。因为真正的使用场景下,子组件的数据都是来自父组件的。组件的数据都是来自调用者的,然后会把每一行的,在开发者需要时,传递出去。 Vue的slot-scope的场景的个人理解 这篇文章不是单纯把文档的话和api拿来翻译和演示,而是谈谈我对于slot-scope的使用场景的个人理解,如果理解错误,欢迎讨论! ...
摘要:数据结构之应用之常用命令之应用场景说明本文参考了开发实战指南,还有实战自己之前的笔记。我们正式进入主题吧,中种数据结构的使用场景介绍。应用场景土法建索引。此命令会覆盖哈希表中已存在的域。 数据结构之Redis应用之常用命令之应用场景 说明 1、本文参考了Redis开发实战指南GitBook,还有《Redis实战》自己之前的笔记。主体框架来自这里。 2、感谢大佬们的付出,在这里自己只是...
阅读 2860·2021-10-14 09:50
阅读 1217·2021-10-08 10:21
阅读 3645·2021-10-08 10:16
阅读 3062·2021-09-27 14:02
阅读 3135·2021-09-23 11:21
阅读 2108·2021-09-07 10:17
阅读 406·2019-08-30 14:00
阅读 2105·2019-08-29 17:26