Add optional scope parameter when namespacing
mpeyper opened this issue · 2 comments
This is going to get a bit confusing to explain, but I'll do my best.
I've run into an issue where I want to add a namespaced
reducer for a subspaced
component, but the reducer will be a sibling of parent component's reducer, instead of a child.
Component structure:
- App
- Parent (namespace:
'parent'
)- Child (namespace:
'child'
)
- Child (namespace:
- Parent (namespace:
Reducer structure:
- Root
- Parent (namspace: 'parent')
- Child (namespace: 'child')
The reason why the reducer is a sibling and not being combined into the parent's reducer is because the reducers are being added dynamically using the `replaceReducer' which, so far, I have only been able to get reducers to be added to the top level of the store.
The problem is, when an action (e.g. 'SET_VALUE'
) is dispatched from the child, as it breaks out of each subspace, the namespace gets prepended so the final action type is 'parent/child/SET_VALUE'
but the action is ignore by both reducers:
- The parent reducer will successfully remove the
'parent'
namespace but none of it's reducers are listening for the resulting action type ('child/SET_VALUE'
). - The child reducer is looking for an action that starts the
'child\'
so it won't pass on an action that starts with'parent/child'
.
I propose the namespacing functionality be expanded to include an scope
parameter to apply the namespace to. If passed undefined
, if will fallback to the default behaviour of inferring the scope from the nesting hierarchy. I also propose that the same functionality be available anywhere a namespace can be provided (namspace
, subspaced
, SubspaceProvider
)
It could be implemented as:
- a seperate optional parameter
namespace(reducer, 'child', 'parent')
subspaced(mapState, 'child', 'parent')(Component)
<SubspaceProvider mapState={mapState} namespace='child' scope='parent'>
- optionally accepting an object for the `namespace parameter
namespace(reducer, { id: 'child', scope: 'parent' })
subspaced(mapState, { id: 'child', scope: 'parent' })(Component)
<SubspaceProvider mapState={mapState} namespace={{ id: 'child', scope: 'parent' }}>
Another thing to consider what are acceptable values for scope
. I think it should accept:
- a
string
- most basic way to add a scope
namespace(reducer, { id: 'child', scope: 'parent' })
would result in the reducer beingnamespaced
to'parent/child'
- an
array
- can add multiple levels without knowing the
'prefix/...'
convention namespace(reducer, { id: 'child', scope: ['other', 'parent'] })
would result in the reducer beingnamespaced
to'other/parent/child'
- can add multiple levels without knowing the
To enable this, it may be necessary for the subspaced store to carry around it's current namespace
(or scope
?) to be accessed by others when needing to identify the current scope.
If there are no objections to this, I will start working on this soon, or if someone else want's to take a crack, let me know and you can have first dibs.
I've been thinking about this more since writing it up and and I'm not sure if it's actually a good thing to add.
There's something nice and simple about the current method of inferring scope from nesting and introducing explicit scope adds a complexity that is probably not necessary in most cases.
I've decided to put this on hold until I have time to think about it more, or explore alternatives to the dynamic reducer solution that is actually causing the issue here.
I've thought about this and all I need is the current namespace
of the subspaced store to be queryable on the store, e.g. add a fully qualified namespace
value to the store in the redux context
.
With that, I can wrap the problematic reducer in another namespaced
reducer to handle the missing layers.
This should result in hierarchies as follows:
Component structure:
- App
- Parent (namespace:
'parent'
)- Child (namespace:
'child'
)
- Child (namespace:
- Parent (namespace:
Reducer structure:
- Root
- Parent (namespace: 'parent')
- Child (namespace: 'parent/child')