I am working on a web project. In this project we use server side rendering with node , express and react. For fetching data and Redux , we use Redux-Saga. There is only one problem. Every page is rendered from server and when we get to browser, our app acts like a client side application. If a page has some ajax calls, and that page renders from server, although it has all data it needs from server , in client side it makes the ajax calls. I want to stop the additional ajax calls. I want to skip the ajax calls for the requested page from server only.
this is index.jsx file for client side.
import App from './App'
import ReactDOM from 'react-dom'
import React from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux'
import getStore from './getStore';
import createHistory from 'history/createBrowserHistory';
import './styles/styles.scss';
const history = createHistory();
const store = getStore(history);
if (module.hot) {
module.hot.accept('./App', () => {
const NextApp = require('./App').default;
render(NextApp);
});
}
const render = (_App) => {
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<_App />
</ConnectedRouter>
</Provider>
, document.getElementById("AppContainer"));
};
store.subscribe(() => {
const state = store.getState();
if (state.items.length > 0) {
render(App);
}
});
const fetchDataForLocation = location => {
if (location.pathname === "/") {
store.dispatch({ type: `REQUEST_FETCH_ITEMS` });
}
};
fetchDataForLocation(history.location);
history.listen(fetchDataForLocation);
this is the index.js file for server
import path from 'path';
import express from 'express';
import webpack from 'webpack';
import yields from 'express-yields';
import fs from 'fs-extra';
import App from '../src/App';
import { renderToString } from 'react-dom/server';
import React from 'react'
import { argv } from 'optimist';
import { ConnectedRouter } from 'react-router-redux';
import getStore from '../src/getStore'
import { Provider } from 'react-redux';
import createHistory from 'history/createMemoryHistory';
import open from 'open';
import { get } from 'request-promise';
const port = process.env.PORT || 4000;
const app = express();
const useServerRender = argv.useServerRender === 'true';
const inDebugMode = argv.inDebugMode == 'true';
let indexPath = inDebugMode ? '../public/index.html' : './public/index.html';
let mediaPath = inDebugMode ? '../src/styles/media' : './src/styles/media';
app.use('/media', express.static(mediaPath));
function* getItems() {
let data = yield get("http://localhost:3826/api/item/getall", { gzip: true });
return JSON.parse(data);
}
if (process.env.NODE_ENV === 'development') {
const config = require('../webpack.config.dev.babel.js').default;
const compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
stats: {
assets: false,
colors: true,
version: false,
hash: false,
timings: false,
chunks: false,
chunkModules: false
}
}));
app.use(require('webpack-hot-middleware')(compiler));
} else {
app.use(express.static(path.resolve(__dirname, '../dist')));
}
app.get(['/', '/aboutus'], function* (req, res) {
let index = yield fs.readFile(indexPath, "utf-8");
const initialState = {
items: []
};
if (req.path == '/') {
const items = yield getItems();
initialState.items = items.data.items;
}
const history = createHistory({
initialEntries: [req.path]
});
const store = getStore(history, initialState);
if (useServerRender) {
const appRendered = renderToString(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
);
index = index.replace(`<%= preloadedApplication %>`, appRendered)
} else {
index = index.replace(`<%= preloadedApplication %>`, `Please wait while we load the application.`);
}
res.send(index);
});
app.listen(port, '0.0.0.0', () => {
console.info(`Listening at http://localhost:${port}`);
if (process.env.NODE_ENV === 'development') {
open(`http://localhost:${port}`);
}
});
I think if somehow we are able to use server side store in client side, we may overcome this problem.
It's all about store data. we should send store data somehow to client side, And use this data for store in client side.
For me the best solution is via html:
<script id='app-props' type='application/json'>
<![CDATA[<%= initialData %>]]>
</script>
And in store file i retrieve it like this:
if (typeof window !== 'undefined') {
let initialDataEl = document.getElementById('app-props');
try {
let props = initialDataEl.textContent;
props = props.replace("<![CDATA[", "").replace("]]>", "");
defaultState = JSON.parse(props);
}
catch (err) {
console.log(err);
}
}