How To Implement React Server Side Rendering With HMR in Webpack2? - javascript

I am trying to implement server side rendering with my react app that uses HMR and need some clarification on my issues. There seems to be miscommunication between the server and the frontend but I'm not entirely sure why that is.
When I start my server, the browser loads the client side index.html and I am able to edit my site with HMR working just fine. However, when I navigate to another page besides the homepage, and I refresh the browser, the server then renders the html markup in my handleRender function. The sites html markup appears, however there is no css and HMR doesn't work.
To summarize, on first load, it renders the app client side, but upon refresh, it renders the app server side. I'm thinking it might have to do with the way I am using router.use(express.static(clientDir)); but I'm not sure. Any clarification would be helpful!
Client side Index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Base Template</title>
<link rel="stylesheet" type="text/css" href="/static/bundle.css">
</head>
<body id="body">
<div class="root"></div>
<script src="/static/bundle.js"></script>
</body>
</html>
React App index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
const root = document.querySelector('.root');
// Wraps our App in AppContainer
const render = (Component) => {
ReactDOM.render(
<BrowserRouter>
<AppContainer>
<Component/>
</AppContainer>
</BrowserRouter>,
root
);
};
// Renders our application
render(App);
// Checks if there have been changes and accepts them.
// This activates HMR and refreshes modules in the browser
if (module.hot) {
module.hot.accept();
}
Express Server
import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router'
import { resolve } from 'path'
import routes from './routes'
// Imports our React App
import App from '../client/scripts/App'
// Create Express App
const app = express();
// Set the port for our server
app.set('port', process.env.PORT || 3000)
// Use routes to check if the environment is prod || dev
app.use(routes)
// Use handleRender for SSR
app.use(handleRender)
function handleRender(req, res) {
const context = {};
const html = renderToString(
<StaticRouter location={req.url} context={context} >
<App/>
</StaticRouter>
)
if (context.url) {
res.writeHead(301, {
Location: context.url
})
res.end()
} else {
res.write(`
<!doctype html>
<head>
<title>Redux Universal Example</title>
<link rel="stylesheet" type="text/css" href="/static/bundle.css">
</head>
<body>
<div id="app">${html}</div>
<script type="javascript" src="/static/bundle.js"></script>
</body>
`)
res.end()
}
}
export default app
Routes for server
import express, { Router } from 'express'
import { resolve } from 'path'
import { isDev } from '../utils'
const router = Router();
const clientDir = resolve(`${__dirname}/../../client`);
if (isDev()) {
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')
const webpackConfig = require('../../../webpack.config')
const webpackHotMiddleware = require('webpack-hot-middleware')
const compiler = webpack(webpackConfig)
// This compiles our app using webpack
router.use(webpackDevMiddleware(compiler, {
publicPath: webpackConfig.output.publicPath,
noInfo: true
}))
// This connects our app to HMR using the middleware
router.use(webpackHotMiddleware(compiler))
}
router.use(express.static(clientDir));
export default router

Related

SSR app but React Router Navigation on the client side doesn't fetch data and breaks the page

I've created a SSR React app that loads data on the server and sends it to the client as html. The problem kicks in after the initial server request has been served and i try to switch to a different navigation link. The url changes to the correct path but the page itself breaks with a TypeError: Cannot read property 'length' or 'map' of undefined. I believe the fetching somehow is not working on the client side, because if i turn off JavaScript from the browser everything works just fine.
The App has four routes, Home, Movies (needs to fetch data), TvShows (needs to fetch data) and PageNotFound. Again, the problem occurs when for example I open the Home page and try to switch to Movies. However, if i open Movies or TvShows first everything loads correctly because of the initial request being served by the server. Here is my file structure:
And here's the content of some of my files:
index.js (Server.js)
import "#babel/polyfill";
import express from "express";
import { applyMiddleware, createStore } from "redux";
import Routes from "./client/Routes";
import { matchRoutes } from "react-router-config";
import renderer from "./helpers/renderer.js";
import thunk from "redux-thunk";
import reducers from "./reducers";
const compression = require("compression");
const app = express();
app.use(compression());
app.use(express.static("public")); //treats the public(client side) directory as public, available to the outside world
// This is fired every time the server side receives a request
app.get("*", (req, res) => {
// Create a new Redux store instance
const store = createStore(reducers, {}, applyMiddleware(thunk));
const promises = matchRoutes(Routes, req.path)
.map(({ route }) => {
return route.loadData ? route.loadData(store) : null;
})
.map((promise) => {
if (promise) {
return new Promise((resolve, reject) => {
promise.then(resolve).catch(resolve);
});
}
});
Promise.all(promises).then(() => {
// Send the rendered page back to the client
// Grab the initial state from our Redux store
const context = {};
//const finalState = store.getState();
const content = renderer(req, store, context);
if (context.notFound) {
res.status(404);
}
res.send(content);
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT);
client.js
import "#babel/polyfill";
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import { renderRoutes } from "react-router-config";
import Routes from "./Routes";
import reducers from "../reducers";
// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__;
// Create Redux store with initial state
const store = createStore(reducers, preloadedState, applyMiddleware(thunk));
ReactDOM.hydrate(
<Provider store={store}>
<BrowserRouter>
<div>{renderRoutes(Routes)}</div>
</BrowserRouter>
</Provider>,
document.querySelector("#root")
);
renderer.js
import React from "react";
import serialize from "serialize-javascript";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router-dom";
import { Provider } from "react-redux";
import Routes from "../client/Routes";
import { renderRoutes } from "react-router-config";
import { Helmet } from "react-helmet";
// Render the component to a string
export default (req, store, context) => {
const html = renderToString(
<Provider store={store}>
<StaticRouter location={req.path} context={context}>
<div>{renderRoutes(Routes)}</div>
</StaticRouter>
</Provider>
);
const helmet = Helmet.renderStatic();
return `
<!doctype html>
<html>
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
</head>
<body>
<div id="root">${html}</div>
<script>
// WARNING: See the following for security issues around embedding JSON in HTML:
// https://redux.js.org/recipes/server-rendering/#security-considerations
window.__PRELOADED_STATE__ = ${serialize(store.getState())}
</script>
<script src="/bundle.js"></script>
</body>
</html>
`;
};
Routes.js
import App from "./App";
import HomePage from "./pages/HomePage";
import MovieListPage from "./pages/MovieListPage";
import TvShowsPage from "./pages/TvShowsPage";
import NotFoundPage from "./pages/NotFoundPage";
//using spread operator for the components
//and loadData function(if available)
//because they are imported in object form now
export default [
{
...App, //no path added to App, meaning it will always be displayed on screen
routes: [
{
...HomePage,
path: "/",
exact: true,
},
{
...MovieListPage,
path: "/movies",
exact: true,
},
{
...TvShowsPage,
path: "/tvshows",
exact: true,
},
{
...NotFoundPage, //will be shown if react router can't match any of the defined routes
},
],
},
];
MovieListPage.js
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchMovies } from "../../actions";
import { Helmet } from "react-helmet";
class MovieListPage extends Component {
// Have state ready for both Movies and TvShows link clicks/direct requests
componentDidMount() {
if (this.props.movies) return;
this.props.fetchMovies();
}
renderData() {
return this.props.movies.results.map((movie) => {
return (
<div
key={movie.id}
className="card text-center m-3"
style={{ width: "15rem" }}
>
<img
className="card-img-top"
alt="..."
src={this.dynamicUrl(movie)}
/>
<div className="card-body">
<h5 className="card-title">{movie.title}</h5>
<p className="card-text font-weight-light">{movie.release_date}</p>
<a href={this.dynamicLink(movie)} className="btn btn-secondary">
TMDB
</a>
</div>
</div>
);
});
}
dynamicUrl(movie) {
let url = "https://image.tmdb.org/t/p/w200/" + movie.poster_path;
return url;
}
dynamicLink(movie) {
let link = "https://www.themoviedb.org/movie/" + movie.id;
return link;
}
head() {
return (
<Helmet>
<title>{`${this.props.movies.results.length} Movies Loaded`}</title>
<meta property="og:title" content="Movies" />
</Helmet>
);
}
render() {
return (
<div className="container">
{this.head()}
<div className="row">{this.renderData()}</div>
</div>
);
}
}
function mapStateToProps(state) {
return { movies: state.movies };
}
function loadData(store) {
return store.dispatch(fetchMovies());
}
//exporting the component and the loadData function (if present)
//in the form of an object(key:value pair)
// to avoid overlap of different loadData function imports in Routes
export default {
loadData,
component: connect(mapStateToProps, { fetchMovies })(MovieListPage),
};
I can't seem to figure out what is it that i'm missing.
I found the issue in renderer.js. I didn't provide the correct path for my client-side bundle.js in the html served by the server. Instead of <script src="/bundle.js"></script> it had to be <script src="/public/bundle.js"></script>.

Problem using index.html to route components of React App

When running my application on the localhost I had no problem visiting urls that I manually typed in or refreshing the page but after using heroku to deploy the app, I can only visit pages by navigating through the home page. After reading some posts on here( React-router urls don't work when refreshing or writing manually ) , I decided to try to apply a "catch-all" solution. I have implemented the /* function in the 'server.js' file but the webpage loads the blank index.html page instead of the correct react component and can not figure out why. The code for the related pages are below:
Api.js
`
const request = require('request');
const express = require('express');
const app = express();
const router = express.Router();
var varViews = 0;
const {createServer} = require('http');
const path = require('path');
const PORT = process.env.PORT || 3000
const dev = app.get('env') !== 'production'
if(!dev){
console.log("Not Dev mode");
app.use(express.static(path.resolve(__dirname, 'build')));
app.use(express.static(__dirname + '/public'));
app.get("/", (req, res) => {
console.log('Home page');
res.send("This is the home page");
})
app.post("/usbstat", (req, res) => {
varViews++;
var views = {views: varViews};
res.json(views);
})
app.delete("/usbstat", (req, res) => {
varViews = 0;
var views = {views: 0};
res.json(views);
})
app.get("/usbstat", (req, res) => {
var numViews = {views: varViews};
return res.json(numViews);
})
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, '/public/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})
}
app.listen(PORT, () => {
console.log('App is listening on'+PORT);
})
module.exports = app;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<!-- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> -->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Nova Cyber Security Test</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script src="../src/index.js"></script>
</body>
</html>
app.js
import React, { Component } from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import history from './history';
import Home from './pages/home/Home';
import USBDrive from './pages/usbdrive/USBDrive';
import phishingStats from './pages/phishingStats/phishingStats';
import Admin from './pages/admin/Admin';
class App extends Component {
render() {
return (
<Router history={history}>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/USBStats' component={USBDrive}/>
<Route exact path='/phishingStats' component={phishingStats}/>
<Route exact path='/admin' component={Admin}/>
</Switch>
</Router>
);
}
}
export default App;

React serverside rendering pointing to wrong bundle.js

I have a react server-side rendering application along with node & express js.
Routes.js
import React from 'react';
import { Route } from 'react-router-dom';
import Home from './Home';
import Test from './Test';
export default () => {
return (
<div>
<Route exact path="/" component={Home} />
<Route exact path="/test/:deviceId" component={Test} />
</div>
);
};
index.js
import express from 'express';
import renderer from './helpers/renderer';
const app = express();
app.use(express.static('public')));
app.get('*', (req, res) => {
console.log(req.url);
res.send(renderer(req));
});
app.listen(3090, () => {
console.log('listening at http://localhost:3090');
})
renderer.js
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import Routes from '../components/Routes';
export default req => {
const content = renderToString(
<StaticRouter location={req.path} context={{}}>
<Routes />
</StaticRouter>
);
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">${content}</div>
<script src="bundle.js"></script>
</body>
</html>
`;
};
client.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import Routes from './Routes';
ReactDOM.hydrate(
<BrowserRouter>
<Routes />
</BrowserRouter>
, document.getElementById('app'));
Well, I am trying to pass a deviceId along with my route /test/:deviceId,
and my HTML template under renderer.js looks for bundle.js file under /test/build.js instead of /bundle.js
How do I make sure my bundle file always points to the correct location which is under public folder exposed by
app.use(express.static('public'));
if I visit, / route to Home component, it looks for bundle.js under correct folder which is the public folder.
Do let me know if you need any extra information.
Well, finally I have figured out what was changing the path of bundle.js with each out.
if my route is '/', it will look for bundle.js at http://localhost:3090/bundle.js
if the route is '/test/:deviceId', it will look for bundle.js at http://localhost:3090/test/:deviceId/bundle.js (in this scenario it will never find bundle.js)
I fixed it my modifying the html temlate under renderer.js
for the tag I changed path to bundle.js from 'bundle.js' to '/bundle.js'
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import Routes from '../components/Routes';
export default req => {
const content = renderToString(
<StaticRouter location={req.path} context={{}}>
<Routes />
</StaticRouter>
);
return `
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">${content}</div>
<script src="/bundle.js"></script>
</body>
</html>
`;
};
Now, it will always look for bundle.js under http://localhost:3090/bundle.js

How to do server-side rendering in React/redux?

I am new to react/redux I little confused with server side rending in react/redux,
Yes i saw some example on the internet but when i tried with mock api with external server , server side rendering is not working .
cat.js
import React from 'react';
import {render} from 'react-dom';
import {connect} from 'react-redux';
import * as mockApi from '../Actions/mockActions';
class Cat extends React.Component{
componentWillMount(){
this.props.getMockApi();
}
render(){
return(
<div>
Hello Dude
{this.props.mock.data.map((data,i) => {
return <li key={i}>{data.email}</li>
})}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
mock:state.mock
}
};
const mapDispatchToProps = (dispatch) => {
return {
getMockApi:() => dispatch(mockApi.getMockData())
}
};
export default connect(mapStateToProps,mapDispatchToProps)(Cat);
mockActions.js
import axios from 'axios';
import * as types from './actionTypes';
export function getMockData() {
return dispatch => {
return axios.get('http://jsonplaceholder.typicode.com/users').then(response => {
dispatch(setThisData(response.data))
})
}
}
export function setThisData(data) {
return {
type:types.MOCK_API,
payload:data
}
}
App.js
import React from 'react';
import {render} from 'react-dom';
import Cat from './components/cat'
import {Provider} from 'react-redux';
import configureStore from './Store/configureStore';
import { createStore ,applyMiddleware,compose} from 'redux';
import counterApp from './Reducers'
import thunk from 'redux-thunk';
if(typeof window !== 'undefined'){
// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__
// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__
const store = createStore(counterApp, preloadedState, compose(applyMiddleware(thunk)))
render(
<Provider store={store} >
<Cat/>
</Provider>
,
document.getElementById('app')
)
}
devServer.js
import express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware'
import webpackHotMidleware from 'webpack-hot-middleware';
import bodyParser from 'body-parser';
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux';
import counterApp from '../../src/client/ReduxServer/Reducers';
import App from '../../src/client/ReduxServer/components/cat';
import { renderToString } from 'react-dom/server'
import webpackConfig from '../../webpack.config.dev';
let app = express();
app.use(bodyParser.json());
app.use(express.static('public'))
const compiler = webpack(webpackConfig);
app.use(webpackMiddleware(compiler, {
hot: true,
publicPath: webpackConfig.output.publicPath,
noInfo: true
}));
app.use(webpackHotMidleware(compiler));
// app.get('/*', (req, res) => {
// res.sendFile(path.join(__dirname, '../../index.html'))
// });
//Redux Start
app.use(handleRender);
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
function renderFullPage(html, preloadedState) {
console.log(preloadedState)
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="app">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script>
<script src="bundle.js"></script>
</body>
</html>
`
}
//Redux Ends
app.listen(3000, () => {
console.log('Listening')
});
Right now this will only server render the hello dude but not the mock Api call data .I know that missed to fetch the data from server side but the point is what will i do If ihave to render a two components and that component has 5 api reuqest ,And how to fecth the correct api Request
Right Now My client Side Prefecthed state will look like this
window.__PRELOADED_STATE__ = {"mock":{"data":[]}}
Ok, to make this clear, you've created the code to handle server rendering. However, it doesn't load the data that is supposed to be fetched right?
You've done the first step, great! The next step is to load the actual dynamic data to the store. Let's look at this code here
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
What happened is that you created a store. The store is used to render the html into a string. Then you get the store state and put it into preloadedState.
This is great accept that renderToString will not call this.props.getMockApi(); as you would expect.
Instead, you have to fetch the state before you call renderToString();
In this case, what you could do is as following. (Note that this is just an example, you probably want to use something more general in production, especially if you use something like react-router.)
import * as mockApi from '../Actions/mockActions';
function handleRender(req, res) {
const store = createStore(counterApp);
store.dispatch(mockApi.getMockData())
// And since you used redux-thunk, it should return a promise
.then(() => {
const html = renderToString(
<Provider store={store}>
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
});
}
Simple isn't it? ;D, nah just joking. This is one part of react where there's not really an exact solution to the problem yet.
Personally, if I had the choice to go back in time, I'd tell myself to learn other stuff other than server rendering. There are other techniques such as code splitting, lazy loading, etc that I could've used instead. With server rendering, if the javascript arrives long after the user has seen the initial page, they might get frustrated by other things that require js. For example in my case, some links are not working, some buttons don't do anything, etc.
I'm not saying that server rendering is not good. It's an interesting technique, just that there are other techniques that are more beneficial to learn first (Oh, and server rendering basically locks you to use nodejs for your backend). Good luck to you :)

node server, Redux doesn't dispatch content back to UI component

The issue is when I do npm run start-dev to run client side code, it works perfectly. But whenever I run npm run start to start up the server side. The Client side doesn't dispatch the content back to UI. Need help.
Server.js
'use strict';
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';
import NotFoundPage from './components/NotFoundPage';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const content = require('./Action/reducer');
// initialize the server and configure support for ejs templates
const app = new Express();
const server = new Server(app);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// define the folder that will be used for static assets
app.use(Express.static(path.join(__dirname, 'static')));
// universal routing and rendering
app.get('*', (req, res) => {
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
const store = createStore(content);
// in case of error display the error message
if (err) {
return res.status(500).send(err.message);
}
// in case of redirect propagate the redirect to the browser
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
// generate the React markup for the current route
let markup;
if (renderProps) {
// if the current route matched we have renderProps
markup = renderToString(
<Provider store={store}>
<RouterContext {...renderProps}/>
</Provider>
);
} else {
// otherwise we can render a 404 page
markup = renderToString(<NotFoundPage/>);
res.status(404);
}
res.send(renderFullPage(markup))
// render the index template with the embedded React markup
// return res.render('index', { markup });
}
);
});
function renderFullPage(html) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/img/favicon.ico">
<link rel="apple-touch-icon" sizes="76x76" href="assets/img/apple-icon.png">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>Chris</title>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<meta name="viewport" content="width=device-width" />
<link href="bootstrap3/css/bootstrap.css" rel="stylesheet" />
<link href="assets/css/gsdk.css" rel="stylesheet" />
<link href="assets/css/demo.css" rel="stylesheet" />
<!-- Font Awesome -->
<link href="bootstrap3/css/font-awesome.css" rel="stylesheet"/>
<link href='https://fonts.googleapis.com/css?family=Grand+Hotel' rel='stylesheet' type='text/css'/>
</head>
<body>
<div id="main">${html}</div>
<script src="../static/js/bundle.js"></script>
<script src="jquery/jquery-1.10.2.js" type="text/javascript"></script>
<script src="assets/js/jquery-ui-1.10.4.custom.min.js" type="text/javascript"></script>
<script src="bootstrap3/js/bootstrap.js" type="text/javascript"></script>
<script src="assets/js/gsdk-checkbox.js"></script>
<script src="assets/js/gsdk-radio.js"></script>
<script src="assets/js/gsdk-bootstrapswitch.js"></script>
<script src="assets/js/get-shit-done.js"></script>
<script src="assets/js/custom.js"></script>
</body>
</html>
`
}
// start the server
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
Client:
'use strict';
import React from 'react';
import { render } from 'react-dom'
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import Layout from './components/Layout';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const reducer = require('./Action/reducer');
const store = createStore(reducer);
// import { createStore } from 'redux';
// const content = require('./Action/reducer');
// const store = createStore(content);
// import Layout from './components/Layout';
render(
<Provider store={store}>
<Router history={browserHistory} routes={routes} onUpdate={() => window.scrollTo(0, 0)}/>
</Provider>,
document.getElementById('main')
)
Layout.js
'use strict';
import React from 'react';
import { Link } from 'react-router';
// const actions = require('../Action/actions');
import * as actions from '../Action/actions';
import {connect} from 'react-redux';
class Layout extends React.Component {
handleSwitchLang(targetLang) {
this.props.switchLanguage(targetLang);
}
render() {
let switchLanguage = this.props.switchLanguage;
let content = this.props.content;
return (
some UI code
);
}
}
function mapStateToProps(state) {
return { content: state.content }
}
export default connect(mapStateToProps, actions)(Layout);
reducer.js
const action_types = require('./action_types');
import json from '../../lang.json';
const initialState = {
content: json.en // Loads default language content (en) as an initial state
};
const reducer = function (state = initialState, action) {
switch (action.type) {
case action_types.SWITCH_LANGUAGE:
return {
content: json[action.language]
};
default:
return state;
}
};
module.exports = reducer;
You can try out my code if you want. Here is my github project.
https://github.com/luznlun/samwebsite
clone the project. do npm install, npm runs start-dev to run client side(Working), npm run start(problem with dispatch).
Really appreciate the help

Categories