第七章 redux
六、react-redux
7. 代码 - react-redux 数据共享版
7.1 效果

7.2 App
import React, { Component } from "react";
import Count from "./containers/Count";
import Person from "./containers/Person";
export default class App extends Component {
render() {
return (
<div>
<Count />
<hr />
<Person />
</div>
);
}
}
7.3 Count
import React, { Component } from "react";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/actions/count";
import { connect } from "react-redux";
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() {
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>
);
}
}
export default connect(
(state) => ({ count: state.he, renshu: state.rens.length }),
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count);
7.4 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, 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);
7.5 store
import { createStore, applyMiddleware, combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
const allReducer = combineReducers({
he: countReducer,
rens: personReducer,
});
export default createStore(allReducer, applyMiddleware(thunk));
7.6 constant
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
7.7 actions
7.5.1 count
import { INCREMENT, DECREMENT } from "../constant";
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
7.5.2 person
import { ADD_PERSON } from "../constant";
export const createAddPersonAction = (personObj) => ({
type: ADD_PERSON,
data: personObj,
});
7.8 reducers
7.8.1 count
import { INCREMENT, DECREMENT } from "../constant";
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
7.8.2 person
import { ADD_PERSON } from "../constant";
const initState = [{ id: "001", name: "tom", age: 18 }];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [data, ...preState];
default:
return preState;
}
}
7.9 总结
(1).定义一个Person组件,和Count组件通过redux共享数据。
(2).为Person组件编写:reducer、action,配置constant常量。
(3).重点:Person的reducer和Count的Reducer要使用combineReducers进行合并,
合并后的总状态是一个对象!!!
(4).交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。
七、纯函数和高阶函数
1. 纯函数
- 一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
- 必须遵守以下一些约束
- 不得改写参数数据
- 不会产生任何副作用,例如网络请求,输入和输出设备
- 不能调用 Date.now()或者 Math.random()等不纯的方法
- redux 的 reducer 函数必须是一个纯函数
2. 高阶函数
- 理解: 一类特别的函数
- 常见的高阶函数:
- 定时器设置函数
- 数组的 forEach()/map()/filter()/reduce()/find()/bind()
- promise
- react-redux 中的 connect 函数
- 作用: 能实现更加动态, 更加可扩展的功能
八、使用 redux 调试工具
1. 安装 chrome 浏览器插件

2. 下载工具依赖包
- npm install --save-dev redux-devtools-extension
3. 总结
(1).yarn add redux-devtools-extension
(2).store中进行配置
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
九、react-redux 最终版

1. 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")
);
2. App.jsx
import React, { Component } from "react";
import Count from "./containers/Count";
import Person from "./containers/Person";
export default class App extends Component {
render() {
return (
<div>
<Count />
<hr />
<Person />
</div>
);
}
}
3. store.js
import { createStore, applyMiddleware } from "redux";
import reducer from "./reducers";
import thunk from "redux-thunk";
export default createStore(reducer, applyMiddleware(thunk));
4. containers
4.1 Count
import React, { Component } from "react";
import {
increment,
decrement,
incrementAsync,
} from "../../redux/actions/count";
import { connect } from "react-redux";
class Count extends Component {
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() {
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>
);
}
}
export default connect(
(state) => ({
count: state.count,
personCount: state.persons.length,
}),
{
increment,
decrement,
incrementAsync,
}
)(Count);
4.2 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.personArr.map((p) => {
return (
<li key={p.id}>
{p.name}--{p.age}
</li>
);
})}
</ul>
</div>
);
}
}
export default connect(
(state) => ({
personArr: state.persons,
count: state.count,
}),
{ addPerson }
)(Person);
5. reducers
5.1 index
import { combineReducers } from "redux";
import count from "./count";
import persons from "./person";
export default combineReducers({
count,
persons
});
5.2 count
import { INCREMENT, DECREMENT } from "../constant";
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
5.3 person
import { ADD_PERSON } from "../constant";
const initState = [{ id: "001", name: "tom", age: 18 }];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [data, ...preState];
default:
return preState;
}
}
6. actions
6.1 count
import { INCREMENT, DECREMENT } from "../constant";
export const increment = (data) => ({ type: INCREMENT, data });
export const decrement = (data) => ({ type: DECREMENT, data });
export const incrementAsync = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data));
}, time);
};
};
6.2 person
import { ADD_PERSON } from "../constant";
export const addPerson = (personObj) => ({
type: ADD_PERSON,
data: personObj,
});
7. 总结
(1).所有变量名字要规范,尽量触发对象的简写形式。
(2).reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer
十、项目打包
npm run build
npm install -g serve
serve -s build
