Closed Darmody closed 7 years ago
说说你的看法,解决什么问题,怎么实现。
解决的问题:
feeble
里的 model 还并不支持关联。假设存在 老师
和 学生
两个 model,老师可以有多个学生。那么如果我在一个老师的页面里需要显示属于这个老师的所有学生,现在的做法应该是要写 select
方法去找出来,比较不优美。如果能用类似 teacher.students()
的实例方法直接得到关联的 model 对象,开发者就会会心一笑。Entity
这样的 model,而且当我需要更新 老师
,学生
这些 model 时,都需要去 call Entity.update
这样的 action 来更新数据,代码读起来就不是很舒服。如果能有内建的 normalizr,开发者就不需要维护和关心 Entity
这样的 model (除非他有特殊需求,也还是可以去建立 Entity
model 自己维护),而 model 本身提供 Teacher.updateData
这样的静态方法去更新数据也会更语意化。怎么实现:
以 hackernews example 为例:
feeble
的构造函数中,将 Entity
定义为默认 model
https://github.com/feeblejs/feeble/blob/master/src/feeble.js#L34Entity
model 中相对应 state 的静态方法Story
的时候可以直接定义 model 的 schema :import { Schema, arrayOf } from 'normalizr'
const story = new Schema('story')
const user = new Schema('user')
const schema = {
STORY: story,
STORY_ARRAY: arrayOf(story),
USER: user,
}
const model = feeble.model({
namespace: `story::${type}`,
state: {
loading: false,
},
schema,
})
Story
的数据时,直接调用 Story.updateDate(id, story)
或 Story.updateDate(stories)
如: https://github.com/feeblejs/hackernews/blob/master/src/models/story.js#L85-L86Story
相关的用户时,可以调用 story.users()
获取。select
https://github.com/feeblejs/hackernews/blob/master/src/models/story.js#L97-L106我把 feeble
想象成一个比较完整的框架,所以我觉得类似 normalizr
这样的 lib 是需要的?
参考:https://github.com/tommikaikkonen/redux-orm
可以考虑加进来。
还有一种做法,其实用 normalizr 定义完的 schema 已经知道 relationship 了,可以实现一个对 state 进行方便查询的工具:
const state = {
tweets: {
ids: [2, 1];
},
entities: {
tweets: {
1: { id: 1, body: 'Hello', author: 1 },
2: { id: 2, body: '你好', author: 2 }
},
users: {
1: { id: 1, name: 'Meck', active: true },
2: { id: 2 name: 'Ava', active: false }
}
}
}
const tweet = new Schema('tweets');
const user = new Schema('users');
tweet.define({
author: user
});
const schemas = {
tweet,
user
}
const db = createDatabase(schemas, state.entities);
@connect(
state => ({
// [
// { id: 2, body: '你好', author: { id: 2, name: 'Ava' } },
// { id: 1, body: 'Hello', author: { id: 1, name: 'Meck' } }
// ]
tweets: db.tweets.find({id: { $in: state.tweets.ids }}).includes('author'),
// [
// { id: 1, name: 'Meck', active: true }
// ]
users: db.users.find({active: true}),
// { id: 1, name: 'Meck', active: true }
user: db.users.findOne({id: 1}),
})
)
class Tweets extends Component {
render() {
...
};
}
Exactly what I am thinking. feeble-activerecord
.
@yesmeck 说一下我更具体的想法:
Entity
model, 并自带如下 actions
:create
: 接受一个或一组 data
, 并创建这些 data
.update
: 接受一个或一组 data
, 并更新这些 data
(用新对象完全替换原对象).destroy
: 接受一个或一组 data
, 并删除这些 data
.fetch
: 接受一个或一组 id
, 查询并返回这些数据.Entity
model, 并拥有上述的 actions
,并且:Teacher.associated('Student').action('fetch', ...)
select
方法帮助开发者去获取 model 的 id?我这里没有用到你上面提到的 tweets: db.tweets.find({id: { $in: state.tweets.ids }}).includes('author')
这种方式,是因为我的想法是,这可能增加了使用成本。开发者需要了解一套新的 DSL。如果把这一块查询转换成用 reselect
(或是 feeble
提供的 select 方法) 自己实现查找的逻辑,也许成本会更低。
我感觉 Entity 还比较难抽象的,不同的项目用法可能不一样的。https://github.com/feeblejs/feeble/blob/master/examples/todo/src/models/entity.js 跟https://github.com/feeblejs/hackernews/blob/master/src/models/entity.js
你说的不一样,是指在 todo
里,用到了 create
和 update
actions,在 hackernews
里,用到的是 set
方法吗?
因为我看这两个项目里,state
的 entities
结构都是一样的,都是按照 normalizr
来的,所以只有 actions
定义的不一样吧。
所以我们保持 normalizr
的 state
结构,再定义非常通用的 action
做 CRUD。
两个例子中的分别定义的 create
update
set
action,其实就可以通过 set
达到 create
和 update
的效果,所以提供越简单的 action
就可以应对更多情况。
而且我想了下,关联更新也是可以实现的。
如果真的还有比较复杂的需求没有考虑到,就保留一个类似 set
的 action 去直接可以更新整个 entities
的 state 也是可行的吧。
又认真看了下 redux-orm
,感觉太重了。还是 normalizr
做的事情比较明了。
Hi, 详细地看了代码, 写得很棒, 很像我一位前同事的风格, cool !
请问是否考虑集成类似
normalizr
这样的 lib 呢? JSON API 的返回结果处理起来还是比较麻烦的, 就算用上了normalizr
, 也是要在reducer
里频繁去更新entities
, 也许在feeble
里集成normalizr
或类似的功能可以更方便呢, 而且也能给model
加上has_many
,has_one
的关联关系.