react-redux使用
npm i react-redux让 store 和 页面组件 产生关联
基本使用
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
import * as actionTypes from "./constants";
export function addCountAction(count) {
return {
type: actionTypes.ADD_COUNT,
count,
};
}
export const subCountAction = (count) => ({
type: actionTypes.SUB_COUNT,
count,
});
import * as actionTypes from "./constants";
const initState = {
count: 666,
};
function reducer(state = initState, action) {
switch (action.type) {
case actionTypes.ADD_COUNT:
return { ...state, count: state.count + action.count };
case actionTypes.SUB_COUNT:
return { ...state, count: state.count - action.count };
default:
return state;
}
}
export default reducer;
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addCountAction, subCountAction } from "../store/actionCreators";
export class About extends PureComponent {
render() {
const { count } = this.props;
return (
<div>
<h2>About Page:{count}</h2>
<div>
<button onClick={(e) => this.props.addCount(6)}>+6</button>
<button onClick={(e) => this.props.subCount(6)}>-6</button>
<button onClick={(e) => this.props.addCount(10)}>+10</button>
<button onClick={(e) => this.props.subCount(10)}>-10</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({ count: state.count });
const mapDispatchToProps = (dispatch) => ({
addCount: (num) => dispatch(addCountAction(num)),
subCount: (num) => dispatch(subCountAction(num)),
});
// connect返回值是一个高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(About);
// <About {...this.props} {...obj} />
组件中异步操作
npm i axios
代码:
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { changeBannersAction, changeRecommendsAction } from "../store/actionCreators";
import axios from "axios";
export class Category extends PureComponent {
componentDidMount() {
axios.get("http://123.207.32.32:8000/home/multidata").then((res) => {
const { banner, recommend } = res.data.data;
const banners = banner.list;
const recommends = recommend.list;
// console.log(banners, recommends);
this.props.changeBanners(banners);
this.props.changeRecommends(recommends);
});
}
render() {
return (
<div>
<h2>Category</h2>
</div>
);
}
}
const mapDispatchToProps = (dispatch) => ({
changeBanners: (banners) => dispatch(changeBannersAction(banners)),
changeRecommends: (recommends) => dispatch(changeRecommendsAction(recommends)),
});
export default connect(null, mapDispatchToProps)(Category);
Category请求数据,存储到redux,About组件展示数据(mapStateToProps)
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addCountAction, subCountAction } from "../store/actionCreators";
export class About extends PureComponent {
render() {
const { count, banners, recommends } = this.props;
return (
<div>
<h2>About Page:{count}</h2>
<div>
<button onClick={(e) => this.props.addCount(6)}>+6</button>
<button onClick={(e) => this.props.subCount(6)}>-6</button>
<button onClick={(e) => this.props.addCount(10)}>+10</button>
<button onClick={(e) => this.props.subCount(10)}>-10</button>
</div>
<div>
<h2>轮播图数据</h2>
<ul>
{banners.map((item, index) => {
return <li key={index}>{item.title}</li>;
})}
</ul>
<h2>推荐数据</h2>
<ul>
{recommends.map((item, index) => {
return <li key={index}>{item.title}</li>;
})}
</ul>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({ count: state.count, banners: state.banners, recommends: state.recommends });
const mapDispatchToProps = (dispatch) => ({
addCount: (num) => dispatch(addCountAction(num)),
subCount: (num) => dispatch(subCountAction(num)),
});
// connect返回值是一个高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(About);
// <About {...this.props} {...obj} />
import * as actionTypes from "./constants";
export const changeBannersAction = (banners) => ({
type: actionTypes.CHANGE_BANNERS,
banners,
});
export const changeRecommendsAction = (recommends) => ({
type: actionTypes.CHANGE_RECOMMENDS,
recommends,
});
export const CHANGE_BANNERS = "change_banners";
export const CHANGE_RECOMMENDS = "change_recommends";
import * as actionTypes from "./constants";
const initState = {
count: 666,
banners: [],
recommends: [],
};
function reducer(state = initState, action) {
switch (action.type) {
case actionTypes.ADD_COUNT:
return { ...state, count: state.count + action.count };
case actionTypes.SUB_COUNT:
return { ...state, count: state.count - action.count };
case actionTypes.CHANGE_BANNERS:
return { ...state, banners: action.banners };
case actionTypes.CHANGE_RECOMMENDS:
return { ...state, recommends: action.recommends };
default:
return state;
}
}
export default reducer;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
// <React.StrictMode>
<Provider store={store}>
<App />
</Provider>
// </React.StrictMode>
);
理解中间件
dispatch(function)-redux-thunk使用
npm i redux-thunk
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
Category.jsx
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { fetchDataAction } from "../store/actionCreators";
export class Category extends PureComponent {
componentDidMount() {
this.props.fetchData();
}
render() {
return (
<div>
<h2>Category</h2>
</div>
);
}
}
const mapDispatchToProps = (dispatch) => ({
fetchData: () => dispatch(fetchDataAction()),
});
export default connect(null, mapDispatchToProps)(Category);
actionCreators.js
import * as actionTypes from "./constants";
import axios from "axios";
export const changeBannersAction = (banners) => ({
type: actionTypes.CHANGE_BANNERS,
banners,
});
export const changeRecommendsAction = (recommends) => ({
type: actionTypes.CHANGE_RECOMMENDS,
recommends,
});
export const fetchDataAction = () => {
// 如果是一个普通的action,需要返回action对象
// 问题:对象中是不能直接拿到从服务器请求的异步数据的
// return {} 如果返回一个函数,那么redux是不支持的,可以使用redux-thunk解决
return (dispatch) => {
// 异步操作:网络请求
axios.get("http://123.207.32.32:8000/home/multidata").then((res) => {
const { banner, recommend } = res.data.data;
const banners = banner.list;
const recommends = recommend.list;
dispatch(changeBannersAction(banners));
dispatch(changeRecommendsAction(recommends));
});
};
};
redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
export default store;
Reducer文件拆分
combineReducers函数
自己实现:
完整拆分代码:
import { createStore, applyMiddleware, compose, combineReducers } from "redux";
import thunk from "redux-thunk";
// import reducer from "./reducer";
import countReducer from "./count";
import homeReducer from "./home";
import userReducer from "./user";
// 将多个reducer合并在一起
const reducer = combineReducers({
count: countReducer,
home: homeReducer,
user: userReducer,
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
export default store;
count文件夹
actionCreators.js
import * as actionTypes from "./constants";
export function addCountAction(count) {
return {
type: actionTypes.ADD_COUNT,
count,
};
}
export const subCountAction = (count) => ({
type: actionTypes.SUB_COUNT,
count,
});
constants.js
export const ADD_COUNT = "add_count";
export const SUB_COUNT = "sub_count";
index.js
import reducer from "./reducer";
export default reducer;
export * from "./actionCreators";
reducer.js
import * as actionTypes from "./constants";
const initState = {
count: 666,
};
function reducer(state = initState, action) {
switch (action.type) {
case actionTypes.ADD_COUNT:
return { ...state, count: state.count + action.count };
case actionTypes.SUB_COUNT:
return { ...state, count: state.count - action.count };
default:
return state;
}
}
export default reducer;
在页面组件使用
store.getState().count.count
import React, { PureComponent } from "react";
import store from "../store";
import { addCountAction } from "../store/count/actionCreators";
export class Home extends PureComponent {
constructor() {
super();
this.state = {
count: store.getState().count.count,
};
}
componentDidMount() {
store.subscribe(() => {
const state = store.getState().count;
console.log("Home subscribe state=> ", state);
this.setState({
count: state.count,
});
});
}
addCount(num) {
store.dispatch(addCountAction(num));
}
render() {
const { count } = this.state;
return (
<div>
<h2>Home count:{count}</h2>
<div>
<button onClick={(e) => this.addCount(1)}>+1</button>
<button onClick={(e) => this.addCount(5)}>+5</button>
<button onClick={(e) => this.addCount(10)}>+10</button>
</div>
</div>
);
}
}
export default Home;