如何在React / Redux应用程序中指定状态的形状?

时间:2017-06-28 03:29:11

标签: reactjs redux state-management

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

虽然我在Redux中找到了我所寻找的大部分答案,但仍有一些我不确定如何处理的事情。

其中一个方面是如何指定我想在我的应用中使用的“实体”的形状。在我过去使用的其他框架中,我已经看到为此目的广泛使用ES2015类,但在React / Redux应用程序中,对象文字是目前表达应用程序状态的首选方式。 昨晚我正在阅读关于normalizing data in the redux docs的内容,虽然它给了我关于如何处理深层嵌套对象的好主意,但它让我觉得有些东西丢失了,那就是如何在一个地方指定并尽可能清楚应用状态的结构/形状。

获取上述文章中使用的样本数据:

{
    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以来一直困扰着我的事情。

所以问题是,是否有任何方式/通用实践可以让我以最清晰的方式表达形状,特别是构成商店将要管理的状态的对象的每个属性?

3 个答案:

答案 0 :(得分:3)

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

标准化只是组织这些值的方法,无论您如何选择定义其内容。

答案 1 :(得分: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等,以便在运行时具有明确的类型和基本类型安全性。

答案 2 :(得分:0)

Redux的好处在于你有一个非常明确的分离关注的状态。每个减速器都由其自身的一部分负责,如果您最终通过添加更多数据/逻辑来扩展减速器,您只需要将减速器分解为更小的减速器。

通常,我会避免在reducer中的大数据集合中使用数组。数组非常酷并且为您提供了许多不错的功能(排序,过滤,减少等),但循环使用它们昂贵。如果可以,请使用对象并使用ID来标识对象,这样您就可以使用最快的方式访问对象。

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

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

如果您需要跟踪列表对象 数组,您只需在帖子 reducer中创建两个新的reducer:< / p>

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

export default combineReducers({
  byId,
  allIds
})

所以你的状态就像

{
  posts: {
    byIds: {},
    allIds: []
  }
}