Redux-toolkit: Suggestion: namespaced reducers / actions

Created on 7 Dec 2019  路  13Comments  路  Source: reduxjs/redux-toolkit

Hi!

I love redux and I love reducers that filter actions by a namespace
and created my own namespaced-duck-factory library because of that.

It seems that redux-toolkit could make my lib obsolete so I would love to have the option of creating state slice reducers that filter actions by a { meta: 'namespace' } property (for example).

If I understand it correctly it would be a little extension of createSlice() so it also emits namespaced action-creators.

Thanks for reading :)

Most helpful comment

Sorry to comment such an old thread.

As It turns out.
redux-toolkit did indeed made it unneccessary to have preconfigured slices. (I also never really needed the namespacing)
Especially with the entityAdapter and immer out of the box.

So this library gave me so much joy and makes my life easier.

I even managed to introducce it to a context / hooks only codebase for a large client and it works very well so far - we use it to make redux-less redux possible (by using it with useReducer() and some middleware)

So thanks and:

Happy Christmas (well, soon-ish) 馃槃
@phryneas

All 13 comments

Heyo :)

createSlice already namepaces all actions going with the slice - so an increment action on a counter slice would be of type counter/increment.

So if you were to namepace that again, I believe it would be more appropriate to namespace the type one level deeper (creating types like namespace/counter/increment) instead of using meta for that - as reducers usually decide solely by type if they're responsible for handling an action and many established patterns (and interop with many other libraries) break if this rule is ignored.

If you wanted to do that, there's nothing speaking against creating some kind of "higher-order-slice" like this:

function createCounterSlice(namespace: string) {
  return createSlice({
    name: `${namespace}/counter`,
    initialValue: 0,
    reducers: { increment(state){ state++; }  }
  });
}
const clickCounterSlice = createCounterSlice('click');
console.log(clickCounterSlice.action.increment()) // { type: 'click/counter/increment' }

So I think your use case should already be covered - would that work for you?

PS: I love the logo of your library - childhood memories!

Thanks and thanks for reading!

I think my usecase is exotic then, because I use the namespaces to short-circuit some reducers. Meaning, some wont receive the action at all (non-namespace filtering reducers still do)

It seems a accepted pattern that every reducer always receives every action dispatched.

I have to experiment with namespaced actions and think about this.

Thanks you very much for the great work :))

ps: I love the logo too, it was the biggest motivation in creating the lib. :_D

I did a little playing around - if you really want to go for the meta, you can certainly do it using the prepare notation.

I've created a little example here: https://codesandbox.io/s/reverent-allen-w8z2n

But as I said, if you can, stick for the type for the routing, as most things will be much clearer, especially when looking into devTools etc.

In the end, you can make reducers created by createSlice react to actions from other slices using extraReducers.

Wow. You are fast.

I appreciate the effort and learned a lot reading your code!

This is a great christmas present.
Thank you so much.

I will definetly use redux-toolkit from now on!

All the best to you and the team, and have a great next year!

:))

Happy christmas then :tada: :smile:

Sorry to comment such an old thread.

As It turns out.
redux-toolkit did indeed made it unneccessary to have preconfigured slices. (I also never really needed the namespacing)
Especially with the entityAdapter and immer out of the box.

So this library gave me so much joy and makes my life easier.

I even managed to introducce it to a context / hooks only codebase for a large client and it works very well so far - we use it to make redux-less redux possible (by using it with useReducer() and some middleware)

So thanks and:

Happy Christmas (well, soon-ish) 馃槃
@phryneas

@phyneas is there anyway to customize the namespacing?

We're migrating to toolkit from constant names like export const UPDATE_SEARCH = 'UPDATE_SEARCH', which we used in Redux-Saga like actions.UPDATE_SEARCH.

For migration purposes I'm trying to export all the constant names from our newly created slices so we can change as little of the outside code as possible.

The default namespacing results in exporting objects like this though:

{
  search/updateSearch: 'search/updateSearch'
}

Unfortunately the name containing a slash makes it so we can't do actions.NAME anymore. actions[NAME] isn't the end of the world, but customizability would be a nice to have.

No, the namespacing is intentionally hardcoded to nameOfSlice + '/' + reducerName.

I guess I'll be going without then, but I think allowing for the separator to be customized would be great!

There's really not enough benefit for it. For most users and uses of RTK, action types are entirely an implementation detail at this point - the only time you care about them is when you read the history list in the DevTools.

I'm not quite sure what migration process you're doing here, but it seems like you might want to consider doing some string transformations on the keys or something? Hard to say without seeing more details.

Unfortunately the name containing a slash makes it so we can't do actions.NAME anymore. actions[NAME] isn't the end of the world, but customizability would be a nice to have.

I can't really think of a point in sagas where you have to use the type string explicitly.
You should be able to use the action creator instead.

So I'd recommend that instead of yield take(actions.NAME, ...) you do a yield take(slice.action, ...). It's a minimal code change and will also help you with type inference going forward.

As for your map object. There is no rule that key and value have to match.

So if you want to prevent changes in other places at all cost (which I wouldn't, see above), why not just do

{
  OLD_NAME: 'new/name'
}

@phryneas oh, if I can use slice.action then forget it, that's way better! I hadn't though Redux Saga supported passing action creators.

And yeah it occurred to me that key/value need not be the same but that's some mental overhead when debugging. Thanks so much for taking the time to let me know what I was doing was unnecessary.

I just wanted to follow up now that I've had some more time to implement and conceptualize; it's absolutely the right choice to not allow customization of namespaces in createSlice.

We opted for a combination of createReducer and createAction instead. It makes sense to keep createSlice the most simple and opinionated tool in the toolkit. Thanks again @markerikson and @phryneas.

Was this page helpful?
0 / 5 - 0 ratings