在redux中扩展本质

时间:2018-04-27 12:33:47

标签: javascript redux

我的州看起来像这样:

state = {
  entities: {
    users: {},
    articles: {},
  },
  pagination: {
    articlesByUser: {
      1: { // userId = 1
        isFetching: true,
        ids: [],
      },
      2: { // userId = 2
        isFetching: true,
        ids: [],
      },
    },
  },
}

它适用于包含列表的网页,但文章模型因index路由和get路由而异。

index路线的回复:

$ curl http://api//articles
[{
  "id": 0,
  "user_id": 0,
  "title": "...",
  "short_description": "...",
  ...
}
...
]

get路线的回复:

$ curl http://api//articles/0
{
  "id": 0,
  "user_id": 0,
  "title": "...",
  "body": "...",
  "meta": {...},
  "view_count": 100,
  ...
}

实体不同。 GetModel请求延长IndexModel。因此pagination reducer的状态应如下所示:

pagination: {
  articlesByUser: {
    1: { // userId = 1
      isFetching: true,
      ids: [],
    },
    2: { // userId = 2
      isFetching: true,
      ids: [],
    },
    ...
  },
  articleByArticleId: {
    1: { // articleId = 1
      isFetching: true,
    },
    ...
  }
},

如何在一个和多个文章的句柄加载状态(pagination)中更好地构造isFetching = true reducer?

2 个答案:

答案 0 :(得分:4)

我不知道你对模特的引用是什么意思;我的假设是你在谈论后端的模型,但这并没有真正影响我们,所以我会忽略它们。

使用操作在Redux

中获取和格式化数据

让我们从这句话开始:

  

对于带有列表的页面,它可以正常工作,但是文章模型对于索引路径不同并获得路径

这实际上并不重要!路线之间的数据是不同的(即使它不理想)。

我不知道您当前在哪里处理您的API请求,但我建议将它们放入Redux Actions。使用中间件Redux Thunk,我们可以在我们的动作创建者中拥有功能。动作的一部分工作是为减速器准备数据。这意味着我们可以在操作中使用函数来格式化数据,使其在到达reducer时始终相同。这意味着我们不需要编写许多类似的reducers来处理相同的实体类型,保持DRY并使其更容易维护。

在这种情况下,我会有三个动作:

getAllArticles()

getArticlesById(id)

putArticles(articles)

两个get文章操作将负责发出请求,格式化数据。然后,他们获取此数据并将其传递给putArticlesconst getAllArticles = () => { return (dispatch, getState) => { fetch(yourRoute).then((json) => { const formattedData = json // format/normalize your data here dispatch(putArticles(formattedData)) } } } const getArticleById = (id) => { return (dispatch, getState) => { fetch(yourRoute + id).then((json) => { const formattedData = json // format/normalize your data here dispatch(putArticles(formattedData)) } } } const putArticles = (articles) => { return { type: 'PUT_ARTICLES', payload: {articles} } } 实际调度reducer正在侦听的操作。

你的方法看起来像这样:

state = {
   articles: {
      entities: { /* each article by ID */},
      result: [/* array of ID, primary used for looping */],
      pagination: { /* various pagination methods */ }
   },
  ...
}

规范化数据

我要看的下一步是规范化您的数据。实际上,您已经完成了将实体拆分并将分页信息与实际实体列表分开的相当好的工作。

我会按实体类型打破你的商店。

{{1}}

规范化数据可防止您使用嵌套资源列表(文章>用户>评论,作为示例)。您已经完成了这项工作,使用像Normalizr这样的库对其进行形式化将允许您标准化处理数据的方式。

我会将分页移动到单个实体(用户,文章)中。这样就可以根据类型将事物整齐地分开,并防止出现大量不相关的数据。

作为一个整体深入正常化不属于SO问题的范围,但请看看这两个链接:

Normalizing Redux State Shape

Updating Normalized Data

答案 1 :(得分:2)

  

我认为我的结构是多余的,因为创建了两个简化器来描述一个实体。

您可以使用2个实体:usersarticles来存储所有用户和文章数据,包括来自isFetching的{​​{1}}状态和部分数据:

api/articles

然后,当您成功检索到来自state = { users: { 1: { // userId === 1 name: 'John', // user properties articles: [1, 2, 5], // article ids associated with user } }, articles: { 1: { // articleId === 1 title: '...', isFetching: true, } } } 的文章时,您可以针对文章api/articles/:idSET_ARTICLE_DATA发送id操作,并替换您的部分文章数据减速器(假设您将物品保存在单独的减速器中):

data