react-ssr之事件綁定

沒有處理事件的頁面是不完整…

這裏使用一個計數器的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實現事件綁定
  • 完成代碼傳送門
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章