Skip to content

Instantly share code, notes, and snippets.

@wzup
Last active November 12, 2018 16:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wzup/702af49d7e386d845c56c76fc3a5b1b1 to your computer and use it in GitHub Desktop.
Save wzup/702af49d7e386d845c56c76fc3a5b1b1 to your computer and use it in GitHub Desktop.
React server-side rendering with react-router 3.x
'use strict';
const NODE_ENV = process.env.NODE_ENV || 'development';
/* React and Redux stuff */
const React = require('react');
const ReactDOM = require('react-dom');
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
import { createLogger } from 'redux-logger';
const loggerMiddleware = createLogger();
const middleware = routerMiddleware(history);
/**
* My four modules.
*/
const reducersFactory = require('./reducersFactory');
const GetRouter = require('./router');
let getRoutes = require('./routes');
let state = require('./state');
/**
* <BrowserRouter> props. In separate variable for convenience
* https://reacttraining.com/react-router/web/api/BrowserRouter
*/
let routerConf = {
basename: '/', // string
getUserConfirmation: null, // func
forceRefresh: false, // bool, full reload or not
keyLength: 12, // num, def == 6,
}
/**
* This is for redux-devtools-extension in Chrome console.
* Just a useful dev feature. It has nothing to do with my app.
* https://github.com/zalmoxisus/redux-devtools-extension
*/
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
/**
* Create Redux store.
* http://redux.js.org/docs/basics/Store.html
* http://redux.js.org/docs/api/createStore.html
*/
let store = createStore(
reducersFactory({}), // pass initial state.
window.__state__, // important.
// applyMiddleware(thunkMiddleware, loggerMiddleware, middleware), // if w/o redux-devtools-extension
composeEnhancers( applyMiddleware(thunkMiddleware, loggerMiddleware, middleware) ) // if with redux-devtools-extension
);
/**
* Assemble a final app component. To render it into a DOM node.
*/
let Application = (
<Provider store={store}>
<GetRouter env="browser" routes={getRoutes({})} routerConf={routerConf} />
</Provider>
)
/**
* Finally, render it into DOM node
*/
ReactDOM.render(Application, document.getElementById('root'));
'use strict';
/**
* I make reducersFactory a function in order to pass it an initial state as a parameter.
* Switch-case are just for example. You may have your own
*/
function reducersFactory(initialState) {
return function reducers(state = initialState, action) {
switch (action.type) {
case 'login_success':
return Object.assign({}, state, {
user: action.user,
login_starts: false,
});
break;
case 'login_failure':
return Object.assign({}, state, {
user: action.user,
login_starts: false,
});
break;
default:
return state;
}
}
}
module.exports = reducersFactory;
'use strict';
const NODE_ENV = process.env.NODE_ENV || 'development';
const React = require('react');
import { StaticRouter, BrowserRouter, Route, Link } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
/**
* This is only Router.
* This is how I separate it for browser and server environment
* Look at browser.js and server.js and you will see how env prop is passed here
*/
function getRouter(params) {
if(params.env == 'browser') {
return (
<BrowserRouter router={params.routerConf}>
{params.routes}
</BrowserRouter>
);
}
if(params.env == 'server') {
return (
<StaticRouter
basename='/'
location={params.url}
context={params.context}>
{params.routes}
</StaticRouter>
)
}
}
module.exports = getRouter;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment