一、React Redux 数据共享
1、基本介绍
- combineReducers 函数用于汇总所有的 Reducer 变为一个总的 Reducer
2、演示
(1)redux
- constant
js
复制代码
// 定义 action 中 type 的常量值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
- action
js
复制代码
// 该文件专门为 Count 组件生成 action
import { INCREMENT, DECREMENT } from "../constant";
// 同步 action
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步 action,就是 action 的值为函数,异步 action 中一般都会调用同步 action
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
js
复制代码
import { ADD_PERSON } from "../constant";
export const createAddPersonAction = (data) => ({ type: ADD_PERSON, data });
- reducer
js
复制代码
// 该文件是用于创建一个为 Count 组件服务的 Reducer
// Reducer 本质就是一个函数
// Reducer 会接收到两个参数,preState(之前的状态)、action(动作对象)
// 从 action 中可以获取到 type 和 data,根据 type 决定如何加工 data
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;
}
}
js
复制代码
import { ADD_PERSON } from "../constant";
const initState = [];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [...preState, data];
default:
return preState;
}
}
- store
js
复制代码
// 该文件专门用于暴露一个 store 对象,整个应用只有一个 store 对象
import { createStore, applyMiddleware, combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
// 汇总所有的 Reducer 变为一个总的 Reducer
const reducer = combineReducers({
count: countReducer,
persons: personReducer,
});
// applyMiddleware 用于应用基于 Redux 的中间件
export default createStore(reducer, applyMiddleware(thunk));
(2)container
- Count 容器组件
jsx
复制代码
import React, { Component } from "react";
// 引入 action
import { createIncrementAction, createDecrementAction, createIncrementAsyncAction } from "../../redux/actions/count";
// 引入 connect 函数,用于连接组件与 Redux
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;
const { count } = this.props;
if (count % 2 !== 0) {
this.props.jia(value * 1);
}
};
// 异步加
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.jiaAsync(value * 1, 500);
};
render() {
return (
<div>
<h2>当前人员数量为:{this.props.personCount}</h2>
<h2>当前求和为:{this.props.count}</h2>
<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>
);
}
}
// 1. mapStateToProps 函数返回的是一个对象
// 2. 返回的对象中,key 就作为传递给组件 props 的 key,value 就作为传递给组件 props 的 value
// 3. mapStateToProps 函数用于传递状态
function mapStateToProps(state) {
return {
count: state.count,
personCount: state.persons.length,
};
}
// 1. mapDispatchToProps 函数返回的是一个对象
// 2. 返回的对象中,key 就作为传递给组件 props 的 key,value 就作为传递给组件 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)),
};
}
// 创建并暴露一个 Count 的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Count);
- Person 容器组件
jsx
复制代码
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.addPerson(personObj);
this.nameNode.value = "";
this.ageNode.value = "";
};
render() {
return (
<div>
<h2>求和为 {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>
);
}
}
function mapStateToProps(state) {
return {
persons: state.persons,
count: state.count,
};
}
// mapDispatchToProps 的简写,如果传入的是对象,就自动用 dispatch 包裹每个方法
const mapDispatchToProps = {
addPerson: createAddPersonAction,
};
export default connect(mapStateToProps, mapDispatchToProps)(Person);
(3)main
- 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>
);
}
}
- index.js
js
复制代码
import React from "react"; // 引入 React 核心库
import ReactDOM from "react-dom"; // 引入 ReactDOM
import App from "./App"; // 引入 App 组件
import store from "./redux/store";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);
- 安装 Edge 浏览器插件
Redux DevTools
- 安装
redux-devtools-extension 依赖
shell
复制代码
pnpm install redux-devtools-extension@2.13.8
- 使用
redux-devtools-extension 依赖
js
复制代码
// 该文件专门用于暴露一个 store 对象,整个应用只有一个 store 对象
import { createStore, applyMiddleware, combineReducers } from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
// 汇总所有的 Reducer 变为一个总的 Reducer
const reducer = combineReducers({
count: countReducer,
persons: personReducer,
});
// applyMiddleware 用于应用基于 Redux 的中间件
export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
三、React Redux 最终优化
1、redux
- constant
js
复制代码
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
- action
js
复制代码
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);
};
};
js
复制代码
import { ADD_PERSON } from "../constant";
export const createAddPersonAction = (data) => ({ type: ADD_PERSON, data });
- reducer
js
复制代码
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;
}
}
js
复制代码
import { ADD_PERSON } from "../constant";
const initState = [];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [...preState, data];
default:
return preState;
}
}
js
复制代码
import { combineReducers } from "redux";
import countReducer from "./count";
import personReducer from "./person";
export default combineReducers({
countReducer,
personReducer,
});
- store
js
复制代码
import { createStore, applyMiddleware } from "redux";
import reducer from "./reducers";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
2、container
- Count 容器组件
jsx
复制代码
import { 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.increment(value * 1);
};
// 减
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value * 1);
};
// 奇数再加
incrementIfOdd = () => {
const { value } = this.selectNumber;
const { countReducer } = this.props;
if (countReducer % 2 !== 0) {
this.props.increment(value * 1);
}
};
// 异步加
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value * 1, 500);
};
render() {
return (
<div>
<h2>当前人员数量为:{this.props.personCount}</h2>
<h2>当前求和为:{this.props.countReducer}</h2>
<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) => ({
countReducer: state.countReducer,
personCount: state.personReducer.length,
}),
{
increment: createIncrementAction,
decrement: createDecrementAction,
incrementAsync: createIncrementAsyncAction,
},
)(Count);
- Person 容器组件
jsx
复制代码
import { 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.addPerson(personObj);
this.nameNode.value = "";
this.ageNode.value = "";
};
render() {
return (
<div>
<h2>求和为 {this.props.countReducer}</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.personReducer.map((p) => {
return (
<li key={p.id}>
{p.name}--{p.age}
</li>
);
})}
</ul>
</div>
);
}
}
export default connect(
(state) => ({
countReducer: state.countReducer,
personReducer: state.personReducer,
}),
{
addPerson: createAddPersonAction,
},
)(Person);
3、main
- App 组件
js
复制代码
import { 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>
);
}
}
- index.js
js
复制代码
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"),
);