在 redux-orm 模式实例上使用 reducer 方法

Use reducer method on redux-orm schema instance

我正在使用 redux-orm 创建规范化和非规范化模型。我发现当我创建一个模式时,我得到了错误:

Uncaught Error: Schema has been renamed to ORM. Please import ORM instead of Schema from Redux-ORM

默认安装的0.90-rc1和`0.8.4

我都用过

当 运行 此代码时:

import { Schema } from 'redux-orm'
import Todo from './Todo'
import Tag from './Tag'
import User from './User'

const schema = new Schema()
schema.register(Todo, Tag, User)

export default schema

但是我发现 redux-orm 中模式的文档和代码仍然存在。

如果我从

切换
import { Schema } from 'redux-orm'

import { ORM as Schema } from 'redux-orm'

代码有效,但我收到一条错误消息,指出此处未定义 reducer 方法:

import { schema } from './models' 

console.log(schema)

const rootReducer = combineReducers({
  orm: schema.reducer(),
  selectedUserId: selectedUserIdReducer
})

大部分代码基于primer here

我的模型是这样的:

ValidatingModel.js

import { PropTypes } from 'react'
import { Model } from 'redux-orm'
import propTypesMixin from 'redux-orm-proptypes'

const ValidatingModel = propTypesMixin(Model)

export default ValidatingModel

Todo.js

import { fk, many } from 'redux-orm'
import { PropTypes } from 'react'
import ValidatingModel from './ValidatingModel'
import User from './User'
import Tag from './Tag'
import { CREATE_TODO, MARK_DONE, DELETE_TODO, ADD_TAG_TO_TODO, REMOVE_TAG_FROM_TODO } from '../actionTypes'
export default class Todo extends ValidatingModel {
  static reducer (state, action, Todo, session) {
    const { payload, type } = action
    switch (type) {
      case CREATE_TODO:
        const tagIds = payload.tags.split(',').map(str => str.trim())
        const props = Object.assign({}, payload, { tags: tagIds })
        Todo.create(props)
        break
      case MARK_DONE:
        Todo.withId(payload).set({ 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.propTypes = {
  id: PropTypes.number,
  text: PropTypes.string.isRequired,
  done: PropTypes.bool.isRequired,
  user: PropTypes.oneOf([PropTypes.instanceOf(User), PropTypes.number]),
  tags: PropTypes.arrayOf(PropTypes.oneOf([
    PropTypes.number,
    PropTypes.instanceOf(Tag)
  ]))
}

Todo.defaultProps = {
  done: false
}

Todo.fields = {
  user: fk('User', 'todos'),
  tags: many('Tag', 'todos')
}

Tag.js

import ValidatingModel from './ValidatingModel'
import { PropTypes } from 'react'
import { CREATE_TODO, ADD_TAG_TO_TODO } from '../actionTypes'

export default class Tag extends ValidatingModel {
  static reducer (state, action, Tag, session) {
    const { payload, type } = action
    switch (type) {
      case CREATE_TODO:
        const tags = payload.tags.split(',')
        const trimmed = tags.map(name => name.trim())
        trimmed.forEach(name => Tag.create(name))
        break
      case ADD_TAG_TO_TODO:
        if (!Tag.filter({ name: payload.tag }).exists()) {
          Tag.create({ name: payload.tag })
        }
        break
    }
  }
}

Tag.modelName = 'Tag'

Tag.backend = {
  idAttribute: 'name'
}

Tag.propTypes = {
  name: PropTypes.string
}

这是User模型,我在看到@squiroid原答案后添加了一个no-op reducer

import ValidatingModel from './ValidatingModel'
import { PropTypes } from 'react'

export default class User extends ValidatingModel {
  static reducer (state, action, User, session) {
    return state
  }
}

User.modelName = 'User'

User.propTypes = {
  id: PropTypes.number,
  name: PropTypes.string
}

据我从您的代码中可以看出,您似乎错过了在模型中定义减速器的代码 (TODO, TAG, USER)

根据文档 here

您需要在每个模型中有一个静态方法。

static reducer(state, action, Tag) static reducer(state, action, TODO) static reducer(state, action, USER)

首先,我需要使用 ORM 而不是 Schema。所以我将 Schema 的导入更改为:

import { ORM as Schema } from 'redux-orm'

其次,我不得不将减速器的签名更改为:

static reducer (action, SessionSpecificModel, session)

the redux-orm docs have been updated, the second argument is not the state of the reducer but a session specific model.

来自文档中的签名:

static reducer (state, action, Model, session)

第三,我不得不更改 todo 中的代码以使用 toRefArraytoModelArray 以便在 [=24= 的列表中调用 map ] 和 Tag 个实例:

return orm.Todo.filter({ user: userId }).toModelArray().map(todo => {
  const obj = Object.assign({}, todo.ref)
  obj.tags = todo.tags.toRefArray().map(tag => tag.name)
  return obj
})

第四,我必须从 session 实例中解析 Model class。

我仍然发现创建 Todo 的问题,其中:

session.Todo.create(props)

抛出 error:

提供给 Todo.create 的道具 tags[0] 无效。

当使用 props 调用时:

{
 "text":"Test my data",
 "tags":[
   "urgent",
   "personal"
  ],
  "user":0
}

验证似乎干扰了模型的创建。创建标签时,将 PropTypes 指定为:

const { string, number, arrayOf oneOfType, instanceOf } = PropTypes
Todo.propTypes = {
   text: string,
   user: oneOfType([
      number,
      instanceOf(User)
   ]),
   tags: oneOfType([
      arrayOf(string),
      arrayOf(
        instanceOf(Tag)
      )
   ])
}

在 redux-orm 中引导或创建模型时,您可以将模型的 id 或实例提供给相关 属性。因此,确保两者都被 Model.

接受是必要的

要进一步阅读有关从 redux-orm 0.8 迁移到 0.9 的信息,请查看开发人员的指南: https://github.com/tommikaikkonen/redux-orm/wiki/0.9-Migration-Guide

github repo 上的 README 落后了,但令人惊讶的是 npm README 已更新为 0.9,尽管 0.9 的 PR 尚未合并。 https://www.npmjs.com/package/redux-orm