HenrikJoreteg / redux-bundler

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

react to url changes #30

Closed ajo2995 closed 6 years ago

ajo2995 commented 6 years ago

I'm writing a meta-search application that uses createAsyncResourceBundle to create bundles for various APIs. Each has a reactX selector based on selectXShouldUpdate and selectQueryString being truthy. If they are it returns a {actionCreator: 'doFetchX'}

In the application, there is an input box for the query string that onChange calls store.doUpdateQuery(newQuery)

How would you recommend getting my bundles to detect and respond to the updated url?

ajo2995 commented 6 years ago

How about adding a custom reducer to the createAsyncResourceBundle? I can make it respond to the URL_UPDATED event. My implementation and a test are here: https://github.com/ajo2995/redux-bundler/commit/e0114282f713237cf0f63340e9dbda7ad7b263ee If this approach makes sense, I can submit a pull request

greggb commented 6 years ago

My impression from the docs and examples is the createAsyncResourceBundle is pretty much just a conduit from your API to your store. Additional reactions to state changes should be done in separate bundles where you would act on the new state.

If you have a doUpdateQuery action could you react to that instead of having the url as the middleware to your secondary action? Alternatively, could you have a reaction in a bundle that checks the new query string from the routeinfo.

I tried a few times to add too much functionality into createAsyncResourceBundle thinking it was like a normal bundle with an async 'helper'. In reality I think think it's probably good that it's somewhat restrictive so you will end up using more of the built in selector patterns.

HenrikJoreteg commented 6 years ago

@ajo2995 hey! Sorry, I'm struggling to understand exactly what you're trying to do. Can you give me some more background?

The thing to realize is the createAsyncBundle just returns an object. You can wrap the resulting reducer to add handling of other action types.

You can attach other action creators/selectors to it then export the result.

const bundle = createAsyncResourceBundle({...opts})

bundle.reactDoSomethingElse = createSelector(...)

export default bundle
ajo2995 commented 6 years ago

My apologies - as a redux newbie I don't even know how to ask the questions yet.

Below is an excerpt from one of my bundles (it fetches blog posts about sorghum!) I'm hitting the infinite loop the docs warned about if I add a reaction to the doUpdateQuery action, but I'm not sure why.

I only want to doFetchSorghumPosts if the query string has changed, I just don't know how to check for that. Also, should I invoke a doClearSorghumPosts action here as well?

Since I'm doing this for several API endpoints (and not just this API), I thought I could extend the reducer to handle the the URL_UPDATED action that is dispatched from the createUrlBundle. I haven't tried it yet.

import {createAsyncResourceBundle, createSelector} from 'redux-bundler'
const API = 'http://localhost:5000/search_api';

const sorghumPosts = createAsyncResourceBundle({
  name: 'sorghumPosts',
  actionBaseType: 'SORGHUM_POSTS',
  getPromise: ({store}) =>
    fetch(`${API}/posts?${store.selectQueryString()}`)
      .then(res => res.json())
});

sorghumPosts.reactSorghumPosts = createSelector(
  'selectSorghumPostsShouldUpdate',
  'selectQueryString',
  (shouldUpdate, queryString) => {
    if (shouldUpdate && queryString) {
      return {actionCreator: 'doFetchSorghumPosts'}
    }
  }
);

// when I add this, infinite loop
sorghumPosts.reactDoUpdateQuery = createSelector(
  'selectQueryString',
  queryString => {
    return {actionCreator: 'doFetchSorghumPosts'}
  }
);
ajo2995 commented 6 years ago

I added a bundle that deploys some BATCH_ACTIONS to clear each of the async resources and update the url