简体   繁体   English

为React / Redux应用程序构造状态

[英]Structuring state for a react/redux app

I'm struggling with structuring a React/Redux application - I'm listing out the problem with options I tried for solutions, but nothing "feels right", so hoping someone here could help me out. 我正在努力构建一个React / Redux应用程序-我列出了我为解决方案尝试的选项的问题,但没有“感觉正确”的东西,因此希望这里的人能为我提供帮助。

Here's a rough idea of my component structure: 这是我的组件结构的大致概念:

<Dashboard>
    <Widget1 dataFetcher=()=>{}>
        <Header>
            <Title> ... </Title>
            <Menu>
                <MenuItem {..cosmeticProps} text="OpenSettings" onClick=handleSettingsOpen>
                <MenuItem {..cosmeticProps} text="Delete" onClick=handleWidgetDelete>
            </Menu>
        </Header>
        <Body>
            <Settings isOpen isValid fields onValidate onAutoComplete.. </Settings>
            { ifError ? ErrorLayout}
            { ifFetching ? FetchingLayout }
            { ifValid ? DataLayout }
        </Body>
    </Widget1>
    ...
</Dashboard>

And here's the state structure (event handlers shown for completeness, not because they're explicitly part of the state) 这是状态结构(显示事件处理程序是为了保持完整性,而不是因为它们显式属于状态)

Dash: {
    widgets: {
        widget1: {
            menu: {
                isOpen: true,

                handleSettingsOpen: ()=>{}
                handleWidgetDelete: ()=>{}
            }
            settings: {
                isOpen: true,
                isValid: true,
                fields: [...],

                onValidate: ()=>{},
                onAutoComplete:()=>{},
                onSave:()=>{}
            }
            data: {
                isFetching: false,
                isError: false,
                items: [],

                fetch: ()=>{}
                parse: ()=>{}
            }
        }
        ...
    }
}

Option 1: 选项1:

Connect the dashboard and let it pass to children as required. 连接仪表板,并根据需要将其传递给子级。 ie,

Connected-dashboard.js 连接 - dashboard.js

stateToProps ()=> { widgets: state.widgets }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete handleSettingsSave ... } //Dashboard would bind these with moduleid while rendering
  • Pro: Everything else can be 'dumb', single source of truth 优点:其他一切都可以是“哑巴”,单一的真理来源
  • Con: Knows too much about state, list of props/dispatches it takes just to pass down makes for ugly reading 缺点:对状态了解太多,只是传下来的道具/调度清单使阅读变得难看

Option 2: 选项2:

Build a 'connected' widget and use that in the dashboard. 构建一个“已连接”的小部件,并在仪表板中使用它。

connected-widget.js 连接-widget.js

stateToProps ()=> { state.widgets[props.widgetid] }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete handleSettingsSave ... }
  • Pro: Dashboard can now be a dumb container, which it is anyway 优点:仪表板现在可以是一个哑容器,无论如何都可以
  • Con: Widget knows too much about state structure? 缺点:Widget对状态结构了解得太多?

Option 3: Build connected versions of individual components and assemble later 选项3:构建各个组件的连接版本并稍后组装

connected-menu.js 连接-menu.js

stateToProps ()=> { state.widgets[props.widgetid].menu }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete }

connected-settings.js 连接-settings.js

stateToProps ()=> { state.widgets[props.widgetid].settings }
dispatchToProps ()=> { handleSave, handleValidate }
  • Pro: Every component gets exactly the slice of state it cares about 优点:每个组件都能准确获取其关心的状态
  • Con: Too many components listening on the state? 缺点:监听状态的组件过多? Also the question of who 'assembles' it. 还有谁“组装”它的问题。

Option 3.1: Restructure state to be: 选项3.1:将状态重构为:

Dashboard: {
    widgets: { ..}
    menu: {widgetid: {isopen ..}}
    settings: {widgetid: {widgetid ..}}
}

(State is flatter with this approach, but not sure if it matters much) (国家采用这种方法比较讨人喜欢,但不确定是否重要)

Overall, this may be naive/obvious, but to me the trade-off seems to be having a parent which either knows too much about the state, or too much about how it's children are put-together. 总体而言,这可能是幼稚的/显而易见的,但对我而言,折衷方案似乎是让父母对州知之甚少,或者对孩子的子女过分了解太多。 How would you approach this? 您将如何处理?

Option 3: Does it make sense for Menu and Settings to know "widgetId"? 选项3:“菜单”和“设置”知道“ widgetId”是否有意义? It seems they would be more reusable if they simply receive the properties menu or settings respectively. 如果它们分别分别接收属性菜单或设置,它们似乎将更可重用。

Option 1: Do you want to update Dashboard stateToProps and dispatchToProps for each widget component supported? 选项1:是否要为支持的每个窗口小部件组件更新Dashboard stateToProps和dispatchToProps?

For these reasons, I like option 2, the connected Widget1. 由于这些原因,我喜欢选项2,即连接的Widget1。

As for state nesting depth, Redux Async Actions has a "Note on Nested Entities" that suggests avoiding deeply nested entities to avoid duplicate data. 至于状态嵌套深度, Redux异步操作具有“关于嵌套实体的说明”,建议避免使用深度嵌套的实体以避免重复数据。

In your example, if any widgets had duplicate menu or settings state object, a normalized state would allow the widgets to share the same state. 在您的示例中,如果任何窗口小部件具有重复的菜单或设置状态对象,则标准化状态将允许窗口小部件共享相同的状态。

Dashboard: {
    widgets: {
        widget1: {menuId:1, settingsId: 1, ...},
        widget2: {menuId:1, settingsId: 1, ...},
    },
    menus: {1: {...}},
    settings: {1: {...}}
}

Actually, with this structure, Menu and Settings only need to know menuId or settingsId, not widgetId. 实际上,通过这种结构,“菜单和设置”仅需要知道menuId或settingsId,而无需知道widgetId。 I still prefer connecting the widget though. 我仍然更喜欢连接小部件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM