5

Let's say I have a component like below.

User extends React.Component {
  componentDidMount() {
    this.props.fetchUserDetails(this.props.params.userSlugName);
    // this slug name is coming from route params (ex: path is /users/:userSlugName)
  }
  // Other lifecycle methods
}

User.loadData = () => {
  // some data fetching logic for backend
}

I'm using react-router v4 with react-router-config settings. I'm running out of ideas. How to get userSlugName inside the server.

Now how can I prefetch these details in Server for SSR to work properly.

Akhil P
  • 1,580
  • 2
  • 20
  • 29

1 Answers1

0

Incorporating async logic in Server side rendering is a bit tricky. When you call renderToString(), you will get the html for the initial render(). What you need is the html for subsequent render() which happens when the data comes in.

The basic idea is the following:

  • Execute the API calls
  • Wait for them to finish
  • Return html for final render()

You can try the approach mentioned on Redux website (https://redux.js.org/recipes/server-rendering#async-state-fetching) or on this tutorial (https://www.sitepoint.com/asynchronous-apis-server-rendered-react/).

I prefer the latter, it's more generic and you don't need different fetching code for each component. You might want to tweak the code to make it simpler though. More details on react router's context API here : https://medium.freecodecamp.org/how-to-protect-your-routes-with-react-context-717670c4713a

function handleRender(req, res) {
    const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
    console.log('fullUrl: ', fullUrl);
    console.log('req.url: ', req.url);

    // Create a new Redux store instance
    const store = createStore(reducerFn);
    const context = {};    // Store stuff here

    const urlToRender = req.url;
    // Render the component to a string
    const html1 = renderToString(
        <Provider store={store}>
            <StaticRouter location={urlToRender} context={context}>
                {routes}
            </StaticRouter>
        </Provider>
    );

    // Get promises from context, wait for all of them to finish
    // Render again
    const html = renderToString(
        <Provider store={store}>
            <StaticRouter location={urlToRender} context={context}>
                {routes}
            </StaticRouter>
        </Provider>
    );
    const helmet = Helmet.renderStatic();

    // Grab the initial state from our Redux store
    const preloadedState = store.getState();

    // Send the rendered page back to the client
    res.send(renderFullPage(helmet, html, preloadedState));
}

I'll share the code for https://www.heloprotocol.in/ when I get a chance.

Kira
  • 415
  • 4
  • 16