1

I'm using the below function to return initial server-rendered markup and data in case of lack of javascript support:

    export const serverRender = async () => {
        const { port, host } = config;
        const resp = await 
    axios.get(`http://${host}:${port}/testData.json`);

        const initialData = resp.data;
        return {
            initialMarkup: ReactDOMServer.renderToString(<App initialData={initialData} />),
            initialData,
        };
    };

I serve this data to my template as follows (details aren't that important):

    app.setViewEngine("pug");
    app.use(express.static(path.join(__dirname, "../public")));
    app.use(express.static(path.join(__dirname, "../assets")));
    app.enableCors();
    await app.listen(PORT, () => {
        console.log(`Nest App listening on port ${PORT}`);
    });

In my template, I use pug interpolation to read initialData into the window object in javascript (window.initialData = #{initialData}). If my client was a javascript client I could read from the window object like this: window.initialData, but Typescript doesn't allow this.

My question is, what is the best way to pass pre-fetched data and pass it to the client side? Ie. so I can do something like this when I render the client:

    /* somehow grab pre-fetched data */
    ReactDOM.hydrate(<App />, document.getElementById("root")); // entry point for webpack

I'm not saying this is the best way (which is another reason why I'm asking this question), but in the past for small pure javascript projects I've assigned the data to window as above and then in the client rendering of my react, I've done something like this:

    const initialData = window.initialData;
    ReactDOM.hydrate(<App initialData={initialData} />, document.getElementById("root")); // entry point for webpack

This doesn't fly in Typescript

N/a

Error message for the window case: Property 'initialData' does not exist on type 'Window'

But I want to find some other way anyways.

Ben Smith
  • 19,589
  • 6
  • 65
  • 93
StarLlama
  • 380
  • 2
  • 12

1 Answers1

2

Declare how the window global object looks like with your custom initialData value:

declare global {
    interface Window { 
        initialData: any; 
    }
}

Once you've declared this, then:

const initialData = window.initialData;

should work.

Ben Smith
  • 19,589
  • 6
  • 65
  • 93
  • Thanks, this worked! Out of curiosity, is there a better way that you know of? – StarLlama May 31 '19 at 23:06
  • 1
    @StarLlama When I have had to do this (i.e. get data to my client side app from the server), I've stored the data in a [data attribute](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) and then retrieved it on the client using e.g. document.getElementById("yourDivId").dataset.initialData. – Ben Smith Jun 02 '19 at 23:23