Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add option to reload all data #1

Open
Goues opened this issue Jan 2, 2018 · 4 comments
Open

Feature: Add option to reload all data #1

Goues opened this issue Jan 2, 2018 · 4 comments

Comments

@Goues
Copy link

Goues commented Jan 2, 2018

Hi,

we rely heavily on redux-autoloader in our latest project to fetch all data necessary. We would like to implement a "Refresh" button for the user (because otherwise users tend to hit F5 when they see no such button).

However, since we have a lot of data, we have lots of data and they are parametrized by ids (thousands of api endpoint in total), we cannot simple call .refresh() per component. So we would like to have a .refreshAll() method somewhere.

We tried dispatching a reset/load action, but reducer/saga depends on getting the apiCall as payload, which we cannot pass when api calls are parametrized.

Is there a possibility this package might include an internal memory of all instances to expore a refreshAll method? Maybe like a second HOC to wrap the refresh button in.

@nygardk
Copy link
Collaborator

nygardk commented Jan 2, 2018

Hello,

Before implementing such a feature, I would like to understand your use case a bit better. Could you briefly explain what you are trying to achieve (regarding e.g. the ID parametrization) with the redux-autoloader, and how? A code example would be nice!

@Goues
Copy link
Author

Goues commented Jan 2, 2018

Sure.

We have an app with react-router strctured like this:

<Router>
	...
	<Route path="/first/:id" component={FirstWrapper}
	<Route path="/second/:id" component={SecondWrapper}
	...
</Router>

Our wrappers look similar to this:

FirstWrapper = reduxAutoloader({
	reloadOnMount: false,
	cacheExpiresIn: 15e3,
	autoRefreshInterval: 60e3,
	name: props => `first-${props.id || ''}`,
	apiCall: props => Api.getFirst(props.id),
});

Some wrappers are used in a way that needs both data sets (they are wrapped in both ReduxAutoloaders) and we use mapStateToProps to distinguish data. In a single view, we can have up to five different wrappers.

Our app is basically a live data presentation, so this is all good and we really appriciate redux-autoloader because it saved us ton of work.

But now the refresh button is supposed to be global, on top of the app, and it should trigger reload of all mounted wrappers, there lies the problem, because we have no way of triggering .refresh() when button is not a descendant of any redux-autoloader.

<Router>
	...
	<RefreshAll />
	...
	<Route path="/first/:id" component={FirstWrapper}
	<Route path="/second/:id" component={SecondWrapper}
	...
</Router>

We were thinking of multiple different possible solutions:

(0. make react-router refresh the dom - there we failed, since we have too many pure components that block the propagation)

  1. wrap refresh button in all loaders RA(RA(RA(RA(RA(Refresh))))), and merge .refresh() methods into one - very ugly
  2. create a memory store of all active RAs (in mapStateToProps) - the problem is that we cannot access apiCall and name from state and since they are dynamic, we can't "make them up"
  3. create a HOC around RA as a memory that would capture apiCall and name to be used in global refresh (like using context?)

We are currently cost-benefit analysis if we will try to implement it ourselves and submit a PR or it is just a little bit too expensive; or if you think of any other approach to this...

Since someone else might also like this feature, I thought about creating the issue.

@nygardk
Copy link
Collaborator

nygardk commented Jan 2, 2018

Ok, thanks, I understand your problem now better.

I've had a long-term improvement in mind, which would be something like a "loader manifest", which would essentially mean that you could describe all your loaders at the very top level of your application, and then simply refer to the manifest (configuration) in the decorated components. This way the 1-way data binding and data flow would work naturally also in this case. Also, it would make it possible to e.g. (pre-)load data in some cases even if the components are not mounted. That, however, is a huge refactor and would be simply too large feature to solve this problem for you now.

The approach I would suggest now is to make a simple refreshBy saga and an action creator accordingly, which could then be imported from the root level of the library. That would allow you trigger multiple refreshes based e.g. on a regex expression. Usage example:

import { refreshBy } from 'redux-autoloader';
import { connect } from 'react-redux';
...
connect(null, { refreshBy })(YourComponent)
...

Call refreshBy with a function to return true or false:

const shouldLoaderRefresh = ({ name, dataReceivedAt }) =>
  /first\-\d*/.test(loaderName) && (Date.now() - dataReceivedAt) > 5000;

this.props.refreshBy(shouldLoaderRefresh);

... which would refresh all loaders with name first-{number} where data has been last loaded over 5 seconds ago.

If you feel like it, you can implement it yourselves -- depending on your schedule. I could also try to take a look at it, but I'm not sure how soon.

Goues added a commit to Goues/redux-autoloader that referenced this issue Jan 3, 2018
Create collection and withCollection HOCs to allow global reload
Goues added a commit to Goues/redux-autoloader that referenced this issue Jan 3, 2018
Create collection and withCollection HOCs to allow global reload
@Goues
Copy link
Author

Goues commented Jan 3, 2018

I made two commits because the first one had wrong latin caracters in my name.

This might be useful to someone, its as simple as we need it to be, so it might not be ready for merge yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants