尚硅谷
1. react-redux的基本使用
UI组件--components-Count
- 只负责 UI 的呈现,不带有任何业务逻辑
- 通过props接收数据(一般数据和函数)
- 不使用任何 Redux 的 API
import React, { Component } from 'react'
export default class Count extends Component {
state = {carName:'奔驰c63'}
//加法
increment = ()=>{
const {value} = this.selectNumber
this.props.jia(value*1)
}
//减法
decrement = ()=>{
const {value} = this.selectNumber
this.props.jian(value*1)
}
//奇数再加
incrementIfOdd = ()=>{
const {value} = this.selectNumber
if(this.props.count % 2 !== 0){
this.props.jia(value*1)
}
}
//异步加
incrementAsync = ()=>{
const {value} = this.selectNumber
this.props.jiaAsync(value*1,500)
}
render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
容器组件-containers-Count
- 负责管理数据和业务逻辑,不负责UI的呈现
- 使用 Redux 的 API
- 一般保存在containers文件夹下
//引入Count的UI组件
import CountUI from '../../components/Count'
//引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
/*
1.mapStateToProps函数返回的是一个对象;
2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
3.mapStateToProps用于传递状态
*/
function mapStateToProps(state) {
return { count: state }
}
/*
1.mapDispatchToProps函数返回的是一个对象;
2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
3.mapDispatchToProps用于传递操作状态的方法
*/
function mapDispatchToProps(dispatch) {
return {
jia: number => dispatch(createIncrementAction(number)),
jian: number => dispatch(createDecrementAction(number)),
jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time)),
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
App.jsx
import React, { Component } from 'react'
// 注意,这里引入containers组件下的Count,即Count的容器组件
import Count from './containers/Count'
import store from './redux/store'
export default class App extends Component {
render() {
return (
<div>
{/* 给容器组件传递store */}
<Count store={store} />
</div>
)
}
}
redux
constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
count_action.js
/*
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'
//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}
count_reducer.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from './constant'
const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log(preState);
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return
preState +
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}
store.js
/*
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//暴露store
export default createStore(countReducer,applyMiddleware(thunk))
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
ReactDOM.render(<App/>,document.getElementById('root'))
//监测redux中状态的改变,如redux的状态发生了改变,那么重新渲染App组件
store.subscribe(()=>{
ReactDOM.render(<App/>,document.getElementById('root'))
})
2. react-redux优化
容器组件和UI组件整合成一个组件-containers-Count
import React, { Component } from 'react'
//引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/count_action'
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
//定义UI组件
class Count extends Component {
state = { carName: '奔驰c63' }
//加法
increment = () => {
const { value } = this.selectNumber
this.props.jia(value * 1)
}
//减法
decrement = () => {
const { value } = this.selectNumber
this.props.jian(value * 1)
}
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
//异步加
incrementAsync = () => {
const { value } = this.selectNumber
this.props.jiaAsync(value * 1, 500)
}
render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h1>当前求和为:{this.props.count}</h1>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
//使用connect()()创建并暴露一个Count的容器组件
//简写写法:直接将函数体写在connect中,同时将mapDispatchToProps简写,可以省略dispatch的调用
export default connect(
state => ({ count: state }),
//mapDispatchToProps的一般写法
/* dispatch => ({
jia:number => dispatch(createIncrementAction(number)),
jian:number => dispatch(createDecrementAction(number)),
jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
}) */
//mapDispatchToProps的简写,这样写得到一个action对象,react-redux自带帮你dispatch
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count)
App.jsx
无需自己给容器组件传递store,把所有容器都需要的store交给Provider,给包裹一个<Provider store={store}>即可。
import React, { Component } from 'react'
import Count from './containers/Count'
export default class App extends Component {
render() {
return (
<div>
<Count/>
</div>
)
}
}
index.js
使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
3. react-redux数据共享版
容器组件和UI组件整合成一个组件-containers-Count
import React, { Component } from 'react'
//引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction
} from '../../redux/actions/count'
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
//定义UI组件
class Count extends Component {
//加法
increment = () => {
const { value } = this.selectNumber
this.props.jia(value * 1)
}
//减法
decrement = () => {
const { value } = this.selectNumber
this.props.jian(value * 1)
}
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.jia(value * 1)
}
}
//异步加
incrementAsync = () => {
const { value } = this.selectNumber
this.props.jiaAsync(value * 1, 500)
}
render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
<h4>当前求和为:{this.props.count}</h4>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
//使用connect()()创建并暴露一个Count的容器组件,和上面相比这里发生了变化
export default connect(
state => ({
count: state.he,
renshu: state.rens.length
}),
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count)
容器组件和UI组件整合成一个组件-containers-Person
import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import { connect } from 'react-redux'
import { createAddPersonAction } from '../../redux/actions/person'
class Person extends Component {
addPerson = () => {
const name = this.nameNode.value
const age = this.ageNode.value
const personObj = { id: nanoid(), name: name, age: age }
this.props.jiaYiRen(personObj)
this.nameNode.value = ''
this.ageNode.value = ''
}
render() {
return (
<div>
<h2>我是Person组件,上方组件求和为{this.props.he}</h2>
<input ref={c => this.nameNode = c} type="text" placeholder="输入名字" />
<input ref={c => this.ageNode = c} type="text" placeholder="输入年龄" />
<button onClick={this.addPerson}>添加</button>
<ul>
{
this.props.yiduiren.map((p) => {
return <li key={p.id}>{p.name}--{p.age}</li>
})
}
</ul>
</div>
)
}
}
export default connect(
state => ({ yiduiren: state.rens, he: state.he }),//映射状态
{ jiaYiRen: createAddPersonAction }//映射操作状态的方法
)(Person)
redux-action-count.js
/*
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from '../constant'
//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(createIncrementAction(data))
},time)
}
}
redux-action-person.js
import {ADD_PERSON} from '../constant'
//创建增加一个人的action动作对象
export const createAddPersonAction = personObj => ({type:ADD_PERSON,data:personObj})
redux-reducers-count.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from '../constant'
const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log('countReducer@#@#@#');
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}
redux-reducers-person.js
import {ADD_PERSON} from '../constant'
//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]
export default function personReducer(preState=initState,action){
// console.log('personReducer@#@#@#');
const {type,data} = action
switch (type) {
case ADD_PERSON: //若是添加一个人
return [data,...preState]
default:
return preState
}
}
constant.js
/*
该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
store.js
/*
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import { createStore, applyMiddleware, combineReducers } from 'redux'
//引入为Count组件服务的reducer
import countReducer from './reducers/count'
//引入为Person组件服务的reducer
import personReducer from './reducers/person'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//汇总所有的reducer变为一个总的reducer,对象内部key:value值为state中的状态
const allReducer = combineReducers({
he: countReducer,
rens: personReducer
})
//暴露store
export default createStore(allReducer, applyMiddleware(thunk))
App.jsx
import React, { Component } from 'react'
import Count from './containers/Count' //引入的是Count的容器组件,不是UI组件
import Person from './containers/Person'//引入的是Person的容器组件,不是UI组件
export default class App extends Component {
render() {
return (
<div>
<Count/>
<hr/>
<Person/>
</div>
)
}
}
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
)
4. react-redux最终版-完善了代码规范
容器组件和UI组件整合成一个组件-containers-Count
import React, { Component } from 'react'
//引入action
import {
increment,
decrement,
incrementAsync
} from '../../redux/actions/count'
//引入connect用于连接UI组件与redux
import { connect } from 'react-redux'
//定义UI组件
class Count extends Component {
state = { carName: '奔驰c63' }
//加法
increment = () => {
const { value } = this.selectNumber
this.props.increment(value * 1)
}
//减法
decrement = () => {
const { value } = this.selectNumber
this.props.decrement(value * 1)
}
//奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber
if (this.props.count % 2 !== 0) {
this.props.increment(value * 1)
}
}
//异步加
incrementAsync = () => {
const { value } = this.selectNumber
this.props.incrementAsync(value * 1, 500)
}
render() {
//console.log('UI组件接收到的props是',this.props);
return (
<div>
<h2>我是Count组件,下方组件总人数为:{this.props.personCount}</h2>
<h4>当前求和为:{this.props.count}</h4>
<select ref={c => this.selectNumber = c}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
)
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({
count: state.count,
personCount: state.persons.length
}),
{
increment: increment,
decrement: decrement,
incrementAsync: incrementAsync
}
)(Count)
容器组件和UI组件整合成一个组件-containers-Person
import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import { connect } from 'react-redux'
import { addPerson } from '../../redux/actions/person'
class Person extends Component {
addPerson = () => {
const name = this.nameNode.value
const age = this.ageNode.value * 1
const personObj = { id: nanoid(), name, age }
this.props.addPerson(personObj)
this.nameNode.value = ''
this.ageNode.value = ''
}
render() {
return (
<div>
<h2>我是Person组件,上方组件求和为{this.props.count}</h2>
<input ref={c => this.nameNode = c} type="text" placeholder="输入名字" />
<input ref={c => this.ageNode = c} type="text" placeholder="输入年龄" />
<button onClick={this.addPerson}>添加</button>
<ul>
{
this.props.persons.map((p) => {
return <li key={p.id}>{p.name}--{p.age}</li>
})
}
</ul>
</div>
)
}
}
export default connect(
state => ({
persons: state.persons,
count: state.count
}),//映射状态
{ addPerson: addPerson }//映射操作状态的方法
)(Person)
redux-action-count.js
/*
该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from '../constant'
//同步action,就是指action的值为Object类型的一般对象
export const increment = data => ({type:INCREMENT,data})
export const decrement = data => ({type:DECREMENT,data})
//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const incrementAsync = (data,time) => {
return (dispatch)=>{
setTimeout(()=>{
dispatch(increment(data))
},time)
}
}
redux-action-person.js
import {ADD_PERSON} from '../constant'
//创建增加一个人的action动作对象
export const addPerson = personObj => ({type:ADD_PERSON,data:personObj})
redux-reducers-count.js
/*
1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import {INCREMENT,DECREMENT} from '../constant'
const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
// console.log('countReducer@#@#@#');
//从action对象中获取:type、data
const {type,data} = action
//根据type决定如何加工数据
switch (type) {
case INCREMENT: //如果是加
return preState + data
case DECREMENT: //若果是减
return preState - data
default:
return preState
}
}
redux-reducers-person.js
import {ADD_PERSON} from '../constant'
//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]
export default function personReducer(preState=initState,action){
// console.log('personReducer@#@#@#');
const {type,data} = action
switch (type) {
case ADD_PERSON: //若是添加一个人
return [data,...preState]
default:
return preState
}
}
redux-reducers-index.js
/*
该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import { combineReducers } from 'redux'
//引入为Count组件服务的reducer
import count from './count'
//引入为Person组件服务的reducer
import persons from './person'
//汇总所有的reducer变为一个总的reducer
export default combineReducers({
count: count,
persons: persons
})
store.js
/*
该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入汇总之后的reducer
import reducer from './reducers'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//引入redux-devtools-extension,redux开发者工具
import {composeWithDevTools} from 'redux-devtools-extension'
//暴露store
export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
codewhy
1. 基础版
page/about:
import React from "react";
import { connect } from "react-redux";
import { decAction, subAction } from "../store/actionCreators";
function About(props) {
// console.log("About页面重新渲染了");
return (
<div>
<hr />
<h1>About</h1>
<h2>当前计数: {props.counter}</h2>
<button onClick={(e) => props.decrement()}>-1</button>
<button onClick={(e) => props.subNumber(5)}>-5</button>
<h1>Banner</h1>
<ul>
{props.banners.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
<h1>Recommend</h1>
<ul>
{props.recommends.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
</div>
);
}
const mapStateToProps = (state) => {
return {
banners: state.banners,
recommends: state.recommends,
counter: state.counter,
};
};
const mapDispatchToProps = (dispatch) => {
return {
decrement: function () {
dispatch(decAction());
},
subNumber: function (num) {
dispatch(subAction(num));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(About);
page/home:
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import axios from "axios";
import {
incAction,
addAction,
changeBannersAction,
changeRecommendAction,
} from "../store/actionCreators";
class Home extends PureComponent {
componentDidMount() {
axios({
url: "http://123.207.32.32:8000/home/multidata",
}).then((res) => {
const data = res.data.data;
this.props.changeBanners(data.banner.list);
this.props.changeRecommends(data.recommend.list);
});
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={(e) => this.props.increment()}>+1</button>
<button onClick={(e) => this.props.addNumber(5)}>+5</button>
</div>
);
}
}
// 相比about组件,简写形式
const mapStateToProps = (state) => ({
counter: state.counter,
});
const mapDispatchToProps = (dispatch) => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
},
changeBanners(banners) {
dispatch(changeBannersAction(banners));
},
changeRecommends(recommends) {
dispatch(changeRecommendAction(recommends));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
actionCreators.js
import axios from "axios";
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND,
} from "./constants.js";
// 简写
export const addAction = (num) => ({
type: ADD_NUMBER,
num,
});
export const subAction = (num) => ({
type: SUB_NUMBER,
num,
});
export const incAction = () => ({
type: INCREMENT,
});
export const decAction = () => ({
type: DECREMENT,
});
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners,
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends,
});
constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
export const CHANGE_BANNERS = "CHANGE_BANNERS";
export const CHANGE_RECOMMEND = "CHANGE_RECOMMEND";
index.js/store
import { createStore } from "redux";
import reducer from "./reducer.js";
const store = createStore(reducer);
export default store;
reducer.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND
} from './constants.js';
const defaultState = {
counter: 0,
banners: [],
recommends: []
}
function reducer(state = defaultState, action) {
switch (action.type) {
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num };
case SUB_NUMBER:
return { ...state, counter: state.counter - action.num };
case INCREMENT:
return { ...state, counter: state.counter + 1 };
case DECREMENT:
return { ...state, counter: state.counter - 1 };
case CHANGE_BANNERS:
return { ...state, banners: action.banners };
case CHANGE_RECOMMEND:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default reducer;
App.js
import React, { PureComponent } from "react";
import Home from "./pages/home3";
import About from "./pages/about3";
export default class App extends PureComponent {
render() {
return (
<div>
<Home />
<About />
</div>
);
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
2. 中间件-thunk
page/about:
import React from "react";
import { connect } from "react-redux";
import { decAction, subAction } from "../store/actionCreators";
function About(props) {
// console.log("About页面重新渲染了");
return (
<div>
<hr />
<h1>About</h1>
<h2>当前计数: {props.counter}</h2>
<button onClick={(e) => props.decrement()}>-1</button>
<button onClick={(e) => props.subNumber(5)}>-5</button>
<h1>Banner</h1>
<ul>
{props.banners.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
<h1>Recommend</h1>
<ul>
{props.recommends.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
</div>
);
}
const mapStateToProps = (state) => {
return {
banners: state.banners,
recommends: state.recommends,
counter: state.counter,
};
};
const mapDispatchToProps = (dispatch) => {
return {
decrement: function () {
dispatch(decAction());
},
subNumber: function (num) {
dispatch(subAction(num));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(About);
page/home:
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import {
incAction,
addAction,
getHomeMultidataAction,
} from "../store/actionCreators";
class Home extends PureComponent {
componentDidMount() {
this.props.getHomeMultidata();
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={(e) => this.props.increment()}>+1</button>
<button onClick={(e) => this.props.addNumber(5)}>+5</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
counter: state.counter,
});
const mapDispatchToProps = (dispatch) => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
},
getHomeMultidata() {
dispatch(getHomeMultidataAction());
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
actionCreators.js
import axios from "axios";
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND,
} from "./constants.js";
// 简写
export const addAction = (num) => ({
type: ADD_NUMBER,
num,
});
export const subAction = (num) => ({
type: SUB_NUMBER,
num,
});
export const incAction = () => ({
type: INCREMENT,
});
export const decAction = () => ({
type: DECREMENT,
});
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners,
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends,
});
// redux-thunk中定义的action函数
export const getHomeMultidataAction = (/*接收传入的参数*/) => {
return (dispatch, getState) => {
// getState--用于获取redux中的数据
axios({
url: "http://123.207.32.32:8000/home/multidata",
}).then((res) => {
const data = res.data.data;
dispatch(changeBannersAction(data.banner.list));
dispatch(changeRecommendAction(data.recommend.list));
});
};
};
constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
export const CHANGE_BANNERS = "CHANGE_BANNERS";
export const CHANGE_RECOMMEND = "CHANGE_RECOMMEND";
index.js/store
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer.js";
const storeEnhancer = applyMiddleware(thunk);
const store = createStore(reducer, storeEnhancer);
export default store;
reducer.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND
} from './constants.js';
const defaultState = {
counter: 0,
banners: [],
recommends: []
}
function reducer(state = defaultState, action) {
switch (action.type) {
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num };
case SUB_NUMBER:
return { ...state, counter: state.counter - action.num };
case INCREMENT:
return { ...state, counter: state.counter + 1 };
case DECREMENT:
return { ...state, counter: state.counter - 1 };
case CHANGE_BANNERS:
return { ...state, banners: action.banners };
case CHANGE_RECOMMEND:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default reducer;
App.js
import React, { PureComponent } from "react";
import Home from "./pages/home4";
import About from "./pages/about3";
export default class App extends PureComponent {
render() {
return (
<div>
<Home />
<About />
</div>
);
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
3. 中间件-saga
page/about:
import React from "react";
import { connect } from "react-redux";
import { decAction, subAction } from "../store/actionCreators";
function About(props) {
// console.log("About页面重新渲染了");
return (
<div>
<hr />
<h1>About</h1>
<h2>当前计数: {props.counter}</h2>
<button onClick={(e) => props.decrement()}>-1</button>
<button onClick={(e) => props.subNumber(5)}>-5</button>
<h1>Banner</h1>
<ul>
{props.banners.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
<h1>Recommend</h1>
<ul>
{props.recommends.map((item, index) => {
return <li key={item.acm}>{item.title}</li>;
})}
</ul>
</div>
);
}
const mapStateToProps = (state) => {
return {
banners: state.banners,
recommends: state.recommends,
counter: state.counter,
};
};
const mapDispatchToProps = (dispatch) => {
return {
decrement: function () {
dispatch(decAction());
},
subNumber: function (num) {
dispatch(subAction(num));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(About);
page/home:
import React, { PureComponent } from 'react';
// import {connect} from '../utils/connect';
import { connect } from 'react-redux';
import {
incAction,
addAction,
fetchHomeMultidataAction
} from '../store/actionCreators'
class Home extends PureComponent {
componentDidMount() {
this.props.getHomeMultidata();
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={e => this.props.increment()}>+1</button>
<button onClick={e => this.props.addNumber(5)}>+5</button>
</div>
)
}
}
const mapStateToProps = state => ({
counter: state.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
},
getHomeMultidata() {
dispatch(fetchHomeMultidataAction);
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
actionCreators.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND,
FETCH_HOME_MULTIDATA,
} from "./constants.js";
// 简写
export const addAction = (num) => ({
type: ADD_NUMBER,
num,
});
export const subAction = (num) => ({
type: SUB_NUMBER,
num,
});
export const incAction = () => ({
type: INCREMENT,
});
export const decAction = () => ({
type: DECREMENT,
});
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners,
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends,
});
// redux-saga拦截的action
export const fetchHomeMultidataAction = {
type: FETCH_HOME_MULTIDATA,
};
constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
export const FETCH_HOME_MULTIDATA = "FETCH_HOME_MULTIDATA";
export const CHANGE_BANNERS = "CHANGE_BANNERS";
export const CHANGE_RECOMMEND = "CHANGE_RECOMMEND";
index.js/store
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
//1. 导入创建中间件的函数;
import createSagaMiddleware from "redux-saga";
import saga from "./saga";
import reducer from "./reducer.js";
// composeEnhancers函数
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
// 引入thunk中间件
// const storeEnhancer = applyMiddleware(thunk);
// 2.通过创建中间件的函数,创建中间件,并且放到applyMiddleware函数中;
const sagaMiddleware = createSagaMiddleware();
const storeEnhancer = applyMiddleware(thunk, sagaMiddleware);
const store = createStore(reducer, composeEnhancers(storeEnhancer));
//3.启动中间件的监听过程,并且传入要监听的saga;
sagaMiddleware.run(saga);
export default store;
reducer.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
CHANGE_BANNERS,
CHANGE_RECOMMEND
} from './constants.js';
const defaultState = {
counter: 0,
banners: [],
recommends: []
}
function reducer(state = defaultState, action) {
switch (action.type) {
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num };
case SUB_NUMBER:
return { ...state, counter: state.counter - action.num };
case INCREMENT:
return { ...state, counter: state.counter + 1 };
case DECREMENT:
return { ...state, counter: state.counter - 1 };
case CHANGE_BANNERS:
return { ...state, banners: action.banners };
case CHANGE_RECOMMEND:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default reducer;
saga
import { takeEvery, put, all, takeLatest } from "redux-saga/effects";
import axios from "axios";
import { FETCH_HOME_MULTIDATA, ADD_NUMBER } from "./constants";
import { changeBannersAction, changeRecommendAction } from "./actionCreators";
//3. 函数执行,进行异步操作,并调用对应的action
function* fetchHomeMultidata(action) {
const res = yield axios.get("http://123.207.32.32:8000/home/multidata");
const banners = res.data.data.banner.list;
const recommends = res.data.data.recommend.list;
// yield put(changeBannersAction(banners));
// yield put(changeRecommendAction(recommends));
yield all([
yield put(changeBannersAction(banners)),
yield put(changeRecommendAction(recommends)),
]);
}
//1. 封装一个生成器函数并暴露,内部拦截对应type的action
function* mySaga() {
// takeLatest takeEvery区别:
// takeLatest: 依次只能监听一个对应的action,也就是多个相同请求只执行最后一次
// takeEvery: 每一次都会被执行
yield all([
// 2. takeLatest(要监听拦截的type, 拦截后调用的生成器函数)
takeLatest(FETCH_HOME_MULTIDATA, fetchHomeMultidata),
takeLatest(ADD_NUMBER, fetchHomeMultidata),
]);
}
export default mySaga;
App.js
import React, { PureComponent } from "react";
import Home from "./pages/home";
import About from "./pages/about";
export default class App extends PureComponent {
render() {
return (
<div>
<Home />
<About />
</div>
);
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
4.最终版--拆分目录结构
page/about:
import React from 'react';
// import { connect } from '../utils/connect';
import { connect } from 'react-redux';
import {
decAction,
subAction
} from '../store/counter/actionCreators';
function About(props) {
return (
<div>
<hr />
<h1>About</h1>
<h2>当前计数: {props.counter}</h2>
<button onClick={e => props.decrement()}>-1</button>
<button onClick={e => props.subNumber(5)}>-5</button>
<h1>Banner</h1>
<ul>
{
props.banners.map((item, index) => {
return <li key={item.acm}>{item.title}</li>
})
}
</ul>
<h1>Recommend</h1>
<ul>
{
props.recommends.map((item, index) => {
return <li key={item.acm}>{item.title}</li>
})
}
</ul>
</div>
)
}
const mapStateToProps = state => {
return {
counter: state.counterInfo.counter,
banners: state.homeInfo.banners,
recommends: state.homeInfo.recommends
}
};
const mapDispatchToProps = dispatch => {
return {
decrement: function () {
dispatch(decAction());
},
subNumber: function (num) {
dispatch(subAction(num))
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(About);
page/home:
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import {
incAction,
addAction
} from '../store/counter/actionCreators';
import {
fetchHomeMultidataAction
} from '../store/home/actionCreators';
class Home extends PureComponent {
componentDidMount() {
this.props.getHomeMultidata();
}
render() {
return (
<div>
<h1>Home</h1>
<h2>当前计数: {this.props.counter}</h2>
<button onClick={e => this.props.increment()}>+1</button>
<button onClick={e => this.props.addNumber(5)}>+5</button>
</div>
)
}
}
const mapStateToProps = state => ({
counter: state.counterInfo.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
},
getHomeMultidata() {
dispatch(fetchHomeMultidataAction);
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
counter/actionCreators.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT,
} from './constants.js';
export const addAction = num => ({
type: ADD_NUMBER,
num
});
export const subAction = num => ({
type: SUB_NUMBER,
num
});
export const incAction = () => ({
type: INCREMENT
});
export const decAction = () => ({
type: DECREMENT
});
counter/constants.js
export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
counter/index.js
import reducer from './reducer';
export {
reducer
}
//可以将counter文件夹下所有的导出都集中到index.js中统一导出,更规范
counter/reducer.js
import {
ADD_NUMBER,
SUB_NUMBER,
INCREMENT,
DECREMENT
} from './constants.js';
// 拆分counterReducer
const initialCounterState = {
counter: 0
}
function counterReducer(state = initialCounterState, action) {
switch (action.type) {
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num };
case SUB_NUMBER:
return { ...state, counter: state.counter - action.num };
case INCREMENT:
return { ...state, counter: state.counter + 1 };
case DECREMENT:
return { ...state, counter: state.counter - 1 };
default:
return state;
}
}
export default counterReducer;
home/actionCreators.js
import axios from 'axios';
import {
CHANGE_BANNERS,
CHANGE_RECOMMEND,
FETCH_HOME_MULTIDATA
} from './constants.js';
// 轮播图和推荐的action
export const changeBannersAction = (banners) => ({
type: CHANGE_BANNERS,
banners
});
export const changeRecommendAction = (recommends) => ({
type: CHANGE_RECOMMEND,
recommends
});
// redux-thunk中定义的action函数
export const getHomeMultidataAction = (dispatch, getState) => {
axios({
url: "http://123.207.32.32:8000/home/multidata",
}).then(res => {
const data = res.data.data;
dispatch(changeBannersAction(data.banner.list));
dispatch(changeRecommendAction(data.recommend.list));
})
}
// redux-saga拦截的action
export const fetchHomeMultidataAction = {
type: FETCH_HOME_MULTIDATA
}
home/constants.js
export const FETCH_HOME_MULTIDATA = "FETCH_HOME_MULTIDATA";
export const CHANGE_BANNERS = "CHANGE_BANNERS";
export const CHANGE_RECOMMEND = "CHANGE_RECOMMEND";
home/index.js
import reducer from './reducer';
export {
reducer
}
//可以将home文件夹下所有的导出都集中到index.js中统一导出,更规范
home/reducer.js
import {
CHANGE_BANNERS,
CHANGE_RECOMMEND
} from './constants.js';
// 拆分homeReducer
const initialHomeState = {
banners: [],
recommends: []
}
function homeReducer(state = initialHomeState, action) {
switch (action.type) {
case CHANGE_BANNERS:
return { ...state, banners: action.banners };
case CHANGE_RECOMMEND:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default homeReducer;
index.js/store
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import createSagaMiddleware from "redux-saga";
import saga from "./saga";
import reducer from "./reducer.js";
// 1.引入thunk中间件
// composeEnhancers函数--redux调试工具
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
// const storeEnhancer = applyMiddleware(thunk);
// 2.创建sagaMiddleware中间件
const sagaMiddleware = createSagaMiddleware();
const storeEnhancer = applyMiddleware(thunk, sagaMiddleware);
const store = createStore(reducer, composeEnhancers(storeEnhancer));
sagaMiddleware.run(saga);
export default store;
reducer.js/store
import { reducer as counterReducer } from './counter';
import { reducer as homeReducer } from './home';
import { combineReducers } from 'redux';
// function reducer(state = {}, action) {
// return {
// counterInfo: counterReducer(state.counterInfo, action),
// homeInfo: homeReducer(state.homeInfo, action)
// }
// }
//reducer应该是一个什么类型? function
//合并
const reducer = combineReducers({
counterInfo: counterReducer,
homeInfo: homeReducer
});
export default reducer;
saga.js/store
import { takeEvery, put, all } from 'redux-saga/effects';
import axios from 'axios';
import {
FETCH_HOME_MULTIDATA
} from './home/constants';
import {
changeBannersAction,
changeRecommendAction
} from './home/actionCreators';
function* fetchHomeMultidata(action) {
const res = yield axios.get("http://123.207.32.32:8000/home/multidata");
const banners = res.data.data.banner.list;
const recommends = res.data.data.recommend.list;
// yield put(changeBannersAction(banners));
// yield put(changeRecommendAction(recommends));
yield all([
yield put(changeBannersAction(banners)),
yield put(changeRecommendAction(recommends))
])
}
function* mySaga() {
// takeLatest takeEvery区别:
// takeLatest: 依次只能监听一个对应的action
// takeEvery: 每一个都会被执行
yield all([
takeEvery(FETCH_HOME_MULTIDATA, fetchHomeMultidata),
// takeLatest(ADD_NUMBER, fetchHomeMultidata),
]);
}
export default mySaga;
App.js
import React, { PureComponent } from "react";
import Home from "./pages/home";
import About from "./pages/about";
export default class App extends PureComponent {
render() {
return (
<div>
<Home />
<About />
</div>
);
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);