HenrikJoreteg / redux-bundler

Compose a Redux store out of smaller bundles of functionality.
https://reduxbundler.com
583 stars 46 forks source link

How to pass args to createAsyncBundle/doFetch{Name} ? #11

Closed huygn closed 6 years ago

huygn commented 6 years ago

I'm trying to achieve below code with createAsyncBundle:

// component.js
this.props.doFetchProjects("foo")

// createAsyncBundle
export default createAsyncResourceBundle({
  name: 'projects',
  getPromise: (...args) => {
    console.log(args); // only receive {dispatch, getState, store}
    return Promise.resolve();
  },
  actionBaseType: 'PROJECTS'
});

Looking at the code for getPromise, we don't seem to pass additional args from doFetchData, am I missing something? Wouldn't it be more convenient for caller if we do smthing like this

const doFetchData = (...extraArgs) => args => {
  ...
  return opts.getPromise(args, ...extraArgs)
}
HenrikJoreteg commented 6 years ago

@huygn you're right, those arguments are not passed through, the assumption is that your state already has whatever other parameters you may need, and that you don't actually have to directly call doFetchProjects from a component at all.

Instead you can add a reactor to the returned bundle that will trigger the fetch under the exact circumstances you want. I added an example of this to the docs just now.

Pasted below for convenience:


Defining the state that should trigger the fetch:

Rather than manually calling doFetch{Name} from a component, you can use a reactor to define the scenarios in which the action should be dispatched. The simplest way is to add it to your bundle after generating it and then using the select{Name}ShouldUpdate as an input selector. The following code would cause the fetch to happen right away and the data to be kept up to date not matter what state the rest of the app was in or URL/Route was being displayed.

const bundle = createAsyncResourceBundle({
  name: 'honeyBadger',
  actionBaseType: 'HONEY_BADGER',
  getPromise: () => {
    // return
  }
})

bundle.reactHoneyBadgerFetch = createSelector(
  'selectHoneyBadgerShouldUpdate',
  shouldUpdate => {
    if (shouldUpdate) {
      return { actionCreator: 'doFetchHoneyBadger' }
    }
  }
)

export default bundle

If instead you wanted to only have the fetch occur on a certain URL or route, or based on other conditions, you can check for that as well by adding and checking for other conditions in your reactor:

const bundle = createAsyncResourceBundle({
  name: 'honeyBadger',
  actionBaseType: 'HONEY_BADGER',
  getPromise: () => {
    // return
  }
})

bundle.reactHoneyBadgerFetch = createSelector(
  'selectHoneyBadgerShouldUpdate',
  'selectPathname',
  (shouldUpdate, pathname) => {
    if (shouldUpdate && pathname === '/honey-badger') {
      return { actionCreator: 'doFetchHoneyBadger' }
    }
  }
)

export default bundle
huygn commented 6 years ago

Thanks for clarify 👍 however I still need to do pass args even with reactors like below (args: [{ sort: 'desc' }]), are there better alternatives for doing this?

bundle.reactHoneyBadgerFetch = createSelector(
  'selectHoneyBadgerShouldUpdate',
  shouldUpdate => {
    if (shouldUpdate) {
      return { actionCreator: 'doFetchHoneyBadger', args: [{ sort: 'desc' }] }
    }
  }
)
HenrikJoreteg commented 6 years ago

@huygn hm.... the entire store is passed so I guess I'm a little confused about what you'd need to pass as an argument that you couldn't already determine based on all the state in the store?

huygn commented 6 years ago

I don't think I want to store such simple api query param in the store.. it feels overkill to me

HenrikJoreteg commented 6 years ago

@huygn I may not be understanding what you mean. Are you saying this value is not dynamic? What determines sort order? Or is it always "desc"? If so, could you apply it to the URL directly instead of passing it as a param?

huygn commented 6 years ago

The sort value in my case depends on the pathname, ie. if path=/ then sort=asc, else its sort=desc everywhere.

btw I figured I could already do the same thing in getPromise using store.selectX, thanks 👍