-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Async data and Flux stores #530
Comments
One action. There must be one action for async flow. This action dispathes two events - first, REQUEST_TODO fired before send, and other, REQUEST_TODO_COMPLETED - after send. (ok, you should handle error somehow also, e.x. REQUEST_TODO_FAILED) Please take a look at Fluxxor tutorial about async Flux, it's very simple and clear. PS. It this question related to react-router ? |
Yes sorry, I mixed up when I wrote this issue. There is only one action, which triggers two events as you said. This is related to react-router, as I want the router to display the react component once he receives all the data from the server (ie. when REQUEST_TODO_COMPLETED is emitted). In the example linked, it uses callbacks, waiting that all promises are fulfilled before rendering the component with the filled data prop. I am wondering how I can apply this method to the Flux architecture, knowing that it deals with events... |
Here's how I do it: // Usage example:
//
// willTransitionTo(transition, params) {
// transition.wait(
// observeStore(
// DraftStore,
// s => s.isLoaded()
// ).then(() => {
// if (DraftStore.isMissingTitle()) {
// transition.redirect('composeDraft', params);
// }
// })
// );
// }
'use strict';
var Promise = require('bluebird');
function observeStore(store, predicate) {
var performCheck;
return new Promise(resolve => {
performCheck = () => {
if (predicate.call(null, store)) {
resolve();
}
};
store.addChangeListener(performCheck);
performCheck();
}).finally(() => {
store.removeChangeListener(performCheck);
});
}
module.exports = observeStore; You can do |
I find flux interesting in some cases, and totally nuts in others (like using it to get the router to render), but if you think its important, I think it'd look something like this: var DataStore = require('DataStore');
var RouterStore = require('RouterStore');
RouteActionCreators = {
routeChange (Handler, state) {
// 2. web api util fetches data
DataUtil.fetchData(state.params);
// 3. dispatcher dispatches action
dispatchAction('ROUTE_CHANGE', {Handler, state});
// 4. RouterStore listens for 'ROUTE_CHANGE' and stores
// `Handler` and `state` for subscribers
// 5. DataUtil dispatches 'DATA_LOADED' and then `DataStore`
// grabs the data from that payload
}
};
// 6. we have subscribed here to the data store, to render when
// the data changes
DataStore.addChangeListener(render);
function render() {
// 7. get the handler off the RouterStore
var { Handler } = RouterStore.getState();
// 8. and the data
var data = DataStore.getState();
// 9. render
React.render(<Handler data={data}/>, document.body);
}
Router.run(routes, (Handler, state) => {
// 1. route changes call an action with payload
RouterActionCreators.routeChange(Handler, state);
}); |
Just wanted to say thanks for this, it helped me with integrating fluxxor into my app with react router. for anyone else: var React = require('react');
var Router = require('react-router');
var routes = require('./routes');
var flux = require('./flux');
var appStore = flux.store('AppStore');
var viewRoot = document.getElementById('content');
var initialState = JSON.parse(document.getElementById('state').innerHTML);
appStore.on('change', function () {
var Handler = appStore.state.handler;
var data = appStore.state.data;
React.render(<Handler state={data}/>, viewRoot);
});
Router.run(routes, Router.HistoryLocation, function (Handler, state) {
if (initialState.isInitial) {
delete initialState.isInitial;
flux.actions.hydrate({ initialState: initialState, handler: Handler, state: state});
} else {
flux.actions.request({ state: state, handler: Handler});
}
}); |
@gaearon thanks for this technique. I have a login with an async call to fetch user data with a token (which might be stored locally). I'm using the static willTransitionTo(transition, params, query, callback) {
if (!LoginStore.isLoggedIn()) {
//store next path in RouterStore for redirecting after authentication
let transitionPath = transition.path;
RouterActionCreators.storeRouterTransitionPath(transitionPath);
//check if still waiting for a user data request
observeStore(LoginStore, s => !s.isRequestingUserData())
.then(() => {
if (!LoginStore.isLoggedIn()) {
transition.redirect('/login');
}
})
.finally(callback);
}else{
callback();
}
} |
I am using the Flux architecture. Each time I visit a page, the page requests data from a Store, but as the action is created (eg. REQUEST_TODO), there is no explicit callback triggered, but another action will be created once the request is completed (eg. REQUEST_TODO_COMPLETED).
I am trying to implement something similar to (https://github.com/rackt/react-router/blob/master/docs/api/run.md or https://github.com/rackt/react-router/blob/master/examples/async-data/app.js), I get the principles, but I struggle adapting with the concept of actions. Should I consider my actions differently, by adding some sort of callback, but this would make the dataflow more complex?
I am just starting, so this is likely I have missed something.
Thanks
The text was updated successfully, but these errors were encountered: