Server-side Rendering
What server-side rendering (SSR) do is basically rendering our React markup that's supposed to be only rendered on the client browser by our JavaScript bundle directly from our server. Our client-side bundle would then rehydrate our server-side rendered markup so it can be interactive later on.
There's several reason for why we want to server-side render our React app. First, server-side rendered web app are more crawler friendly, so it can then boost our SEO ranking better, especially for crawlers that didn't run JavaScript. Second, our initial page load would be faster, since users can immediately see informations on our site, and when our JavaScript bundle finally arrives, it would just need to rehydrate our server-side rendered markup instead of regenerating all the DOM element again.
Creating server-side rendered React web apps are known to be very painful process since you need to configure lots of things from the server, data loading process, etc. But fret' not, since Treats are designed to supports SSR by default, we can just add few adjustments to our pages component and let Treats handle the rest.
To implement SSR in Treats, we can just provide getInitialState static method for our page component. The getInitialState method would then receives router and server context object that could be used as sources for any data fetching or state adjustment that you may want to make from our server-side actions. For example:
// src/pages/my-page/my-page.js
import React, { Component } from "react";
import myAction from "../redux/my-action";
class MyPage extends Component {
....
static async getInitialState({ router, serverContext}) {
const { req, reduxStore } = serverContext;
return reduxStore.dispatch(myAction.serverSideRender(req));
}
render() {
const { status, myData } = this.props;
return (
<div>
{status === "loading" && <span>Loading....</span>}
{status === "done" && myData && myData.length > 0 && <div>
{myData.map(datum => {
<RENDER SOMETHING WITH THE DATA>
})}
</div>}
</div>
);
}
}
const mapStateToProps = state => ({
status: state.status,
myData: state.myData
});
const mapDispatchToProps = dispatch => ({
...
});
export default AsyncComponent(module, connect(mapStateToProps, mapDispatchToProps)(MyPage));
To define getInitialState from functional component:
// src/pages/my-page/my-page.js
import React, { Component } from "react";
import myAction from "../redux/my-action";
const MyPage = ({ status, myData }) => (
<div>
{status === "loading" && <span>Loading....</span>}
{status === "done" && myData && myData.length > 0 && <div>
{myData.map(datum => {
<RENDER SOMETHING WITH THE DATA>
})}
</div>}
</div>
);
MyPage.getInitialState = async ({ router, serverContext}) => {
const { req, reduxStore } = serverContext;
return reduxStore.dispatch(myAction.serverSideRender(req));
};
const mapStateToProps = async (state) => ({
status: state.status,
myData: state.myData
});
const mapDispatchToProps = dispatch => ({
...
});
export default AsyncComponent(module, connect(mapStateToProps, mapDispatchToProps)(MyPage));
And don't forget to register our page in the router definition like so:
// src/_route/module.js
export default [{
name: "my-page",
path: "/my-page"
}]
// src/_route/route.js
import MyPage from "../page/my-page"
export default {
"/my-page": MyPage
};
Router and Server Context Object
Router and server context object would always be passed on our page's getInitialState method, these object can then be used to determine what action would be made to render our React app on the server:
routerobject contains current matched route for this component. This is basically the compiled version of our route definition, for the example above, the router object would be:
{
name: "my-page",
path: "/my-page",
component: MyPage
}
serverContextobject containsreq,res,reduxStore, andapolloClient:reqobject express request object.resobject express response object.reduxStoreRedux Store redux store that is specifically created for current request.apolloClientApollo Client Apollo GraphQL client that is specifically created for the current request.
