如何组织我的嵌套对象以实现更好的状态管理?
How to organise my nested object for better state management?
这更像是一个组织问题,而不是技术问题。我想我可能会增加复杂性,而更有经验的开发人员会简化它。我缺乏那种经验,需要帮助。
它是一个菜单编辑器,我在其中将我的数据库中的菜单对象加载到状态中:
state = {
user_token: ####,
loadingMenu: true,
menu: {} // menu will be fetched into here
}
对象看起来像这样:
{
menuID: _605c7e1f54bb42972e420619,
brandingImg: "",
specials: "2 for 1 drinks",
langs: ["en", "es"],
items: [
{
id: 0,
type: "menuitem",
isVisible: true,
en: {
name: "sandwich 1",
desc: "Chicken sandwish"
},
es: {
name: "torta 1"
},
price: 10
},
// ...
// ABOUT 25 MORE ITEMS
]
}
UI 允许用户单击并单独更新项目。因此,当他们更改文本时,我发现自己不得不进行奇怪的解构,如下所示:
function reducer(state, action) {
if (action.type === UPDATE_NAME) {
const newMenuItems = state.menu.items.map((oldItem) => {
if (oldItem.id === action.payload.id) {
return { ...oldItem, ["en"]: { ...oldItem["en"], name: action.payload.newName } }
// ["en"] for now, but will be dynamic later
}
return oldItem
})
return { ...state, menu: { ...state.menu, items: newMenuItems } }
}
}
这似乎是个坏主意,因为我要用我的新对象替换整个状态。请问有没有更好的组织方式?
我知道有不变性管理器,我尝试使用immer.js,但运行成了障碍。我需要映射我所有的菜单项以找到一个用户想要编辑(将 ID 与事件目标的 ID 匹配)。我不知道还有什么方法可以直接定位它,也不知道该怎么做:
draft.menu.items[????][lang].name = "Sandwich One"
所以,我再次认为我的组织是错误的,因为不变性管理器可能应该使这变得容易。任何想法,我可以重构什么?
首先,您当前的减速器看起来不错。那个“奇怪的解构”是 very typical。您将 总是 将整个 state
替换为一个新对象,但您处理的是浅拷贝,因此它不是每个级别的全新对象。您没有修改的菜单项仍然是对相同对象的引用。
I need to map through all my menu items to find the one user wants to edit (matching the ID to the event target's ID). I don't know how else to target it directly.
您可以使用 .findIndex()
获取要更新的项目的索引。
const {lang, name, id} = action.payload;
const index = draft.menu.items.findIndex( item => item.id === id);
if ( index ) { // because there could be no match
draft.menu.items[index][lang].name = name;
}
This is more of an organisation than technical question. I think I may be adding complexity, where a more experienced dev would simplify. I lack that experience, and need help.
我对状态结构的建议是将所有项目存储在由 id
键入的字典中。这使得更新项目更容易,因为您不再需要在数组中查找它。
const {lang, name, id} = action.payload;
draft.items[index][lang].name = name;
menu
对象只有一个 ID 数组,而不是 items
属性 的对象数组。当您 select 一个菜单时,您的 select 或者可以用它们的对象替换 ID。
const selectMenu = (state) => {
const menu = state.menu;
return { ...menu, items: menu.items.map((id) => state.items[id]) };
};
这更像是一个组织问题,而不是技术问题。我想我可能会增加复杂性,而更有经验的开发人员会简化它。我缺乏那种经验,需要帮助。
它是一个菜单编辑器,我在其中将我的数据库中的菜单对象加载到状态中:
state = {
user_token: ####,
loadingMenu: true,
menu: {} // menu will be fetched into here
}
对象看起来像这样:
{
menuID: _605c7e1f54bb42972e420619,
brandingImg: "",
specials: "2 for 1 drinks",
langs: ["en", "es"],
items: [
{
id: 0,
type: "menuitem",
isVisible: true,
en: {
name: "sandwich 1",
desc: "Chicken sandwish"
},
es: {
name: "torta 1"
},
price: 10
},
// ...
// ABOUT 25 MORE ITEMS
]
}
UI 允许用户单击并单独更新项目。因此,当他们更改文本时,我发现自己不得不进行奇怪的解构,如下所示:
function reducer(state, action) {
if (action.type === UPDATE_NAME) {
const newMenuItems = state.menu.items.map((oldItem) => {
if (oldItem.id === action.payload.id) {
return { ...oldItem, ["en"]: { ...oldItem["en"], name: action.payload.newName } }
// ["en"] for now, but will be dynamic later
}
return oldItem
})
return { ...state, menu: { ...state.menu, items: newMenuItems } }
}
}
这似乎是个坏主意,因为我要用我的新对象替换整个状态。请问有没有更好的组织方式?
我知道有不变性管理器,我尝试使用immer.js,但运行成了障碍。我需要映射我所有的菜单项以找到一个用户想要编辑(将 ID 与事件目标的 ID 匹配)。我不知道还有什么方法可以直接定位它,也不知道该怎么做:
draft.menu.items[????][lang].name = "Sandwich One"
所以,我再次认为我的组织是错误的,因为不变性管理器可能应该使这变得容易。任何想法,我可以重构什么?
首先,您当前的减速器看起来不错。那个“奇怪的解构”是 very typical。您将 总是 将整个 state
替换为一个新对象,但您处理的是浅拷贝,因此它不是每个级别的全新对象。您没有修改的菜单项仍然是对相同对象的引用。
I need to map through all my menu items to find the one user wants to edit (matching the ID to the event target's ID). I don't know how else to target it directly.
您可以使用 .findIndex()
获取要更新的项目的索引。
const {lang, name, id} = action.payload;
const index = draft.menu.items.findIndex( item => item.id === id);
if ( index ) { // because there could be no match
draft.menu.items[index][lang].name = name;
}
This is more of an organisation than technical question. I think I may be adding complexity, where a more experienced dev would simplify. I lack that experience, and need help.
我对状态结构的建议是将所有项目存储在由 id
键入的字典中。这使得更新项目更容易,因为您不再需要在数组中查找它。
const {lang, name, id} = action.payload;
draft.items[index][lang].name = name;
menu
对象只有一个 ID 数组,而不是 items
属性 的对象数组。当您 select 一个菜单时,您的 select 或者可以用它们的对象替换 ID。
const selectMenu = (state) => {
const menu = state.menu;
return { ...menu, items: menu.items.map((id) => state.items[id]) };
};