Help Nepal rebuild by matching donors, service providers and those who need help.
Read dev_setup.md to setup your dev environment
How isomorphic rendering work's for the app, consider a component heirarchy like below:
<App> //Wrapper component
<Hero/> //fetches it's own data
<ProjectList/> //fetches it's own data
<Sidebar/> //fetches it's own data
<Footer/> // Just render some html
</App>
For the above tree to render successfully on the server, the server needs to resolve the data dependency for all the React Components in the tree before it can call React.renderToString(<App flux={flux}/>)
, because React.renderToString
is a synchronous api and data fetching as we know is an async process.
To get around the limitation this is what we do:
-
Call
React.renderToString(<App flux={flux}/>
on server. This is the initial pass and over here we collect data dependencies for all the component's in tree heirarchy. Each component define's it's data dependency incomponenWillMount
[componentWillMount
get's called on server side before render is called]. For e.g to get project's list in<ProjectList/>
component, in it'scomponentWillMount
, we do:componentWillMount() { return this.props.flux.getActions('projects').fetch(); }
-
In the above code we are basically triggering a action to get project's list from
Project Actions
, which looks like below:fetch() { const promise = (resolve) => { this.alt.getActions('requests').start(); setTimeout(() => { this.actions.fetchSuccess(data.projects); this.alt.getActions('requests').success(); return resolve(); }, 300); } // This is important this.alt.resolve(promise); }
Important bit here is
this.alt.reslove(promise)
, on the browser, this tries to resolve the promise immediately, but on the server this pushes the promise to a list of promises that needs to be resolved. Based on our example of the component heirarchy above, on the first pass/render we basically capture all promises for the data requested insidecomponentWillMount
, of component's in the component heirarchy/tree. Once we have resolved all the data dependencies, we do another render withReact.renderToString(<App flux={flux}/>)
on the server, this time with a flux store with all the data dependencies resolved. And then we simply pass the rendered html to the browser. -
There are limitations to this approach. For e.g:
<TopLevelComponent> //Wrapper <DataFetch> //Does a data fetch <ChildDataFetch/> //Child data fetch </DataFetch> </TopLevelComponent>
In the above component heirarchy we cannot resolve the data dependency of the
<ChildDataFetch/>
component, if it relies on the data dependency of the<DataFetch/>
component being resolved. Explore this on your own. -
Important bits.
- Define data dependency for your component in
componentWillMount
- And resolve the promise for data fetch using
this.alt.resolve(promise)
when implementing it in yourAction
to make it compatible on the server side.
- Define data dependency for your component in