最初的SSR(React JS)后,ReactDOM.hydrate()不起作用

时间:2018-10-15 05:41:04

标签: javascript reactjs webpack react-redux react-router

在应用程序的初始服务器端呈现之后,我的onClick事件(在Homepage.js组件中的按钮上)没有执行。似乎我的client.js文件中的ReactDom.hydrate()无法正常工作。任何帮助将不胜感激!您可以转到以下代码库了解整个代码库https://github.com/thegreekjester/React_SSR

运行和重现该问题的步骤:

  • npm安装
  • npm run dev
  • 在浏览器中打开localhost:3000
  • 单击出现的按钮
  • 您应该在控制台中看到一些消息,但是没有看到

homepage.js:

import React from 'react'
import {connect} from 'react-redux'

class HomePage extends React.Component{

    exampleMethod(){
      console.log('Shit is going down')
    }

    render(){
      return(
        <div>
          <h1>{this.props.state.attributes.name}</h1>
          <button onClick={() => this.exampleMethod()}> Console log some text </button>
        </div>
      )
    }
}

const mapStateToProps = (state) => ({state:state.optimizelyReducer});

const mapDispatchToProps = (dispatch) => ({
  dataFileManager: (timing, id, attributes) => dispatch({type:'USER_SERVICE', id:id, attributes:attributes},
                               dispatch({type:'DATAFILE_MANAGER', timing:timing})),
  updateAttr: (attr) => dispatch({type:'UPDATE_ATTR', attr:attr, value:value})
});

HomePage = connect(mapStateToProps, mapDispatchToProps)(HomePage);



export default HomePage;

client.js:

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom';
import { Provider as ReduxProvider } from 'react-redux'
import App from './App.js'
import configureStore from './store/configureStore';

const preloadedState = window.__PRELOADED_STATE__

const store = configureStore(window.__PRELOADED_STATE__);

ReactDOM.hydrate(
  <ReduxProvider store={store}>
  <BrowserRouter>
    <App />
  </BrowserRouter>
  </ReduxProvider>,
  document.getElementById('root')
);

server.js:

import 'babel-polyfill'
import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router'
import bodyparser from 'body-parser'
import App from './src/App.js'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import configureStore from './src/store/configureStore.js'


const app = express();
const PORT = process.env.PORT || 3000


app.use(bodyparser.json());

app.use(express.static('build/public'));

function handleRender(req, res){
  const store = configureStore()
  const context = {}
  const html = ReactDOMServer.renderToString(
    <Provider store={store}>
    <StaticRouter location={req.url} context={context}>
      <App/>
    </StaticRouter>
    </Provider>
  )

  const preloadedState = store.getState()
  res.send(renderFullPage(html, preloadedState))
}

function renderFullPage(html, preloadedState){
  return  `
          <html>
          <head>
          </head>
          <body>
            <div id='root'>${html}</div>
            <script>window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}</script>
            <script type='babel' src='client_bundle.js'></script>
          </body>
          </html>`

}

app.use(handleRender)



app.listen(PORT, () => {
  console.log(`React SSR App is running on port ${PORT}`)
});

Webpack.client.js

const path = require('path');
const webpackNodeExternals = require('webpack-node-externals');

module.exports = {

  // production || development
  mode: 'development',

  // Inform webpack that we're building a bundle
  // for nodeJS, rather then for the browser
  target: 'node',

  // Tell webpack the root file of our
  // server application
  entry: './src/client.js',

  // Tell webpack where to put the output file
  // that is generated
  output: {
    filename: 'client_bundle.js',
    path: path.resolve(__dirname, 'build/public'),
    publicPath: '/build/public'
  },
  module: {
    rules: [
      {
        test: /\.js?$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
        options: {
          presets: [
            'react', 'stage-0', ['env', {
              target: 'web'
            }]
          ]
        }
      }
    ]
  }
};

Webpack.server.js

const path = require('path');
const webpackNodeExternals = require('webpack-node-externals');

module.exports = {

  // production || development
  mode: 'development',

  // Inform webpack that we're building a bundle
  // for nodeJS, rather then for the browser
  target: 'node',

  // Tell webpack the root file of our
  // server application
  entry: './server.js',

  // Tell webpack where to put the output file
  // that is generated
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'build'),
    publicPath: '/build'
  },

  module: {
    rules: [
      {
        test: /\.js?$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
        options: {
          presets: [
            'react', 'stage-0', ['env', {
              target: { browsers: ['last 2 versions']}
            }]
          ]
        }
      }
    ]
  },

  // Tell webpack not to bundle any libraries that exist in the 'node_modules' folder
  // into the server bundle
  externals: [webpackNodeExternals()]

};

1 个答案:

答案 0 :(得分:0)

您需要检查以下几点:

  • 您为什么在客户端Webpack配置中使用target: 'node'
  • <script type='babel' src='client_bundle.js'></script>怎么了?为什么输入babel?
  • 根据您的JavaScript编译方式,您可能还需要在客户端条目中使用babel-polyfill