中文文档:http://www.redux.org.cn/
英文文档:https://redux.js.org/
Github:https://github.com/reactjs/redux
可直接参照 目录十 进行使用 react-redux
store.dispatch()
将 action 传到 store。type
:标识属性, 值为字符串, 唯一, 必要属性。data
:数据属性, 值类型任意, 可选属性之前的状态
、动作对象
。preState
(之前的状态) 是undefined
store.getState()
store.dispatch(action)
store.subscribe(() => { });
store.subscribe
componentDidMount() {// 监听redux中状态的变化,只要变化,就调用renderstore.subscribe(() => {//状态假更新,每次状态更新都会调用renderthis.setState({});});
}
(2)在 index.js 文件中检测 store 中状态的改变,一旦发生改变重新渲染
import React from "react";
import reactDOM from "react-dom";
import App from "./App";
import store from "./redux/store";
reactDOM.render( , document.getElementById("root"));
// store中状态改变,重新渲染dom
store.subscribe(() => {reactDOM.render( , document.getElementById("root"));
});
redux
文件夹,并在 redux 文件夹中创建两个文件,分别是:store.js
、count_reducer.js
,对应store,reducer1.引入redux中的createState函数,创建一个store
2. createState调用时,要传入一个为其服务的reducer
3. 记得暴露 store
/*** 该文件专门用于暴露一个store对象,整个应用只有一个store对象*/
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore } from "redux";
// 引入为count组件服务的reducer
import countReducer from "./count_reducer";const store = createStore(countReducer);
export default store;
/*** 1. 该文件是用于创建一个为为Count组件服务的reducer,reducer的本质是一个函数* 2. reducer函数会接收到两个参数,分别为:之前的状态(preState),动作对象(action)*/
const intState = 0; //初始化状态
// preState===undefined时,preState = intState
export default function countReducer(preState = intState, action) {// 从action对象中获取:type,dataconst { type, data } = action;// 根据type决定加工数据switch (type) {// 加case "increment":return preState + data;// 减case "decrement":return preState - data;default:return preState;}
}
- 获取状态:store.getState()
- 改变状态:store.dispatch({ type: “方法类型”, data: 需要操作的数据 })
- 状态改变后重新渲染
import React, { Component } from "react";
// 引入store,用于获取redux中保存的状态
import store from "../../redux/store";export default class Count extends Component {/*** 在index.js中监听状态改变进行渲染,一劳永逸*/// componentDidMount() {// // 监听redux中状态的变化,只要变化,就调用render// store.subscribe(() => {// // 假更新// this.setState({});// });// }// 加法increment = () => {const { value } = this.selectNumber;store.dispatch({ type: "increment", data: value * 1 });};// 减法decrement = () => {const { value } = this.selectNumber;store.dispatch({ type: "decrement", data: value * 1 });};// 奇数再加incrementIfOdd = () => {const { value } = this.selectNumber;const count = store.getState();if (count % 2 !== 0) {store.dispatch({ type: "increment", data: value * 1 });}};// 异步加incrementAsync = () => {const { value } = this.selectNumber;setTimeout(() => {store.dispatch({ type: "increment", data: value * 1 });}, 500);};render() {return (当前求和为:{store.getState()}
);}
}
constant.js
、count__action.js
/*** 该模块用于定义action对象中type类型的常量值* 目的只有一个:便于管理的同时防止程序员单词写错*/
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
/*** 该文件专门为Count组件生成action对象*/
import { INCREMENT, DECREMENT } from "./constant";// 正常方式
// export const createIncrementAction = (data) => {
// return { type: "increment", data };
// };
// 简写方式
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
/*** 1. 该文件是用于创建一个为为Count组件服务的reducer,reducer的本质是一个函数* 2. reducer函数会接收到两个参数,分别为:之前的状态(preState),动作对象(action)*/
import { INCREMENT, DECREMENT } from "./constant";const intState = 0; //初始化状态
export default function countReducer(preState = intState, action) {// 从action对象中获取:type,dataconst { type, data } = action;// 根据type决定加工数据switch (type) {// 加case INCREMENT:return preState + data;// 减case DECREMENT:return preState - data;default:return preState;}
}
import React, { Component } from "react";
// 引入store,用于获取redux中保存的状态
import store from "../../redux/store";
// 引入actionCreator,专门用于创建action对象
import {createIncrementAction,createDecrementAction,
} from "../../redux/count_action";export default class Count extends Component {// 加法increment = () => {const { value } = this.selectNumber;store.dispatch(createIncrementAction(value * 1));};// 减法decrement = () => {const { value } = this.selectNumber;store.dispatch(createDecrementAction(value * 1));};// 奇数再加incrementIfOdd = () => {const { value } = this.selectNumber;const count = store.getState();if (count % 2 !== 0) {store.dispatch(createIncrementAction(value * 1));}};// 异步加incrementAsync = () => {const { value } = this.selectNumber;setTimeout(() => {store.dispatch(createIncrementAction(value * 1));}, 500);};render() {return (当前求和为:{store.getState()}
);}
}
redux-thunk
yarn add redux-thunk
redux-thunk
/*** 该文件专门用于暴露一个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";const store = createStore(countReducer, applyMiddleware(thunk));
export default store;
异步action
/*** 该文件专门为Count组件生成action对象*/
import { INCREMENT, DECREMENT } from "./constant";
/*** 同步action,就是指action的值为Object类型的一般对象*/
// 正常方式
// export const createIncrementAction = (data) => {
// return { type: "increment", data };
// };
// 简写方式
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(() => {// 异步任务有结果后,分发一个同步的action去真正操作数据dispatch(createIncrementAction(data));}, time);};
};
异步action
// 引入actionCreator,专门用于创建action对象
import {createIncrementAction,createDecrementAction,createIncrementAsyncAction,
} from "../../redux/count_action";// 异步加
incrementAsync = () => {const { value } = this.selectNumber;// setTimeout(() => {store.dispatch(createIncrementAsyncAction(value * 1, 500));// }, 500);
};
yarn add react-redux
1.在 src 文件夹下创建一个
containers
容器文件夹
2.containers 文件夹中创建一个Count
文件夹
3.Count 文件夹下创建一个index.jsx
文件
// 引入Count的UI组件
import CountUI from "../../components/Count";
// 引入connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import {createIncrementAction,createDecrementAction,createIncrementAsyncAction,
} from "../../redux/count_action";/*** 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 {add: (data) => {// 通知redux执行方法dispatch(createIncrementAction(data));},delete: (data) => dispatch(createDecrementAction(data)),addAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),};
}
// 使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
import React, { Component } from "react";
import Count from "./containers/Count";
import store from "./redux/store";export default class App extends Component {render() {return ({/* 给容器组件传递store */}store} /> );}
}
this.props
方式 this.props.count
mapDispatchToProps
中的方法this.props.add(value * 1);
容器组件 和 UI组件 合并成一个组件
connect
模板:
export default connect((state) => ({ key: value }),//映射状态{ key: action方法, }//映射操作状态的方法
)(UI组件);
1.将 src/component/Count/index.jsx 中的内容 剪切放入 src/container/Count/index.jsx 中
2.并删除 src/component 中的Count组件
3.优化connect()()
写法,简化mapDispatchToProps
写法
import React, { Component } from "react";
// 引入connect用于连接UI组件与redux
import { connect } from "react-redux";
// 引入action
import {createIncrementAction,createDecrementAction,createIncrementAsyncAction,
} from "../../redux/count_action";class Count extends Component {// 加法increment = () => {const { value } = this.selectNumber;this.props.add(value * 1);};// 减法decrement = () => {const { value } = this.selectNumber;this.props.delete(value * 1);};// 奇数再加incrementIfOdd = () => {const { value } = this.selectNumber;if (this.props.count % 2 !== 0) {this.props.add(value * 1);}};// 异步加incrementAsync = () => {const { value } = this.selectNumber;this.props.addAsync(value * 1,500);};render() {console.log("UI组件接收到的props值:", this.props);return (当前求和为:{this.props.count}
);}
}/*** 拆分函数写法
// 映射状态
const mapStateToProps = (state) => ({ count: state });
// 映射操作状态的方法
const mapDispatchToProps = (dispatch) => ({add: (data) => dispatch(createIncrementAction(data)),delete: (data) => dispatch(createDecrementAction(data)),addAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),
});// 使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Count);
*//*** 合并函数写法*/
// 使用connect()()创建并暴露一个Count的容器组件
export default connect((state) => ({ count: state }),// mapDispatchToProps 的一般写法// (dispatch) => ({// add: (data) => dispatch(createIncrementAction(data)),// delete: (data) => dispatch(createDecrementAction(data)),// addAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),// })// mapDispatchToProps 的简写{add: createIncrementAction,delete: createDecrementAction,addAsync: createIncrementAsyncAction,}
)(Count);
修改 App.jsx,无需自己给容器组件传递store
import React, { Component } from "react";
import Count from "./containers/Count";export default class App extends Component {render() {return ( );}
}
修改 index.js 文件
1.去除
store.subscribe(() => { });
状态监听
2.给包裹一个
标签
Provider
:让所有组件都可以得到state数据
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(store}> ,document.getElementById("root")
);
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
actions
文件夹,将所有的 action文件 放入。在其中创建一个person
的 action文件,用于为 person组件 的 reducer服务。import { ADD_PERSON } from "../constant";// 创建增加一个人的action对象
export const creactAddPersonAction = (personObj) => {return { type: ADD_PERSON, data: personObj };
};
reducers
文件夹,将所有的 reducers文件 放入。在其中创建一个 person
的reducers文件import { ADD_PERSON } from "../constant";
// 初始化人员列表
const initState = [{ id: 1, name: "tom", age: 20 }];
export default function personReducer(preState = initState, action) {console.log('person')const { type, data } = action;switch (type) {// 添加case ADD_PERSON:return [data, ...preState];default:return preState;}
}
combineReducers
,用于汇总所有的reducer,变为一个整的reducer/*** 该文件专门用于暴露一个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
const allReducer = combineReducers({total:countReducer,persons:personReducer
})
const store = createStore(allReducer, applyMiddleware(thunk));
export default store;
取出 redux 状态时,要取到对象组件的key值
import React, { Component } from "react";
import { connect } from "react-redux";
import { creactAddPersonAction } from "../../redux/actions/person";class Person extends Component {addPerson = () => {const name = this.nameNode.value;const age = this.ageNode.value;const id = this.props.personList.length + 1;let personObj = {id,name,age,};this.props.addPerson(personObj);this.nameNode.value = "";this.ageNode.value = "";};render() {return (Person 组件
上方Count组件的总和为:{this.props.total}
(cur) => (this.nameNode = cur)}type="text"placeholder="请输入姓名"/>(cur) => (this.ageNode = cur)}type="text"placeholder="请输入年龄"/>{this.props.personList.map((v) => {return (- v.id}>姓名:{v.name},年龄:{v.age}
);})}
);}
}const mapStateToProps = (state) => ({personList: state.persons,total: state.total,
});const mapDispatchToProps = {addPerson: creactAddPersonAction,
};export default connect(mapStateToProps, mapDispatchToProps)(Person);
reducer
时// 引入combineReducers,用于汇总所有的reducer
import { combineReducers } from "redux";
// 引入为count组件服务的reducer
import count from "./count";
// 引入Person组件服务的reducer
import persons from "./person";
// 汇总所有的reducer,变为一个整的reducer
const allReducer = combineReducers({count,persons,
});export default allReducer;
import { addPerson } from "../../redux/actions/person";
const mapStateToProps = (state) => ({personList: state.persons,total: state.count,
});const mapDispatchToProps = {addPerson,
};export default connect(mapStateToProps, mapDispatchToProps)(Person);
/*** 该文件用于汇总所有的reducer为一个总的reducer*/
// 引入combineReducers,用于汇总所有的reducer
import { combineReducers } from "redux";
// 引入为count组件服务的reducer
import count from "./count";
// 引入Person组件服务的reducer
import persons from "./person";
// 汇总所有的reducer,变为一个整的reducer
const allReducer = combineReducers({count,persons,
});export default allReducer;
store.js 文件中使用// 引入汇总之后的reducer
import allReducer from "./reducers";const store = createStore(allReducer,applyMiddleware(thunk)
);
export default store;
浏览器拓展程序引入 Redux DevTools
项目中安装 redux-devtools-extension
yarn add redux-devtools-extension
配置store.js文件
// 引入 redux-devtools-extension
import { composeWithDevTools } from "redux-devtools-extension";
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))
);
src 文件夹下创建一个
redux
文件夹
redux 文件夹下创建actions
文件夹、reducers
文件夹、constans.js
文件、store.js
文件
reducers 文件夹下创建index.js
文件
redux 文件层级:
- src- redux- actions- reducers- index.js- constans.js- store.js
actions 文件夹
:reducers 文件夹
:reducers/index.js 文件
:constans.js 文件
:store.js 文件
:
- 安装 redux
用于创建redux中最为核心的store对象
yarn add redux react-redux
- 安装 redux-thunk
用于支持异步 action
yarn add redux-thunk
- 安装 redux-devtools-extension
用于支持 react-redux 开发者工具的使用
yarn add redux-devtools-extension
// 引入combineReducers,用于汇总所有的reducer
import { combineReducers } from "redux";// 汇总所有的reducer,变为一个整的reducer
const allReducer = combineReducers({});export default allReducer;
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore, applyMiddleware } from "redux";
// 引入redux-thunk,用于支持异步action
import thunk from "redux-thunk";
// 引入 redux-devtools-extension
import { composeWithDevTools } from "redux-devtools-extension";
// 引入汇总之后的reducer
import allReducer from "./reducers";const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))
);
export default store;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import store from "./redux/store";const root = ReactDOM.createRoot(document.getElementById("root"));
root.render({/* 此处需要用 Provider 包裹 App,目的是让 App 所有的后代容器组件都能接收到store */}{/* 可代替下方 store.subscribe(),实现自动监听 */}store}>
);
// 监测redux中状态的改变, 若redux中的状态发生了改变,则重新渲染App组件
// store.subscribe(() => {
// root.render(
//
//
//
// );
// });
reportWebVitals();
实现一个数值 加减 的组件
(Count 组件)
src/redux/constants.js 文件修改,添加方法常量
// 定义action对象中type类型的常量值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
src/redux/actions 文件夹新增 count.js
,对应 Count 组件 的 action
import { INCREMENT, DECREMENT } from "../constants.js";// 加
// 简写方式
// export const increment = (data) => ({ type: INCREMENT, data });
// 正常方式
export const increment = (data) => {return {type: INCREMENT,data,};
};
// 减
export const decrement = (data) => {return {type: DECREMENT,data,};
};
src/redux/reducers 文件夹新增 count.js
,对应 Count 组件 的 reducer
/*** 1. 该文件是用于创建一个为为Count组件服务的reducer,reducer的本质是一个函数* 2. reducer函数会接收到两个参数,分别为:之前的状态(preState),动作对象(action)*/
import { DECREMENT, INCREMENT } from "../constants.js";const initState = 0; //初始化状态
// 当第一次 preState 为 undefined 时,preState 赋值等于 initState
export default function increment(preState = initState, action) {// 从 action 对象中获取:type,dataconst { type, data } = action;// 根据 type 决定加工数据switch (type) {case INCREMENT:return preState + data;case DECREMENT:return preState - data;default:return preState;}
}
src/redux/reducers/index.js 文件修改,添加合并 Count 组件 的 reducer
Count 组件中 引入 connect
生成一个容器组件,并暴露。通过this.props....
读取和操作状态。
容器组件写法:
export default connect((state) => ({ key: value }),//映射状态{ key: action方法, }//映射操作状态的方法
)(UI组件);
import React, { Component } from "react";
import { connect } from "react-redux";
import { increment, decrement } from "../../redux/actions/count";class Count extends Component {incrementNumber = () => {this.props.increment(1);};decrementNumber = () => {this.props.decrement(1);};render() {console.log(this.props);return (当前数值:{this.props.num}
);}
}
/*** 映射状态,组件中需要使用的 reducer 状态* state.xxx key 对应 src/redux/reducers/index.js 中 allReducer 对应组件的 key*/
const mapStateToProps = (state) => ({ num: state.count
});
// 映射操作状态的方法,组件中需要使用的事件方法
const mapDispatchToProps = {increment,decrement,
};
// 使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Count);
实现一个人员信息列表 新增 功能
(Persons 组件)
步骤同 3.1 Conut 组件实例 相同
src/redux/constants.js 文件修改,添加方法常量
// 定义action对象中type类型的常量值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";export const ADD_PERSON = "add_person";
src/redux/actions 文件夹新增 persons.js
,对应 Persons 组件 的 action
import { ADD_PERSON } from "../constants.js";// 新增人员
export const addPerson = (data) => ({ type: ADD_PERSON, data });
src/redux/reducers 文件夹新增 persons.js
,对应 Persons 组件 的 reducer
import { ADD_PERSON } from "../constants.js";const initState = [{id: 1,name: "小明",age: 18,},
];
export default function addPerson(preState = initState, action) {const { type, data } = action;// 根据 type 决定加工数据switch (type) {case ADD_PERSON:return [data, ...preState];default:return preState;}
}
src/redux/reducers/index.js 文件修改,添加合并 Persons 组件 的 reducer
Persons 组件 中 引入 connect
生成一个容器组件,并暴露。通过this.props....
读取和操作状态。
import React, { Component } from "react";
import { connect } from "react-redux";
// 引入 action
import { addPerson } from "../../redux/actions/persons.js";class Persons extends Component {add = () => {const name = this.nameNode.value;const age = this.ageNode.value * 1;const personObj = {id: this.props.personList.length + 1,name,age,};this.props.addPerson(personObj);};render() {console.log(this.props);return ((cur) => (this.nameNode = cur)}type="text"placeholder="请输入姓名"/> (cur) => (this.ageNode = cur)}type="number"placeholder="请输入年龄"/> {this.props.personList.map((v) => {return (- v.id}>姓名:{v.name},年龄:{v.age}
);})}
);}
}
/*** 映射状态,组件中需要使用的 reducer 状态* state.xxx key 对应 src/redux/reducers/index.js 中 allReducer 对应组件的 key*/
const mapStateToProps = (state) => ({ personList: state.persons
});
// 映射操作状态的方法,组件中需要使用的事件方法
const mapDispatchToProps = {addPerson,
};
// 使用connect()()创建并暴露一个Persons的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Persons);
Count组件
mapStateToProps
中映射 Person组件 的状态
render()
中渲染
Persons组件
mapStateToProps
中映射 Count组件 的状态
render()
中渲染