question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

let action creators be passed via the provider

See original GitHub issue

First off, thanks so much for Redux and the amazing tooling and introductory content around it. It’s been awesome to learn how all of the parts fit together.

I’ve been running into an issue while building out my first foray into a React/dux app dealing with action creators. I’m having to use mapDispatch a ton for just passing the same action creators into the props of each of my top-level components (without React Router I end up having around 5 top-level components so far, which I’ve called “containers” following the examples I’ve seen).

And the mapDispatch that I’m writing is often just a super plain object like { loadUser, loadTeam, loadCollection } that maps keys to keys. It’s getting really boilerplate-y to have to keep doing this all the time, when really I’d just like to have all my action creators already bound to my single store.

It would be amazing to be able to pass them into the <Provider>:

<Provider store={store} actions={actions}>
  <App />
</Provider>

And be able to use that inside components as:

componentWillMount() {
  const { actions } = this.props
  actions.loadUser(...)
  actions.loadTeams(...)
  ...
}

From looking through the issues, I found that I’m not the first to suggest this, which means others are grappling with this problem too. Here are a few that mention discuss similar things:

One time when it was brought up, it was discarded because of not wanting to pollute props with all of the actions, since the “clobber likelihood” would be high. I totally get the concern about not wanting to pollute props with tons of actions, but we can avoid that by nesting them in props.actions instead.

Another time, @gaearon mentioned the (important) needs of code splitting. I think that’s definitely a use case to support, but surely we could have a load-later approach that works very similarly to the current mapDispatch that would facilitate loading extra modules, while also making it easy for the main use case?

Curious to hear everyone’s thoughts.

From my initial use of both React and Redux, this would save me boilerplate code, and make it possible for people to write nicer boilerplate-reducing functionality on top of the base libraries.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
ianstormtaylorcommented, Jan 14, 2016

Absolutely! In my project so far, I have 5 container components, all of which need to “connected”. And I haven’t fleshed out the entire thing yet, so that number will grow for sure. For each one I have something along the lines of:

import { loadCollection, loadItem, loadTeam } from '../../actions'

// ...

function loadData(props) {
  const { loadCollection, loadItem, loadTeam } = props
}

// ...

const mapDispatchToProps = {
  loadCollection,
  loadItem,
  loadTeam
}

// ...

const Connected = connect(mapStateToProps, mapDispatchToProps)(Component)

But just 3 actions for a container isn’t a lot; I expect some of them to need 10 or more. And each time I add or change an action, I have to make sure to update it in all of these places, or things break in ways that are sometimes hard to discern.

For example, I forgot to add loadTeam to mapDispatchToProps since it was at the bottom of the file, and then proceeded to be pretty confused since the reference still existed, it just wasn’t to a “bound” action creator, so the error was non-obvious. Of course I could rewrite my import to make that not possible:

import * from '../../actions'

// ... but then I have to make my dispatch mapping more verbose ...

const mapDispatchToProps = {
  loadCollection: actions.loadCollection,
  loadItem: actions.loadItem,
  loadTeam: actions.loadTeam
}

If I actually gained from the configuration I might understand why it needed to be verbose, but for my own developer experience, the ideal for me would be to not have to worry about these kinds of things, and just have any function I exported from * as actions be bound to the store automatically. That way, even though I understand how it’s all wired up, I’d never have to think about the mappings again.

Instead, I’d get a really simple workflow of: write an action creator function, and then go use it in my container components. Ideally as easily as just two things to think about:

export function loadCollection(id) {}

// ...

const { actions } = this.props
actions.loadCollection(id)

If I was able to write this in myself from the top-level, I’d be more than glad. But it seems like the way the system is setup, there’s no way to pass other information into the <Provider> instance, so there’s no way I can do it without creating a singleton, which I want to avoid. (I may be missing a good trick here though—I guess I could attach bound actions to the store.dispatch function if I really wanted to, but that seems real hacky.) I’ve even looked into writing a different <Provider>, but there’s so much logic in it that would need to be duplicated and kept up to date that it would be a huge pain to do.

Let me know if that all makes sense, or if I’m doing something incorrectly. Happy to discuss more. Thanks!

0reactions
ianstormtaylorcommented, Jan 20, 2016

Thanks for the response again. I actually did look at all of the examples before asking.

Both solutions solve the problem partially, but still require that the boilerplate in every file, even though I know I want every “connected” component to have access to all of the bound action creators, just like they have access to the store. Which means not only is it impossible for me remove the boilerplate completely (like with store passing), but it means that it’s impossible to pave over react-redux simply for this case from another library. It has to be done in the end files.

I could create a separate <Provider>, which is pretty lightweight, but it seems like I’d also need implement a separate connect() as well, which has tons of extra logic that I’d need to carefully pass through, or reimplement, so maintaining it would be very non-trivial.

It seems like adding all of the bound action creators onto store.dispatch as properties is the only way to do it from the top-level without having to repeat in each file, so I’ll go with that, even if it feels a bit hackish. Thanks

Read more comments on GitHub >

github_iconTop Results From Across the Web

Writing Logic with Thunks - Redux
The thunk typically closes over any arguments passed to the action creator, so they can be used in the logic: Thunk action creators...
Read more >
action creators not available as functions in props when ...
I imported actions and passed it to connect as follows. I have an action creator called authenticate. When I console.log(this.props), ...
Read more >
Different Ways to Dispatch Actions with Redux - Pluralsight
The bindActionCreators method allows us to dispatch actions from any React component that is not connected to the store as "mapDispatchToPros" ...
Read more >
Understanding Redux Saga: From action creators to sagas
Learn how to use Redux Saga for both simple and complex approaches to implementing async operations with action creators, thunks, and sagas.
Read more >
Idiomatic Redux: Why use action creators? - Mark's Dev Blog
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): If an object is passed, each function inside it is assumed to be ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found