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.
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:
Connect the dashboard and let it pass to children as required. ie,
Connected-dashboard.js
stateToProps ()=> { widgets: state.widgets }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete handleSettingsSave ... } //Dashboard would bind these with moduleid while rendering
Option 2:
Build a 'connected' widget and use that in the dashboard.
connected-widget.js
stateToProps ()=> { state.widgets[props.widgetid] }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete handleSettingsSave ... }
Option 3: Build connected versions of individual components and assemble later
connected-menu.js
stateToProps ()=> { state.widgets[props.widgetid].menu }
dispatchToProps ()=> { handleSettingsOpen, handleWidgetDelete }
connected-settings.js
stateToProps ()=> { state.widgets[props.widgetid].settings }
dispatchToProps ()=> { handleSave, handleValidate }
Option 3.1: Restructure state to be:
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"? 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?
For these reasons, I like option 2, the connected 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.
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. I still prefer connecting the widget though.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.