I'm currently reading a book about React and Universal apps in which the author claims that the following is best practice to pass initial state from server to client:
server.js
import React from 'react';
import {renderToStaticMarkup} from 'react-dom/server';
import Myapp from '../MyApp';
import api from '../services';
function renderPage(html, initialData) {
return `
<html>
<body>
${html}
</body>
<script>
window.__INITIAL_STATE__ = ${JSON.stringify(initialData)};
</script>
<script src="bundle.js"></script>
</html>
`;
}
export default function(request, reply) {
const initialData = api.getData();
const html = renderToStaticMarkup(<MyApp />);
reply(renderPage(html, initialData);
}
And then, in the client you would read out the data like this:
bundle.js
const initialData = window.__INITIAL_STATE__ || {};
const mountNode = document.getElementById('root');
ReactDOM.render(<MyApp />, mountNode);
From what I understand is that the initial state first gets converted to a string and then attached as a global object literal to the window object.
This solution looks very rough to me. The book was released in mid 2016. Is usage of window.__INITIAL_STATE__
still the way how to do this or are there better solutions?
For example, I could imagine that it would be possible to offer the initial state in a separate micro service call which then could also be cached better than if the data is embedded directly into the document because then the initial state data has to be transferred every time the page refreshes, even if the data hasn't changed.
Simple answer: Yes.
But I'm not sure why no one has pointed out that you have a very common XSS vulnerability using JSON.stringify(initialData)
what you want to do instead is to:
import serialize from 'serialize-javascript';
window.__INITIAL_STATE__ = ${serialize(initialData)};