Skip to content

Instantly share code, notes, and snippets.

@Ambroos
Created April 20, 2015 08:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Ambroos/7a22c22f7c745d1430a3 to your computer and use it in GitHub Desktop.
Save Ambroos/7a22c22f7c745d1430a3 to your computer and use it in GitHub Desktop.
Async data fetching sample with React-Router and Fluxible
fluxibleApp.rehydrate(dehydratedState, (err, context) => {
if (err) {
debug('Rehydrate error', err);
throw err;
}
let mountNode = document.getElementById('app');
let firstRender = true;
Router.run(fluxibleApp.getComponent(), Router.HistoryLocation, (Handler, state) => {
// Render
React.render(
<Handler context={context.getComponentContext()} />,
mountNode,
() => {
debug('React rendered');
}
);
debug('Starting navigateAction from Router.run');
context.executeAction(clientNavigateAction, state).then((result) => {
debug('navigateAction from Router.run complete', result);
});
});
});
import loadData from '../actions/loadData';
// Other imports
class MyRouteHandler extends React.Component { ... }
let Handler = connectToStores(MyRouteHandler, ...);
Handler.navigateActions = { // Where the magic happens
client: [ loadData ],
server: [ loadData ]
};
export default Handler;
// NPM
import isNode from 'detect-node';
import filter from 'lodash/collection/filter';
import reduce from 'lodash/collection/reduce';
import isArray from 'lodash/lang/isArray';
// Debug
import debugCore from 'debug';
let debug = debugCore('viva:action:Navigate');
export default function navigateAction(actionContext, routerState) {
debug('Router state', routerState);
let routesWithActions = filter(routerState.routes, (route) => route.handler.navigateActions);
debug('routesWithActions', routesWithActions);
let actions = reduce(routesWithActions, (result, route) => {
// Decide if we are a server or a client and pick the right actions.
let actionSet = isNode ? route.handler.navigateActions.server : route.handler.navigateActions.client;
if (actionSet) {
if (!isArray(actionSet)) {
actionSet = [actionSet];
}
Array.prototype.push.apply(result, actionSet);
return result;
}
}, []);
// Build array of Promises. This sets off all actions.
let promises = actions.map((action) => {
return actionContext.executeAction(action, routerState);
});
return Promise.all(promises);
}
/**
* Fluxible Application
*/
server.use((req, res) => {
// Create the context with app config.
let context = fluxibleApp.createContext({config});
// Let the Router run.
Router.run(fluxibleApp.getComponent(), req.path, (Handler, state) => {
// Inside navigateAction we check the route we're navigating to and execute the state setup chain.
context.executeAction(navigateAction, state).then((result) => {
debug('RESOLVED navigateAction', result);
debug('Exposing context state');
let exposedState = 'window.App=' + serialize(fluxibleApp.dehydrate(context)) + ';';
debug('Rendering Application component into html');
// We let React create the application HTML
let markup = React.renderToString(<Handler context={context.getComponentContext()} />);
// We get some metadata that is only relevant for server-side applications
// and render it into the HTML here.
let title = DocumentTitle.rewind();
let status = NestedStatus.rewind();
let html = React.renderToStaticMarkup(<Html title={title} state={exposedState} markup={markup} />);
debug('Sending markup');
res.status(status).send('<!DOCTYPE html>' + html);
}).catch((rejectionReason) => {
debug('REJECTED navigateAction', rejectionReason);
res.status(500).send('<!DOCTYPE html>' + 'Error page temp.');
// Error handling is something I still need to work on. It's unlikely I'll be doing this here.
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment