全部源代碼、文檔和圖片都在 github 的倉庫裏,點擊進入倉庫javascript
更新 store 有三種css
npm i redux react-redux redux-thunk redux-logger -S
npm i redux-devtools-extension -D
這裏的功能有三個html
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import logger from 'redux-logger'; import { composeWithDevTools } from 'redux-devtools-extension'; import reducers from './reducers'; export const getServerStore = () => createStore( reducers, composeWithDevTools(applyMiddleware(thunk, logger)) ); export const getClientStore = () => createStore( reducers, composeWithDevTools(applyMiddleware(thunk, logger)) );
import { combineReducers } from 'redux'; import userReducer from './user/reducer'; export default combineReducers({ user: userReducer });
export const SET_INCREMENT_AGE = 'SET_INCREMENT_AGE'; export const GET_SCHOOL_LIST = 'GET_SCHOOL_LIST';
store/user/createActions.jsjava
import * as Types from './actionTypes'; import axios from 'axios'; export const incrementAge = () => { return { type: Types.SET_INCREMENT_AGE } }; export const getSchoolList = () => { return (dispatch) => { return axios.get('http://localhost:8758/api/getSchoolList').then(res => { if (res.status === 200) { let schoolList = res.data.schoolList; console.log(res.data); dispatch({ type: Types.GET_SCHOOL_LIST, payload: schoolList }); } }); } }
import * as Types from './actionTypes'; const initState = { name: 'mark', age: 18, schoolList: [] }; export default (state = initState, action) => { switch (action.type) { case Types.SET_INCREMENT_AGE: return { ...state, age: state.age + 1 }; case Types.GET_SCHOOL_LIST: console.log(action); return { ...state, schoolList: action.payload }; default: return { ...state }; } }
export default ( <> <Route path='/' exact component={Home}/> <Route path='/news' component={News}/> </> );
export default [ { path: '/', component: Home, exact: true, key: '/' }, { path: '/news', component: News, exact: true, key: '/news' } ];
{ routes.map(route => <Route {...route} />) }
import { Provider } from 'react-redux'; import { Route } from 'react-router-dom'; import { getClientStore } from "../store"; hydrate( <Provider store={getClientStore()}> <BrowserRouter> <> <Header/> <div className="container" style={{ marginTop: 70 }}> { routes.map(route => <Route {...route} />) } </div> </> </BrowserRouter> </Provider>, window.root);
containers/Home/index.jsreact
import React, { Component } from 'react'; import { connect } from 'react-redux'; import * as UserActions from '../../store/user/createActions'; class Home extends Component { state = { number: 0 }; handleClick = () => { this.setState({ number: this.state.number + 1 }); }; incrementAge = () => { this.props.propIncrementAge(); }; getSchoolList = () => { this.props.propGetSchoolList(); } render() { return ( <div> <h2>HELLO, HOME PAGE</h2> <h2> <button className="btn btn-primary" onClick={this.handleClick}>click</button> <span>{this.state.number}</span> </h2> <ul className="list-group"> <li className="list-group-item">name: {this.props.user.name}</li> <li className="list-group-item"> <button className="btn btn-primary" onClick={this.incrementAge}>increment age</button> <span>{this.props.user.age}</span></li> </ul> <h2> <button className="btn btn-primary" onClick={this.getSchoolList}>schoolList</button> </h2> <ul className="list-group"> { this.props.user.schoolList.map(school => ( <li key={school.id} className="list-group-item"> {school.id}. {school.name} </li> )) } </ul> </div> ); } } const mapStateToProps = state => ({ user: state.user }); const mapDispatchToProps = dispatch => ({ propIncrementAge() { dispatch(UserActions.incrementAge()); }, propGetSchoolList() { dispatch(UserActions.getSchoolList()); } }) export default connect(mapStateToProps, mapDispatchToProps)(Home);
import { Provider } from 'react-redux'; import { Route } from 'react-router-dom'; let domContent = renderToString( <Provider store={getServerStore()}> <StaticRouter context={context} location={req.path}> <> <Header/> <div className="container" style={{ marginTop: 70 }}> { routes.map(route => <Route {...route} />) } </div> </> </StaticRouter> </Provider> );
const express = require('express'); let app = express(); const PORT = 8758; app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "content-type"); res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); next(); }); app.get('/api/getSchoolList', (req, res) => { let schoolList = [ { id: 1, name: '動物大學' }, { id: 2, name: '植物大學' }, { id: 3, name: '建築大學' }, { id: 4, name: '服裝大學' } ] return res.json({ schoolList }); }); app.listen(PORT, err => { if (err) { console.log(err); } else { console.log(`the server is running at http://localhost:${PORT}`); } });
import express from 'express'; import render from './render'; const app = express(); const PORT = 3000; app.use(express.static('public')); app.get('*', (req, res) => { render(req, res); }); app.listen(PORT, err => { if (err) { console.log(err); } else { console.log(`Server is running at http://localhost:${PORT}`); } });
import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter, Route, matchPath } from 'react-router-dom'; import { Provider } from 'react-redux'; import { getServerStore } from '../store'; import Header from './../components/Header/index'; import routes from '../routes'; export default (req, res) => { let context = {}; let store = getServerStore(); let domContent = renderToString( <Provider store={store}> <StaticRouter context={context} location={req.path}> <> <Header /> <div className="container" style={{ marginTop: 70 }}> { routes.map(route => <Route {...route} />) } </div> </> </StaticRouter> </Provider> ); let html = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.css" rel="stylesheet"> <title>react-ssr</title> </head> <body> <div id="root">${domContent}</div> <script> window.context = { state: ${JSON.stringify(store.getState())} } </script> <script src="/client.js"></script> </body> </html> `; res.send(html); };