沒有處理事件的頁面是不完整…
這裏使用一個計數器的demo來展示如何實現事件綁定….
主要需要兩個步驟,抽離配置,頁面引入我們寫好的計數器腳本
抽離webpack配置文件,單獨打包server端和client端
- webpack.base.js 基礎配置
module.exports = {
mode: 'development',
target: 'web',
module: {
rules: [
{
test: /\.(js)$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}
]
}
}
- webapck.client.js 客戶端打包配置
const path = require('path')
const nodeExternal = require('webpack-node-externals')
const merge = require('webpack-merge')
const base = require('./webpack.base')
module.exports = merge(base, {
// entry: './src/server/index.js', // 提示
entry: './src/client/index.js',
output: {
filename: 'client.js',
path: path.join(__dirname,'public')
}
})
- webpack.server.js 服務端打包配置
const path = require('path')
const nodeExternal = require('webpack-node-externals')
const merge = require('webpack-merge')
const base = require('./webpack.base')
module.exports = merge(base, {
target: 'node', // 告訴webpack 打包的是node環境的
// entry: './src/server/index.js', // 提示
entry: ['babel-polyfill', './src/server/index.js'],
output: {
filename: 'server.js',
path: path.join(__dirname,'build')
},
// 負責檢測所有引入不得node的核心模塊,並且通知webpack不需要將核心代碼打入到server.js 文件中去
externals: [nodeExternal()],
})
頁面引入計數器
1.引入上邊寫好的腳本(打包後,輸出到public)
2.配置服務器靜態目錄(client端打包後文件存放的路徑)
文件修改
src/containers/Counter/index.js
文件修改如下
import React from 'react'
/**
@desc 這是一個簡單的計數器demo
*/
class Counter extends React.Component{
state = {
number: 0
}
render () {
return (<div style={{textAlign: 'center'}}>
<p>{this.state.number}</p>
<button onClick={() => {
let {number} = this.state
number++;
this.setState({number})
}}>+</button>
</div>)
}
}
export default Counter
因爲服務端返回的是HTML文本,所以需要在客戶端寫一個一模一樣的代碼。用來處理事件綁定
src/client/index.js
頁面修改如下:
ReactDOM.hydrate:是核心,通過他講本地js和服務端返回的代碼進行合併,而不是替換,從而實現事件綁定
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from '../containers/Counter'
// hydrate 表示把服務端渲染未完成的工作完成,比如綁定事件完成
ReactDOM.hydrate(<Counter />, document.getElementById('root'))
src/server/index.js
頁面修改
const Koa = require('koa')
const path = require('path')
const _ = require('koa-route');
import React from 'react'
import Counter from '../containers/Counter/index'
import {renderToString} from 'react-dom/server'
let app = new Koa()
app.use(require('koa-static')('public')) // 設置靜態目錄 方便瀏覽器訪問
app.use(_.get('/', async function (ctx, next) {
// 轉義組件爲字符串
let counter = renderToString(<Counter />)
ctx.body = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">${counter}</div>
<script src="/client.js"></script><!-- 引入腳本 -->
</body>
</html>
`
}))
app.listen(3000)
總結
至此,完成了事件綁定的基本寫法,順便整理一下實現步驟
- 爲了方便處理,我們抽離了webpack的配置
- 寫一個簡單的計數器
- server端引入計數器,然後客戶端(因爲返回的內容是HTML,dom事件沒法綁定…)
- 修改client腳本,使用
ReactDOM.hydrate
實現事件綁定 - 完成代碼傳送門