I have an ExpressJS server that is sometimes rendering the wrong user's data on initial render. See a (slightly simplified) version below.
The issue is that the index.ejs file is often rendering the wrong user's data in reduxState...
My confusion is because I would expect the call to import { store } from 'routes.js' to overwrite the store as {} with every individual user's request. The problem seems to be that the store is becoming a combined store for every user on the site put together.
How can I make sure that each user sees only their data on the site?
routes.js
// src/routes.js
import React from 'react';
import { createStore, applyMiddleware, compose } from "redux";
import routerConfig from "base/routes/routes";
import thunk from "redux-thunk";
import { rootReducer } from "base/reducers";
let initialState = {};
const store = createStore(
  rootReducer, initialState, compose(applyMiddleware(thunk))
);
const routes = routerConfig(store);
export {store};
export default routes;
server.js
import { store } from 'routes';
let getReduxPromise = (renderProps, request) => {
  let store = require('./routes/index.jsx').store
  let { query, params } = renderProps
  let comp = renderProps.components[renderProps.components.length - 1];
  let at = null;
  if (request && request.cookies && request.cookies.accessToken) {
    at = request.cookies.accessToken
  }
  if (comp.fetchData) {
    return comp.fetchData({ query, params, store, at }).then(response => {
      if (request) {
        if (request.cookies && request.cookies.accessToken && request.cookies.userInfo) {
          store.dispatch(
            actions.auth(request.cookies.userInfo),
            request.cookies.accessToken
          )
        } else {
          store.dispatch(actions.logout())
        }
      }
      return Promise.resolve({response, state: store.getState()})
    });
  } else {
    return Promise.resolve();
  }
}
app.get('*', (request, response) => {
  let htmlFilePath = path.resolve('build/index.html' );
  // let htmlFilePath = path.join(__dirname, '/build', 'index.html');
  let error = () => response.status(404).send('404 - Page not found');
  fs.readFile(htmlFilePath, 'utf8', (err, htmlData) => {
    if (err) {
      console.log('error 1')
      error();
    } else {
      match({routes, location: request.url}, (err, redirect, renderProps) => {
        if (err) {
          console.log('error 2')
          error();
        } else if (redirect) {
          return response.redirect(302, redirect.pathname + redirect.search)
        } else if (renderProps) {
          let parseUrl = request.url.split('/');
          if (request.url.startsWith('/')) {
            parseUrl = request.url.replace('/', '').split('/');
          }
          // User has a cookie, use this to help figure out where to send them.
          if (request.cookies.userInfo) {
            const userInfo = request.cookies.userInfo
            if (parseUrl[0] && parseUrl[0] === 'profile' && userInfo) {
              // Redirect the user to their proper profile.
              if (renderProps.params['id'].toString() !== userInfo.id.toString()) {
                parseUrl[1] = userInfo.id.toString();
                const url = '/' + parseUrl.join('/');
                return response.redirect(url);
              }
            }
          }
          getReduxPromise(renderProps, request).then((initialData) => {
            let generatedContent = initialData.response ? render(request, renderProps, initialData.response) : render(request, renderProps, {});
            const title = initialData.response.seo.title || '';
            const description = initialData.response.seo.description || '';
            var draft = [];
            const currentState =  initialData.state;
            if (currentState) {
              const reduxState = JSON.stringify(currentState, function(key, value) {
                if (typeof value === 'object' && value !== null) {
                  if (draft.indexOf(value) !== -1) {
                    // Circular reference found, discard key
                    return;
                  }
                  // Store value in our collection
                  draft.push(value);
                }
                return value;
              });
              draft = null;
              ejs.renderFile(
                path.resolve('./src/index.ejs' ),
                {
                  jsFile,
                  cssFile,
                  production,
                  generatedContent,
                  reduxState,
                  title,
                  description
                }, {},
                function(err, str) {
                  if (err) {
                    console.log('error 3')
                    console.log(err);
                  }
                  response.status(200).send(str);
                });
            } else {
              console.log('error 4')
              console.log(err)
              error();
            }
          }).catch(err => {
            console.log('error 5')
            console.log(err)
            error();
          });
        } else {
          console.log('error 6')
          console.log(err)
          error();
        }
      });
    }
  })
});
index.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%- title %></title>
    <meta name="description" content="<%- description %>"/>
    <link href="<%- cssFile %>" rel="stylesheet"/>
    <script type="text/javascript" charset="utf-8">
      window.__REDUX_STATE__ = <%- reduxState %>;
    </script>
  </head>
  <body>
    <div id="root"><%- generatedContent %></div>
    <script type="text/javascript" src="<%- jsFile %>" defer></script>
  </body>
</html>
example fetchData function in a React component
ExamplePage.fetchData = function (options) {
  const { store, params, at } = options
  return Promise.all([
    store.dispatch(exampleAction(params.id, ACTION_TYPE, userAccessToken))
  ]).spread(() => {
    let data = {
      seo: {
        title: 'SEO Title',
        description: 'SEO Description'
      }
    }
    return Promise.resolve(data)
  })
}
 
    