(精华)2020年7月31日 React 手写ssr服务端渲染

举报
愚公搬代码 发表于 2021/10/18 23:04:50 2021/10/18
【摘要】 共用部分 import React ,{useState} from 'react' import {connect} from 'react-redux' import {getIndexList} ...

共用部分

import React ,{useState} from 'react'
import {connect} from 'react-redux'
import {getIndexList} from '../store/index'
const Index = (props) => {
    let [count,setCount] = useState(1)
    return (
        <div>
            <h1>服务端渲染</h1>
            <h1>{count}</h1>
            <button onClick={()=>{props.getIndexList()}}>加载</button>
            <button onClick={()=>{setCount(count+1)}}>增加</button>
            {
                props.list.map(item=><li key={item.id}>{item.name}</li>)
            }
        </div>
    )
}
Index.load = (store) => {
    return store.dispatch(getIndexList())
}
export default connect(
    state => ({list:state.index.list}),
    {getIndexList}
)(Index)


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
import axios from 'axios'
const GET_LIST = 'INDEX/GET_LIST'

// action 

const changeList = list => ({
    type:GET_LIST,
    list
})

// 有一个请求 可以改变reducer

export const getIndexList = ()=>{
    return (dispatch)=>{
        return axios.get('http://xxxxxxxxxxx').then((res)=>{
            const {list} = res.data
            dispatch(changeList(list))
        })
    }
}
const initState = {
    list:[]
}
export default (state = initState,action) => {
    switch(action.type){
        case GET_LIST:
        const newState = {
            ...state,
            list:action.list
        }
        return newState
        default:
            return state
    }
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

客户端

import React from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter} from 'react-router-dom'
import {Provider} from 'react-redux'
import {getClientStore} from '../store/store'
import {Route,Link} from 'react-router-dom'
import routers from '../router'

const store = getClientStore()
const App = ()=>{
    return (
        <Provider store={store}>
            <BrowserRouter>
                <div>
                    <Link to="/">首页</Link>
                    <Link to="/login">登录</Link>
                </div>
                {routers.map(route=><Route {...route}/>)}
            </BrowserRouter>
        </Provider>
    )
}
ReactDOM.hydrate(
    <App/>
    ,document.getElementById('root'))


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

服务端

import express from 'express'
import React from 'react'
import {renderToString} from 'react-dom/server' // 专门在server端使用的
import {StaticRouter} from 'react-router-dom'
import {Provider} from 'react-redux'
import {getStore} from '../store/store'
import {Route,Link} from 'react-router-dom'
import {matchRoutes} from 'react-router-config'
import routers from '../router'
let store = getStore()
let app = express()
app.use(express.static('public'))
app.get('*',function(req,res){
    // 遍历所有的路由 寻找有load方法的
    const matchedRoutes = matchRoutes(routers,req.path)
    let promises = []
    matchedRoutes.forEach(item=>{
        let {load} = item.route.component
        if(load){
            const promise = new Promise((resolve,reject)=>{
                load(store).then(resolve).catch(reject)
            })  
            promises.push(promise)
        }
    })
    Promise.all(promises).then(()=>{
        let content = renderToString(
            <Provider store={store}>
                <StaticRouter>
                    <div>
                        <Link to="/">首页</Link>
                        <Link to="/login">登录</Link>
                    </div>
                    {routers.map(route=><Route {...route}/>)}
                </StaticRouter>
            </Provider>
            
        )
        const html = `
            <html>
                <head>
                    <title>软谋教育</title>
                </head>
                <body>
                    <div id="root">${content}</div>
                    <script>
                        window._context = ${JSON.stringify(store.getState())}
                    </script>
                    <script src="/main.js"></script>
                </body>
            </html>
        `
        res.send(html)
    })
    

    
})

app.listen(1000,()=>{console.log('监听1000端口成功');
})


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

先编译客户端在启动服务端

"scripts": {
    "dev:server": "webpack --config webpack.server.js --watch",
    "dev:start": "nodemon --watch build --exec node \"./build/bundle.js\"",
    "dev:client": "webpack --config webpack.client.js --watch"
  },


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

文章来源: codeboy.blog.csdn.net,作者:愚公搬代码,版权归原作者所有,如需转载,请联系作者。

原文链接:codeboy.blog.csdn.net/article/details/107723690

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。