Redux Store&第三方数据结构

时间:2016-01-07 13:06:41

标签: javascript redux

这是一个关于将redux与第三方库混合的hacky-ish问题。我很清楚这与Redux指南相反。它主要用于讨论和探索 - 我也不想污染他们的Github问题;)

第三方数据 我们使用关系和不可变数据结构模块来存储我们的应用程序数据。简而言之,该模块有点像关系数据库:

  • 公开表
  • 表包含应用程序数据
  • 表有4种方法:get,post,put,delete
  • 数据对象通过索引/主键动态引用

当前的Redux商店结构 由于我们使用Redux,我们最初选择NOT不直接公开表,因为它们包含方法。我们改为公开Table.get();的结果,它返回一个数组对象的数组。

因此我们的减速器通过使用第三方模块“更新状态”。繁重的工作由第三方完成,减速器基本上总是返回Table.get();。 我们的商店看起来像这样:

// the application data (built by relational-json)
var appDB = {
    People: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    },
    Organization: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    },
    Address: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    }
};

// example Reducer
store = createStore(combineReducers({
    Person: function personReducer(state, action) {
        "use strict";

        switch (action.type) {
            case "UPDATE_PERSON_LIST":
            case "UPDATE_PERSON": {
                appDB.Person.put(action.data, "Person");

                return appDB.Person.get();
            }

            case "CREATE_PERSON": {
                appDB.Person.post(action.data, "Person");

                return appDB.Person.get();
            }

            default: {
                return appDB.Person.get();
            }
        }
    },
    Organization: function personReducer(state, action) {
        "use strict";

        switch (action.type) {
            case "UPDATE_ADDRESS_LIST":
            case "UPDATE_ADDRESS": {
                appDB.Organization.put(action.data, "Organization");

                return appDB.Organization.get();
            }

            case "CREATE_ADDRESS": {
                appDB.Organization.post(action.data, "Organization");

                return appDB.Organization.get();
            }

            default: {
                return appDB.Organization.get();
            }
        }
    },
    Address: function personReducer(state, action) {
        "use strict";

        switch (action.type) {
            case "UPDATE_ADDRESS_LIST":
            case "UPDATE_ADDRESS": {
                appDB.Address.put(action.data, "Address");

                return appDB.Address.get();
            }

            case "CREATE_ADDRESS": {
                appDB.Address.post(action.data, "Address");

                return appDB.Address.get();
            }

            default: {
                return appDB.Address.get();
            }
        }
    }
}));


// resulting initial state looks like:
var state = {
    Person: [],
    Organization: [],
    Address: []
};

我们的实际设置如上所示,但有近100个减速器。大多数减速器也非常相同。它们唯一的变化通常是动作的类型和要更新的表。

问题

替代商店结构? 我们正在考虑使用单个reducer来处理第三方数据,并在Store结构中公开“Tables”.get()。我们的商店将有一个更简单的结构(和更少的减速器),看起来像:

// the application data (built by relational-json)
var appDB = {
    People: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    },
    Organization: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    },
    Address: {
        get: function() {},
        post: function() {},
        put: function() {},
        delete: function() {}
    }
};

// example Reducer
store = createStore(combineReducers({
    appDB: function dbReducer(state, action) {
        "use strict";

        switch (action.type) {
            case "UPDATE_PERSON_LIST":
            case "UPDATE_PERSON": {
                appDB.Person.put(action.data, "Person");
                break;
            }

            case "CREATE_PERSON": {
                appDB.Person.post(action.data, "Person");
                break;
            }

            case "UPDATE_ORGANIZATION_LIST":
            case "UPDATE_ORGANIZATION": {
                appDB.Organization.put(action.data, "Organization");
                break;
            }

            case "CREATE_ORGANIZATION": {
                appDB.Organization.post(action.data, "Organization");
                break;
            }

            case "UPDATE_ADDRESS_LIST":
            case "UPDATE_ADDRESS": {
                appDB.Address.put(action.data, "Address");
                break;
            }

            case "CREATE_ADDRESS": {
                appDB.Address.post(action.data, "Address");
                break;
            }

            default: {
                break;
            }
        }

        return Object.keys(appDB).reduce(function(obj, key) {
            obj[key] = appDB[key].get;

            return obj;
        }, {})
    }
}));


// resulting initial state looks like:
var state = {
    appDB: {
        People: function get() {},
        Organization: function get() {},
        Address: function get() {}
    }
};

如果事情发生冲突,apis.apiX将成为上述方法(get)的对象。数据不会直接暴露,必须使用Table.get();

公开

由于我们使用选择器(重新选择)获取数据,因此我们的情况不会导致问题,并且他们知道数据何时发生了变化,即使它们必须经过{{1 }}

我不安/不确定的是Redux预期或完成的任何其他事情。这样的结构会破坏什么吗?

3 个答案:

答案 0 :(得分:3)

这两个选项都与Redux应用程序的工作方式相反,因为您依赖数据突变而不是返回新对象。

虽然从技术上讲你可以使用Redux改变数据我认为在这种情况下它比它的价值更麻烦,因为你并没有真正从Redux中获益。例如,视图无法有效地重绘,因为突变使得无法一眼就看出哪些数据发生了变化。

这就是为什么我建议您不要使用Redux,如果您想将特定的客户端数据库视为事实的来源。如果 it 是真相的来源,Redux只会运作良好。因此,只需直接使用数据库和/或围绕它构建一个更符合您要做的事情的抽象。

答案 1 :(得分:1)

据我了解,Redux并不关心您的商店是什么样的。这是一个抽象。你决定它的外观。您还可以决定操作如何影响Reducer。决定公开方法和/或数据是诚实无关的。只要你坚持你的设计决定,什么都不会打破。我唯一要警惕的是,通过公开方法而不仅仅是数据,你的应用程序状态是否真的是不可变的。

除此之外,知道您的应用程序状态由第三方方法反映意味着您需要开发组件。它可能不是商定的理想例子,但这并不意味着你不能这样做。无论如何,这是我的意见。

答案 2 :(得分:0)

您可能需要查看https://github.com/tommikaikkonen/redux-orm。它提供了一个类似于“模型”的类似于Redux风格的不可变减少器的API。还是新的,但到目前为止似乎非常有用。