5

自从我开始阅读 SPA 以来,最让我困惑的是如何处理应用程序状态。

尽管我在 Redux 中找到了我一直在寻找的大部分答案,但仍有几件事我不确定如何处理。

其中一件事是如何指定我想在我的应用程序中使用的“实体”的形状。在我过去使用过的其他框架中,我看到大量使用 ES2015 类来实现此目的,但在 React/Redux 应用程序中,对象字面量是迄今为止表达应用程序状态的首选方式。昨晚我在 redux 文档中阅读了有关规范化数据的内容,虽然它给了我关于如何处理深度嵌套对象的好主意,但它让我觉得缺少一些东西,那就是如何在一个单一的尽可能清楚地发现应用程序状态的结构/形状是什么。

以上述文章中使用的样本数据为例:

{
    posts : {
        byId : {
            "post1" : {
                id : "post1",
                author : "user1",
                body : "......",
                comments : ["comment1", "comment2"]    
            },
            "post2" : {
                id : "post2",
                author : "user2",
                body : "......",
                comments : ["comment3", "comment4", "comment5"]    
            }
        }
        allIds : ["post1", "post2"]
    },
    comments : {
        byId : {
            "comment1" : {
                id : "comment1",
                author : "user2",
                comment : ".....",
            },
            "comment2" : {
                id : "comment2",
                author : "user3",
                comment : ".....",
            },
            "comment3" : {
                id : "comment3",
                author : "user3",
                comment : ".....",
            },
            "comment4" : {
                id : "comment4",
                author : "user1",
                comment : ".....",
            },
            "comment5" : {
                id : "comment5",
                author : "user3",
                comment : ".....",
            },
        },
        allIds : ["comment1", "comment2", "comment3", "commment4", "comment5"]
    },
    users : {
        byId : {
            "user1" : {
                username : "user1",
                name : "User 1",
            }
            "user2" : {
                username : "user2",
                name : "User 2",
            }
            "user3" : {
                username : "user3",
                name : "User 3",
            }
        },
        allIds : ["user1", "user2", "user3"]
    }
}

你会如何表达这些数据的形状?像这样?

{
    posts : {

    },
    comments : {

    },
    users : {

    }
}

也许:

{
    posts : {
        byId : {

        }
        allIds : []
    },
    comments : {
        byId : {

        }
        allIds : []
    },
    users : {
       byId : {

        }
        allIds : []
    }
}

好吧,这并没有告诉我每个对象内部的对象的实际形状,byId而这正是自从我开始研究一点 Redux 以来一直困扰我的问题。

所以问题是,有没有什么方法/惯例可以让我以最清晰的方式表达形状,特别是构成商店将要管理的状态的对象的每个属性?

4

3 回答 3

3

作为“Structuring Reducers”文档部分的作者,这是因为数据项的实际内容完全取决于您和您的应用程序。这实际上更像是一个通用的 Javascript “我如何表达类型?” 问题。有像 TypeScript 和 Flow 这样的静态类型系统;基于文档的方法,如 JSDoc;运行时方法,例如 React PropTypes 库或 tcomb;和基于模式的方法,如 JSON-Schema。这些方法中的任何一种都是在应用程序中记录和执行数据类型定义的有效方法。

规范化只是一种组织这些值的方法,无论您选择如何定义它们的内容是什么。

于 2017-06-28T15:42:03.633 回答
2

假设您使用的是纯 JS,最简单的方法是使用propTypes.shape

 // An object taking on a particular shape
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),

如果您使用的是 propTypes,我建议以这种方式声明所有对象的形状。

好处:

  1. 您的对象形状是明确的。
  2. 当意外的物体形状四处传递时,您会很快收到警报。
  3. 您可以在Webstorm等现代编辑器中获得增强的自动完成支持。
  4. 由于对象形状只是一个对象,您可以集中声明以避免重复自己。
  5. 您无需迁移到 TypeScript、Flow 等即可在运行时拥有显式类型和基本类型安全性。
于 2017-06-29T13:17:56.427 回答
0

Redux 的好处是您可以非常清晰地分离状态的关注点。每个reducer都负责自己的状态部分,如果你最终通过添加更多数据/逻辑来扩展reducer,你只需要在更小的reducer中分解那个reducer。

一般来说,我会避免在reducer 内的大数据集合中使用数组。数组很酷,并为您提供了许多不错的功能(排序、过滤、归约等),但循环遍历它们很昂贵。如果可以,请使用对象并使用 ID 来识别您的对象,这样您就可以使用最快的方式访问该对象。

使用您的示例,我将使用第一种方法:

{
  posts: {
    1554: {},
    1557: {}
  },
  comments: {},
  users: {},
}

如果您需要跟踪数组中的列表对象,您只需在您的帖子减速器中创建两个新的减速器:

// postsReducer.js
import byId from 'postsByIdReducer'
import allIds from 'allIdsReducer'

export default combineReducers({
  byId,
  allIds
})

所以你的状态会像

{
  posts: {
    byIds: {},
    allIds: []
  }
}
于 2017-06-28T14:37:42.570 回答