ReactJS stands out from a heap of front-end JavaScript frameworks, which dues to its one-way data binding and reactive data flow.
In order to reuse processing logic in both server and client side, we use express for backend, which is a minimal and flexible Node.js web application framework.
So the puzzle comes in: How to handle render in both sides for multiple request
Brief Glance
Choose React Router for dynamic route matching, separate react component into two types:
container component and view component, introduce a handler layer mechanism.
Further explanation: Container component is a smart component which knows how to fetch data it needs and operate the puppet ones (view component).
Going Deep
Route matching
After look into React Router docs, we can build Nesting logic in Routes.js.
Handler layer definition
Firstly consider every container component(e.g LandingPage) will render one page content, so define static method fetchApiData.
Secondly build the matching logic for both sides, here we introduce fetchApiData util to help us,
filter the component and return its own fetchApiData result after calling.
After having this beautiful util, magic time shows.
In server side render:
In client side render:
Client side render, in order to prevent fetchApiData method call again if already got in server side,
our window has the pageData attribute. If pageData exists, just use the data to render whole page. If not,
client side will use the same logic to fetch api data.
Thirdly extract shared DOM structure, put them into Root Component(e.g App). Also in server sides render code
('<!DOCTYPE html>' + renderToString(context);), directly return whole html instead of define index.html.
Seo requirement
Different page has different meta data in head tag, which meets seo requirement.
In order to do that, additional static method is needed for container component.
Also prepareMetadata util is needed.
If more complex seo requirement comes, for example, need to generate meta data according to different api result,
current implementation can easily expand, just change the render logic like the following, use server side as example:
Call the prepareMetaData and pass api data as parameters, stuff metaData DOM as renderProps.params attribute, then you can use the metaData in App component.
Configuration management
For configuration, make sure both sides can use, and the difficult part is: How client side get configuration.
Two ways:
1) For server side, define global variables. For client side, replace special words in index.html, add extra attribute for window.
2) For server side read configuration file. For client side, let server side pass configuration as renderProps.params attribute into App component, then insert script.