React 서버 렌 더 링 의 길 04 - redux - 01
관련 읽 기
소개
npm i redux react-redux redux-thunk redux-logger -S
npm i redux-devtools-extension -D
2.1 store 만 들 기
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';
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 };
}
}
2.2 루트 파일 의 수정
export default (
<>
>
);
export default [
{
path: '/',
component: Home,
exact: true,
key: '/'
},
{
path: '/news',
component: News,
exact: true,
key: '/news'
}
];
{
routes.map(route => )
}
2.2 클 라 이언 트 의 redux
import { Provider } from 'react-redux'; import { Route } from 'react-router-dom'; import { getClientStore } from "../store"; hydrate(
<>
{ routes.map(route =>> , window.root);) }
-
containers/Home/index.js
- 关于 react-redux 的 connect 的用法,可以把 connect 作为组件的装饰器使用,也可以作为函数直接调用使用,因为装饰器实际上就是函数多次调用的语法糖,所以我统一把 connect 的写成函数调用的形式
- connect 的参数,可以直接把方法写在参数里,也可以像这里一样,把 mapStateToProps 和 mapDispatchToProps 先定义成方法,然后直接把方法作为参数
- 关于 actions 里方法的调用,我这里采用的方法,其实是有些复杂的,最简单其实就是直接在组件内部调用 actions 里的方法。我在这里又在组件内部定义了一个方法 A ,在这个组件的 props 里又定义了一个方法 B ,假如 actions 里的方法是 C 。那么最简单的方法就是直接调用 this.props.C(),但是我这里的顺序是这样的,先调用 A(),然后 A() 调用 B(),最后在 B() 里调用 C()。具体如何调用呢,根据个人喜好选择。
- 这里呢,倒不是我鸡贼,总是说怎么用都行,实际上这个也没有什么标准写法。我还是蛮喜欢现在这种写法的,比较清晰明了,传递参数和调用什么的,都很方便,缺点就是代码量多,修改的时候,改动多
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 (
HELLO, HOME PAGE
{this.state.number}
- name: {this.props.user.name}
-
{this.props.user.age}
{
this.props.user.schoolList.map(school => (
-
{school.id}. {school.name}
))
}
);
}
}
const mapStateToProps = state => ({
user: state.user
});
const mapDispatchToProps = dispatch => ({
propIncrementAge() {
dispatch(UserActions.incrementAge());
},
propGetSchoolList() {
dispatch(UserActions.getSchoolList());
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
2.3 서버 의 redux
import { Provider } from 'react-redux'; import { Route } from 'react-router-dom'; let domContent = renderToString(
<>
{ routes.map(route =>> );) }
2.4 接口服务
- /server/app.js,这里已经完全放开了跨域,暂不处理,后期要做修改调整
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}`);
}
});
2.4 총화
3. server / index. js 의 코드 분할
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(
<>
{
routes.map(route => )
}
>
);
let html = `
react-ssr
${domContent}
window.context = {
state: ${JSON.stringify(store.getState())}
}
`;
res.send(html);
};
관련 읽 기
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Thymeleaf 의 일반 양식 제출 과 AJAX 제출텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.