在初始服务器端渲染(SSR)后,ReactDOM.hydrate()无法工作 (React JS)

4
在我的应用程序的首次服务器端渲染之后,我的Homepage.js组件中按钮的onClick事件没有执行。似乎我在client.js文件中的ReactDom.hydrate()方法无效。非常感谢您的任何帮助!您可以访问以下存储库获取整个代码库:https://github.com/thegreekjester/React_SSR
运行和重现问题的步骤:
- npm install - 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

你需要检查以下几点:

  • 为什么在客户端的webpack配置中使用了target: 'node'
  • <script type='babel' src='client_bundle.js'></script>这个是什么意思?为什么要用babel类型?
  • 根据你编译javascript的方式,你可能还需要在客户端入口中使用babel-polyfill

你好!如果我在client_bundle.js脚本上不加type='babel',就会导致引用错误。 - Peter Louis
这是因为脚本标签没有被加载。如果我没记错的话,错误信息应该是“require未定义”或类似的内容。 - Jonathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接