redux
求和redux_mini版
一、去除组件自身的状态,交给redux来管理
二、在src
文件下创建redux
文件夹,在该文件夹中创建store.js
、count_reducer.js
两个文件
三、store.js
:
-
引入
redux
中的createStore
函数,创建一个store
-
createStore
调用时传入一个为其服务的reducer
-
记得暴露
store
对象
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore } from "redux";
// 引入为Count组件服务的Reducer
import countReducer from "./count_reducer";
// 暴露store
const store = createStore(countReducer);
export default store;
四、count_reducer.js
:
-
reducer
的本质是一个函数,接收两个参数:preState
,action
,并且返回一个加工后的状态 -
reducer
有两个作用:初始化状态,加工状态 -
reducer
第一次被调用,是store
自动触发的,传递的preState
是undefined
count_reducer.js:
// 该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
// reducer函数会接收两个参数,分别是之前的状态(preState),动作对象(action)
// 设置初始值
const initState = 0;
export default function countReducer(preState = initState, action) {
// console.log(preState, action);
// 从action中获取动作类型type和数据data
const { type, data } = action;
// 根据type判断如何加工数据
switch (type) {
case "increment":
return preState + data * 1;
case "decrement":
return preState - data * 1;
default:
return preState;
}
}
五、api:
-
store.getState()
:用于获取数据 -
store.dispatch({type:'xxx',data:xxx})
:用来使用定义的方法 -
store.subscribe(()=>{})
:用来数据更新后render
count.jsx:
//使用
const increment = () => {
store.dispatch({
type: "increment",
data: value * 1,
});
};
//获取数据
<h1>当前求和为:{store.getState()}</h1>
index.js:
// 用于数据更新后render
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById("root"));
});
完整版
基于上面的迷你版,增加了两个文件:
-
count_action.js
:用来生成action
,交给store.dispatch
使用 -
constant.js
:用来定义变量方便管理和防止程序员单词写错
store.js:
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore } from "redux";
// 引入为Count组件服务的Reducer
import countReducer from "./count_reducer";
// 暴露store
const store = createStore(countReducer);
export default store;
count_reducer.js:
// 该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
// reducer函数会接收两个参数,分别是之前的状态(preState),动作对象(action)
// 设置初始值
import { INCREMENT, DECREMENT } from "./constant";
const initState = 0;
export default function countReducer(preState = initState, action) {
// console.log(preState, action);
// 从action中获取动作类型type和数据data
const { type, data } = action;
// 根据type判断如何加工数据
switch (type) {
case INCREMENT:
return preState + data * 1;
case DECREMENT:
return preState - data * 1;
default:
return preState;
}
}
constant.js:
// 该文件是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
count_action.js:
// 该文件专门为count组件生成action对象
import { INCREMENT, DECREMENT } from "./constant";
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
count.jsx:
import store from "../../redux/store";
import {
createIncrementAction,
createDecrementAction,
} from "../../redux/count_action";
//使用
const increment = () => {
store.dispatch(createIncrementAction(value * 1));
};
const decrement = () => {
store.dispatch(createDecrementAction(value * 1));
};
//获取数据
<h1>当前求和为:{store.getState()}</h1>
index.js:
// 用于数据更新后render
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById("root"));
});
实现异步action
-
当延迟的动作不想交给组件自身,想交给
action
-
何时需要异步
action
:想要对状态进行操作,但是具体的数据靠异步任务返回 -
具体编码:
-
yarn add redux-thunk
,并配置在store
中,使用redux
中的中间件applyMiddleware
-
创建
action
的函数不在返回一个对象,而是一个函数,该函数中写异步任务 -
异步任务有结果后,分发一个同步的
action
去真正操作数据
-
-
备注:异步
action
不是必须要写,完全可以直接等待异步任务结束再去分发同步action
store.js:
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore, applyMiddleware } from "redux";
// 引入为Count组件服务的Reducer
import countReducer from "./count_reducer";
import thunk from "redux-thunk";
// 暴露store
const store = createStore(countReducer, applyMiddleware(thunk));
export default store;
count_reducer.js:
// 该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
// reducer函数会接收两个参数,分别是之前的状态(preState),动作对象(action)
// 设置初始值
import { INCREMENT, DECREMENT } from "./constant";
const initState = 0;
export default function countReducer(preState = initState, action) {
// console.log(preState, action);
// 从action中获取动作类型type和数据data
const { type, data } = action;
// 根据type判断如何加工数据
switch (type) {
case INCREMENT:
return preState + data * 1;
case DECREMENT:
return preState - data * 1;
default:
return preState;
}
}
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
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
count.jsx:
import store from "../../redux/store";
import {
createIncrementAction,
createDecrementAction,
} from "../../redux/count_action";
//使用
const increment = () => {
store.dispatch(createIncrementAction(value * 1));
};
const decrement = () => {
store.dispatch(createDecrementAction(value * 1));
};
//获取数据
<h1>当前求和为:{store.getState()}</h1>
index.js:
// 用于数据更新后render
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById("root"));
});
react-redux
基本使用
一、将CountUI组件中与redux的使用全部删除
二、创建Count容器组件:
-
引入Count的UI组件
-
引入connect用于连接UI组件和redux中store
-
使用connect()()创建容器组件CountContainer
-
将容器组件暴露出去
// 引入Count的UI组件
import CountUI from "../../components/Count";
// 引入connect用于连接UI组件和redux中store
import { connect } from "react-redux";
//使用connect()()创建容器组件CountContainer
const CountContainer = connect()(CountUI);
// 将容器组件暴露出去
export default CountContainer;
三、在App.js中不再引入CountUI组件而是引入Count容器组件,再引入store,将store通过props传递
import React from "react";
// import Count from "./components/Count";
// 引入容器组件
import Count from "./containers/Count";
import store from "./redux/store";
export default function App() {
return (
<>
<Count store={store} />
</>
);
}
四、在Count容器组件中定义两个方法,并且将这两个方法传递给connect方法中
-
mapStateToProps():将redux中的状态传递给CountUI组件
-
mapDispatchToProps():将操作状态的方法传递给CountUI组件
// 引入Count的UI组件
import CountUI from "../../components/Count";
// 引入connect用于连接UI组件和redux中store
import { connect } from "react-redux";
//引入action
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
// 该函数中返回的对象是传递给CountUI组件的数据,相当于<CountUI n={900} />
// react-redux在调用该函数时会自动调用store.getState()函数,并且将返回的值传递给了该函数,即state
function mapStateToProps(state) {
return { count: state };
}
// 该函数中返回的对象是传递给CountUI组件的方法,相当于<CountUI jia={()=>{}} />
//同样也会接收一个参数,该参数也是由react-redux调用传递过来的,用来操作store中的方法,即dispatch
function mapDispatchToProps(dispatch) {
return {
jia: (data) => dispatch(createIncrementAction(data)),
jian: (data) => dispatch(createDecrementAction(data)),
jiaAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),
};
}
//使用connect()()创建容器组件CountContainer
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(CountUI);
// 将容器组件暴露出去
export default CountContainer;
五、CountUI组件可以从props接收到Count容器组件传递过来的数据和方法,即redux中的数据和操作redux中数据的方法
const { store, count, jia, jian, jiaAsync } = props;
const increment = () => {
jia(value);
};
<h1>当前求和为:{count}</h1>
优化
mapDistatchToProps简化
初始:
// 该函数中返回的对象是传递给CountUI组件的数据,相当于<CountUI n={900} />
// react-redux在调用该函数时会自动调用store.getState()函数,并且将返回的值传递给了该函数,即state
function mapStateToProps(state) {
return { count: state };
}
// 该函数中返回的对象是传递给CountUI组件的方法,相当于<CountUI jia={()=>{}} />
//同样也会接收一个参数,该参数也是由react-redux调用传递过来的,用来操作store中的方法,即dispatch
function mapDispatchToProps(dispatch) {
return {
jia: (data) => dispatch(createIncrementAction(data)),
jian: (data) => dispatch(createDecrementAction(data)),
jiaAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),
};
}
//使用connect()()创建容器组件CountContainer
const CountContainer = connect(mapStateToProps, mapDispatchToProps)(CountUI);
// 将容器组件暴露出去
export default CountContainer;
简写:
const CountContainer = connect(
(state) => ({ count: state }),
// mapDispatchToProps一般写法
// (dispatch) => ({
// jia: (data) => dispatch(createIncrementAction(data)),
// jian: (data) => dispatch(createDecrementAction(data)),
// jiaAsync: (data, time) => dispatch(createIncrementAsyncAction(data, time)),
// })
// mapDispatchToProps精简写法
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(CountUI);
export default CountContainer;
Provider
-
在index.js文件中不用再使用store.subscribe()方法,react-redux会自动检测
-
在App.jsx文件中不需要挨个组件传递store,而是在index.js中使用react-redux中的Provider来自动精准分配store
App.jsx:
import React from "react";
// 引入容器组件
import Count from "./containers/Count";
export default function App() {
return (
<>
<Count />
</>
);
}
index.js:
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import App from "./App";
import store from "./redux/store";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
整合组件
将CountUI组件和Count容器组件整合在同一个文件中
import { connect } from "react-redux";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
import React, { useState } from "react";
//CountUI组件
function Count(props) {
......
}
//Count容器组件
const CountContainer = connect(
(state) => ({ count: state }),
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count);
export default CountContainer;
数据共享
一、创建Count、Person的相对应的action和reducer
- Count:
action:
// 该文件专门为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
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
reducer:
// 该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
// reducer函数会接收两个参数,分别是之前的状态(preState),动作对象(action)
// 设置初始值
import { INCREMENT, DECREMENT } from "../constant";
const initState = 0;
export default function countReducer(preState = initState, action) {
// 从action中获取动作类型type和数据data
const { type, data } = action;
// 根据type判断如何加工数据
switch (type) {
case INCREMENT:
return preState + data * 1;
case DECREMENT:
return preState - data * 1;
default:
return preState;
}
}
- Person:
action:
import { ADD_PERSON } from "../constant";
// 创建增加一个人的action动作对象
export const createAddPersonAction = (personObj) => ({
type: ADD_PERSON,
data: personObj,
});
reducer:
import { ADD_PERSON } from "../constant";
const initState = [{ name: "tom", age: 18 }];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [...preState, data];
default:
return preState;
}
}
二、定义变量
// 该文件是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
三、将countReducer和personReducer整合
- 使用react-redux中的combineReducers整合,写成对象的形式
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore, applyMiddleware, combineReducers } from "redux";
// 引入为Count组件服务的Reducer
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
// 整合全部reducer变成一个总的reducer
const allReducer = combineReducers({
count: countReducer,
personList: personReducer,
});
// 暴露store
const store = createStore(allReducer, applyMiddleware(thunk));
export default store;
四、创建Count,Person容器组件和UI组件
Count.jsx:
import { connect } from "react-redux";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/actions/count";
import React, { useState } from "react";
//CountUI组件
function Count(props) {
......
}
//Count容器组件
const CountContainer = connect(
//获取redux中的count和personList数据
(state) => ({ count: state.count, personList: state.personList }),
{
jia: createIncrementAction,
jian: createDecrementAction,
jiaAsync: createIncrementAsyncAction,
}
)(Count);
export default CountContainer;
Person.jsx:
import React, { useState } from "react";
import { connect } from "react-redux";
import { createAddPersonAction } from "../../redux/actions/person";
//PersonUI组件
function Person(props) {
......
}
//Person容器组件
export default connect(
//获取redux中的count和personList数据
(state) => ({
personList: state.personList,
count: state.count,
}),
{
add: createAddPersonAction,
}
)(Person);
六、此时两边的组件都可以相互读取各自存放在redux中的数据
redux开发者工具
一、谷歌浏览器安装插件
二、在项目的终端中运行yarn add redux-devtools-extension
三、在store.js文件中引入并使用
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象
// 引入createStore,专门用于创建redux中最为核心的store对象
import { createStore, applyMiddleware, combineReducers } from "redux";
// 引入为Count组件服务的Reducer
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
//引入开发者工具
import { composeWithDevTools } from "redux-devtools-extension";
// 整合全部reducer变成一个总的reducer
const allReducer = combineReducers({
count: countReducer,
personList: personReducer,
});
// 暴露store
const store = createStore(
allReducer,
//使用开发者工具
composeWithDevTools(applyMiddleware(thunk))
);
export default store;