Redux商店&第三方数据结构

Redux Store & third party data structures

本文关键字:第三方 数据结构 amp 商店 Redux      更新时间:2023-09-26

这是一个关于将redux与第三方库混合的棘手问题。我很清楚这与Redux指南相悖。这主要是为了讨论和探索——我也不想污染他们的Github问题;)

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

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

当前Redux商店结构由于我们使用Redux,我们最初选择不直接公开表,因为它们包含方法。相反,我们公开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(); 进行公开

这在我们的案例中不会造成问题,因为我们通过使用选择器(reselect)来获取数据,并且他们知道数据何时发生了变化,即使他们必须通过Table.get();

我感到不安/不确定的是Redux所期望或做的任何其他事情。这样的结构会破坏东西吗?

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

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

这就是为什么如果你想把一个特定的客户端数据库作为真相的来源,我建议你不要使用Redux。Redux只有在是真理的来源时才有效。因此,只需直接使用DB和/或围绕它构建一个更适合您尝试做的抽象。

据我所知,Redux并不在乎你的商店是什么样子的。这是一个抽象概念。你决定它的外观。您还可以决定操作如何通过减速器影响它。老实说,决定公开方法和/或数据是无关紧要的。只要你坚持你的设计决策,就没有什么能打破。我唯一要注意的是,通过公开方法而不仅仅是数据,您的应用程序状态是否真的是不可变的。

除此之外,知道您的应用程序状态由第三方方法反映意味着您在开发组件时要考虑到这一点。这可能不是一个理想的例子,但这并不意味着你不能做到。这是我的观点。

您可能需要研究redux-orm。它提供了一个类似于"模型"的API,围绕着Redux风格的不可变减速器。仍然是新的,但到目前为止似乎很有用。