Comments (13)
Hey, good question. remotely
will be called if locally
returns undefined
(or it doesn't return anything). So if your store keeps track of the current page you could do something like this:
@.fetch
id: 'all-people'
locally: () ->
return @state.people if @state.meta.currentPage == pageNumber
remotely: () ->
PeopleAPI.findPeople(params)
I'm wondering, would it be worth caching pages of users locally? Something like this
@PeopleStore = Marty.createStore
getInitialState: ->
people: []
meta:
totalPages: 0
pagesLoaded: {}
findPeople: (params) ->
pageNumber = if params and params.pageNumber then params.pageNumber else 1
@.fetch
id: 'page-#{pageNumber}'
locally: () ->
if @state.meta.pagesLoaded[pageNumber]
return _.where(@state.people, pageNumber: pageNumber)
remotely: () ->
PeopleAPI.findPeople(params)
receivePeople: (response) ->
@state.totalPages = response.meta.totalPages
@state.pagesLoaded[response.meta.page] = true
@state.people = @state.people.concat(response.people)
@.hasChanged()
from marty.
Thanks @jhollingworth for your response, it totally make sense, now I've got it working! :)
from marty.
So in this example, page change invalidated the catch which is convenient.
What if you have a master list that you always want to reflect the latest snapshot of the database? For instance, if I have a view where i always want to invalidate the local? Nothing is changing with the meta state of the app, only the data is being updated.
I'm running into an infinite loop issue because I'm using the state mixin, which executes the getAll store method every time theres a change to the store (which is every time that I call getAll). Is the only solution to just not use the state mixin, and to not subscribe to changes? How could I use the fetch state (pending, etc) in the view in that case?
var OrderStateMixin = Marty.createStateMixin({
listenTo: OrderStore,
getState: function() { return { orders: OrderStore.getAllOrders({ cache: false });
});
var OrderStore = Marty.createStore({
getAllOrders: function(options) {
options = options || { cache: true };
return this.fetch({
id: 'GET_ALL_ORDERS',
locally: function() {
return !options.cache ? this.state.orders : undefined;
},
remotely: function() {
return OrderApi.getAllOrders();
}
});
},
receiveOrders: function(orders) {
this.setState({ orders: orders });
}
});
from marty.
Hi @nhagen
Maybe you can use a state attribute of the store to control that, something like:
var OrderStore = Marty.createStore({
getAllOrders: function(options) {
options = options || { cache: false };
this.state.cache = options.cache;
return this.fetch({
id: 'GET_ALL_ORDERS',
locally: function() {
return this.state.cache ? this.state.orders : undefined;
},
remotely: function() {
return OrderApi.getAllOrders();
}
});
},
receiveOrders: function(orders) {
this.setState({ orders: orders, cache: true });
}
});
So every time it fetches for the first time locally it returns undefined forcing fetching remotely, which sets then sets cache to true so the second local fetch will return the state projects. The next call to projects from the mixin will pass cache equal false starting all over again.
Hope this helps :)
from marty.
@bigardone the problem from @nhagen (and currently for me too) is e.g. a rendering with pending and done output.
When you fetch remotely, render will be called with promise status pending, but before every render the getState
will be called again with cache: false
, which ends in an infinite loop.
The only hacky solution is a cache timeout after some seconds. Or am I missing something?
from marty.
The fetch API is designed for the case when you expect some state to be there but its not there right now. If I understand you correctly, you have some state in the store but its stale. If thats the case, I think you should have an action which is responsible for refreshing the state.
e.g.
var OrderActionCreators = Marty.createActionCreators({
refreshOrders: Constants.REFRESH_ORDERS(function () {
OrderAPI.updateAllOrders();
});
})
setInterval(OrderActionCreators.refreshOrders, 100);
from marty.
Yup, that worked great. I call OrderActionCreators.refreshOrders
on getInitialState
in my store, and in OrderActionCreators.refreshOrders
I have
var timeout;
var OrderAction ...
refreshOrders: ...
clearTimeout(timeout);
timeout = setTimeout(this.refreshOrders, 10000)
which sort of resets the timeout loop every time the user chooses to manually refresh. An interval of course would work just as well.
Having the refresh as an action ads a lot of flexibility. You can have user-level auto-refresh based on their user settings, or you can have a manual refresh button, or you can do a combination of the two. I think this is better UX and is less bug prone than having refreshes happen behind the scenes and outside of the normal Flux flow.
from marty.
I have to revive this issue, because I'm not sure if I use fetch
correctly at the moment.
I love how marty containers handle all the fetch/loading code for me, so I want to use it. Anyway, when I'm navigating my app without page reloads I have to fetch the data remotely when a page opens. With fetch
this is not possible, because it will be cached once and forever.
Right now I have a parent component in which I invalidate the cache so it's fetched remotely, again. My problem is, I have no idea how to do this in the container using the store itself.
What I want to do is this:
Marty.createContainer(ProfileShow, {
componentWillMount(){
UserStore.invalidateCache();
},
listenTo: UserStore,
fetch : {
user() {
return UserStore.for(this).getUser();
}
},
pending() {
return <div className='pending'>Loading user data...</div>;
},
failed(errors) {
return <div className='error'>Failed to load user. {errors}</div>;
}
});
The code above does not work as intended, because the componentWillMount
method is called after the first fetch is made. Is there any other hook I can use to invalidate the cache before the fetch is done initially? Setting timeouts to invalidate the cache does not feel good, too.
It's a bit cumbersome to wrap everything with components so that I can force a remote fetch.
Thanks a lot for your help!
from marty.
BTW, in general you should not be directly mutating stores except via actions.
Why not just invalidate the cache when your component unmounts? Alternatively, keep track of whether or not this is the first fetch you've done, and invalidate the cache if so.
from marty.
An additional thing is that I've been using a strategy like the one proposed here: #80 (comment) where I force a remote fetch on component load, without explicitly invalidating what's currently in the cache.
from marty.
You are right. I directly mutated the store to simplify the example.
Anyway, on unmount will work in my case. Thanks! It will not work if the component remains and another one using this store is mounted. But this would be acceptable I think, if it ever happens...
I will look into your comment, too. I always ended in some sort of endless loop because the fetch methods gets called multiple times.
from marty.
I don't think the on-mount behavior you have is particularly well defined when you have multiple components accessing the same data either.
To get refresh working without infinite loops, you have to write it like:
getData(id) {
return this.fetchData(id, function () {
return this.state[id];
});
}
refreshData(id) {
let refresh = true;
return this.fetchData(id, function () {
if (refresh) {
refresh = false;
return undefined;
} else {
return this.state[id];
}
});
}
fetchData(id, locally) {
return this.fetch({
id,
locally,
remotely() {
return DataQueries.getData(id);
}
})
}
from marty.
Well, I think when I use multiple components on a single page requesting the same data over and over again, my app structure is questionable anyway :)
Well, I did it sort of the way you describe above in the first place, but without fetch
, locally
and remotely
because it added so much additional code ;)
I think I know what to do now, and how to add a refresh functionality. Thanks for your help!
from marty.
Related Issues (20)
- Cannot read property '0' of undefined HOT 2
- Does the GitHub fetch library have to be used in HTTP Sources? HOT 3
- Server side fetches do not calculate content-length header HOT 6
- webpack, babel, karma & marty v0.9.17 problem with requiring react HOT 5
- I can't get Marty session storage to persist between tabs or Marty localStorage to work at all! HOT 8
- Running headless tests with PhantomJS as a 'browser' fails HOT 2
- Return error in locally HOT 5
- Optionally require `es6-promise` and `isomorphic-fetch` HOT 2
- not properly escaping "</script>" in app state dehydration HOT 2
- test-utils component specs throw on undefined `document` element HOT 10
- Performance Implications? HOT 2
- React.createElement called on each store change
- Consider reversing order in this.handlers HOT 4
- Application.renderToString performance HOT 5
- Application.RenderToString hangs when fetch result returns the value false. HOT 1
- no-iisue HOT 1
- Fetch state in a container based on the result of another fetch HOT 1
- Support React 0.14.0 HOT 6
- Update Docs HOT 2
- How awesome this project has been! HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from marty.