Note on Production UsageIn production, it’s better to serve static files using a server like nginx, and only use Node for handling application requests. However, this is out of scope of this tutorial.
<script>tag that will attach
initialStatewill then be available on the client side by accessing
serve-staticmiddleware included above will serve up this file. We’ll see what that file contains in just a bit.
Note on String Interpolation Syntax
React.render()will hook into the
data-react-idattributes from the server-rendered HTML. This will connect our newly-started React instance to the virtual DOM used on the server. Since we have the same initial state for our Redux store and used the same code for all our view components, the result will be the same real DOM.
Requestobject passed into our server middleware. The parameter is parsed into a number and then set in the initial state. If you visit http://localhost:3000/?counter=100 in your browser, you’ll see the counter starts at 100. In the rendered HTML, you’ll see the counter output as 100 and the
__INITIAL_STATE__variable has the counter set in it.
setTimeoutto simulate a network request that takes 500 milliseconds to respond (this should be much faster with a real world API). We pass in a callback that returns a random number asynchronously. If you’re using a Promise-based API client, then you would issue this callback in your
fetchCounterand receive the result in the callback:
res.send()inside of the callback, the server will hold open the connection and won’t send any data until that callback executes. You’ll notice a 500ms delay is now added to each server request as a result of our new API call. A more advanced usage would handle errors in the API gracefully, such as a bad response or timeout.
counterparameter to ensure this value is a number. If we did not do this, you could easily get dangerous data into the rendered HTML by providing a script tag in the request. That might look like this:
fetchData()methods on your route handler components. They may return async actions, so that your
handleRenderfunction can match the route to the route handler component classes, dispatch
fetchData()result for each of them, and render only after the Promises have resolved. This way the specific API calls required for different routes are colocated with the route handler component definitions. You can also use the same technique on the client side to prevent the router from switching the page until its data has been loaded.