react-ssr之redux使用

作爲全家桶之一,必須要有啊。必須的必啊

  • 安裝redux(這個我就不說了,自己去npm找)

倉庫的基本配置

  • 在src目錄下新增store目錄
  • 在store目錄下創建index.js, actions-types.js actions 目錄, reducers目錄
  • src/store/index.js
import { createStore, applyMiddleware } from 'redux'
import saga from 'redux-saga'
import logger from 'redux-logger'
import reducers from './reducers'
// 注意:因爲服務端和客戶端store不一樣,所以分別創建,後期會看到代碼不同處理
export function getServerStore () {
    return createStore(
        reducers,
        applyMiddleware(saga, logger)
    )
}


export function getClientStore () {
    return createStore(
        reducers,
        applyMiddleware(saga, logger)
    )
}

// 
  • 創建actions-typeas
export const INCREMENT = 'INCREMENT'
  • 創建reducers, 使用index導出reducers, 單獨定義每一個組建的reduces
//src/store/reducers/index.js 中導出counter
import { combineReducers } from 'redux'
import counter from './counter'

let resucers = combineReducers({
    counter
})

export default resucers
  • 新增src/store/reducers/counter.js文件,內容如下
import * as types from '../action-types'

let initState = {
    number: 0
}

export default function (state = initState, action) {
    switch (action.type) {
        case types.INCREMENT:
        let {number} = state
        return {number: ++number}
    default:
        return state;
    }
}

  • 在src/store/reducers/actions目錄中新建counter.js, 然後定義actions
// 計數器的基本配置
import * as types from '../action-types'
export default {
    increment () {
        return {type: types.INCREMENT}
    }
}

引入store

  • 客戶端的配置
import React, {Fragment} from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import routers from '../routes'
import Header from '../components/Header'
import { Provider } from 'react-redux' // 配合使用redux
import { getClientStore } from '../store' // 導入store

// hydrate 表示把服務端渲染未完成的工作完成,比如綁定事件完成
ReactDOM.hydrate(
<Provider store={getClientStore()}>
<BrowserRouter>
    <Fragment>
        <Header />
        <div className="container" style={{marginTop: 70}}>
            {routers}
        </div>
    </Fragment>
</BrowserRouter>
</Provider>, document.getElementById('root'))
  • 服務端的配置
// src/server/index.js
const Koa = require('koa')
const _ = require('koa-route');
import render from './render'

let app = new Koa()
// 設置服務端靜態目錄
app.use(require('koa-static')('public'))
// 這裏路徑改爲*, 不管哪個路徑,都組走這裏
app.use(_.get('*', render))

app.listen(3000, () => {
    console.log('server start at 3000')
})

// src/server/render.js
import { StaticRouter } from 'react-router-dom'
import Header from '../components/Header'
import routes from '../routes'
import React, {Fragment} from 'react'
import {renderToString} from 'react-dom/server'
import { Provider } from 'react-redux'
import { getServerStore } from '../store'

export default  function (ctx, next) {
    let context = {}
    let store = getServerStore()
    let html = renderToString(
        <Provider store={store}>
            <StaticRouter context={{}} location={ctx.req.url}>
                <Fragment>
                    <Header />
                    <div className="container" style={{marginTop: 70}}>
                        {routes}
                    </div>
                </Fragment>
            </StaticRouter>
        </Provider>
    )
    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>
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
    </head>
    <body>
        <div id="root">${html}</div>
        <script src="/client.js"></script>
    </body>
    </html>
    `
}
  • counter中使用store
import React from 'react'
import { connect } from "react-redux"
import actions from '../../store/actions/counter'

class Counter extends React.Component{
    state = {number: 0}
    render () {
        return (<div style={{textAlign: 'center'}}>
            <p>{this.props.number}</p>
            <button onClick={this.props.increment}>+</button>
        </div>)
    }
}
// 連接store
const WrapCounter = connect(
    state => state.counter,
    actions
)(Counter)
export default WrapCounter

總結

上邊是實現redux的基本過程,這裏再總結一下思路

  1. 在src目錄下創建store目錄

  2. 在store目錄下創建index.js, actions-types.js actions 目錄, reducers目錄

  3. 創建actions-typeas

  4. 創建reducers, 使用index導出reducers, 單獨定義每一個組建的reduces

  5. 在服務端和客戶端配置redux的基本代碼

  6. counter中使用store

完整代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章