认识Redux Toolkit
创建新项目:
create-react-app 009learn-reduxtoolkit
npm i @reduxjs/toolkit react-redux
RTK基本使用
createSlice
configureStore
代码: 从下至上
.panel {
display: flex;
}
.panel > div {
flex: 1;
padding: 20px;
border: 2px solid magenta;
}
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(
<Provider store={store}>
<App />
</Provider>
);
import React, { PureComponent } from "react";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import "./style.css";
import { connect } from "react-redux";
export class App extends PureComponent {
render() {
const { count } = this.props;
return (
<div>
<div>App count:{count}</div>
<div className="panel">
<Home />
<Profile />
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
export default connect(mapStateToProps, null)(App);
import { configureStore } from "@reduxjs/toolkit";
import countReducer from "./features/count";
const store = configureStore({
reducer: {
count: countReducer,
},
});
export default store;
import { createSlice } from "@reduxjs/toolkit";
const countSlice = createSlice({
name: "count",
initialState: {
count: 999,
},
reducers: {
addCount(state, { payload }) {
state.count += payload;
},
subCount(state, { payload }) {
state.count -= payload;
},
},
});
export const { addCount, subCount } = countSlice.actions;
export default countSlice.reducer;
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { subCount } from "../store/features/count";
export class Profile extends PureComponent {
render() {
const { count } = this.props;
return (
<div>
Profile count:{count}
<div>
<button onClick={(e) => this.props.subCount(1)}>-1</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
const mapDispatchToProps = (dispatch) => ({
subCount: (count) => dispatch(subCount(count)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addCount } from "../store/features/count";
export class Home extends PureComponent {
render() {
const { count } = this.props;
return (
<div>
Home count:{count}
<div>
<button onClick={(e) => this.props.addCount(1)}>+1</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
const mapDispatchToProps = (dispatch) => ({
addCount: (count) => dispatch(addCount(count)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
RTK异步操作
- const asyncAction = createAsyncThunk('actionName',async()=>{})
- 三种状态(pending,fulfilled,rejected)
- extraReducers
RTK其它两个用法
- extraReducers:(builder)=>{builder.addCase}
- createAsyncThunk('name',async (extraInfo,store)=>{})
RTK的数据不可变性
代码从上到下:
Home页面获取数据,存储到redux,在Profile组件展示数据
import React, { PureComponent } from "react";
// import { connect } from "react-redux";
import { connect } from "../hoc";
import { addCount } from "../store/features/count";
import { fetchDataAction } from "../store/features/home";
export class Home extends PureComponent {
componentDidMount() {
this.props.fetchData();
}
render() {
const { count } = this.props;
return (
<div>
Home count:{count}
<div>
<button onClick={(e) => this.props.addCount(1)}>+1</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
const mapDispatchToProps = (dispatch) => ({
addCount: (count) => dispatch(addCount(count)),
fetchData: () => dispatch(fetchDataAction({ name: "zm", age: 21 })),
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
import React, { PureComponent } from "react";
// import { connect } from "react-redux";
import { connect } from "../hoc";
import { subCount } from "../store/features/count";
export class Profile extends PureComponent {
render() {
const { count, banners, recommends } = this.props;
return (
<div>
Profile count:{count}
<div>
<button onClick={(e) => this.props.subCount(1)}>-1</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.count,
banners: state.home.banners,
recommends: state.home.recommends,
});
const mapDispatchToProps = (dispatch) => ({
subCount: (count) => dispatch(subCount(count)),
});
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
import { createSlice } from "@reduxjs/toolkit";
const countSlice = createSlice({
name: "count",
initialState: {
count: 999,
},
reducers: {
addCount(state, { payload }) {
state.count += payload;
},
subCount(state, { payload }) {
state.count -= payload;
},
},
});
export const { addCount, subCount } = countSlice.actions;
export default countSlice.reducer;
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import axios from "axios";
export const fetchDataAction = createAsyncThunk("fetch/homedata", async (extraInfo, { dispatch, getState }) => {
console.log("extraInfo,dispatch,getState=> ", extraInfo, dispatch, getState);
// 1.发送网络请求,获取数据
const res = await axios.get("http://123.207.32.32:8000/home/multidata");
console.log("res.data=> ", res.data);
// 2.取出数据,并且在此处直接dispatch操作(可选)
// const banners = res.data.data.banner.list;
// const recommends = res.data.data.recommend.list;
// dispatch(changeBanners(banners));
// dispatch(changeRecommends(recommends));
// 3.返回结果,那么action状态会变成fulfilled状态
return res.data;
});
const homeSlice = createSlice({
name: "home",
initialState: {
banners: [],
recommends: [],
},
reducers: {
// 同步
changeBanners(state, { payload }) {
state.banners = payload;
},
changeRecommends(state, { payload }) {
state.recommends = payload;
},
},
// extraReducers: {
// [fetchDataAction.pending](state, action) {
// console.log("fetchDataAction pending");
// },
// [fetchDataAction.fulfilled](state, { payload }) {
// console.log("payload是fetchDataAction()返回值=> ", fetchDataAction(), payload);
// console.log("fetchDataAction fulfilled");
// state.banners = payload.data.banner.list;
// state.recommends = payload.data.recommend.list;
// },
// [fetchDataAction.rejected](state, action) {
// console.log("fetchDataAction rejected");
// },
// },
extraReducers: (builder) => {
// 异步
builder
.addCase(fetchDataAction.pending, (state, action) => {
console.log("fetchDataAction pending");
})
.addCase(fetchDataAction.fulfilled, (state, { payload }) => {
state.banners = payload.data.banner.list;
state.recommends = payload.data.recommend.list;
});
},
});
export const { changeBanners, changeRecommends } = homeSlice.actions;
export default homeSlice.reducer;
import { configureStore } from "@reduxjs/toolkit";
import countReducer from "./features/count";
import homeReducer from "./features/home";
const store = configureStore({
reducer: {
count: countReducer,
home: homeReducer,
},
});
export default store;
import React, { PureComponent } from "react";
import Home from "./pages/Home";
import Profile from "./pages/Profile";
import "./style.css";
import { connect } from "react-redux";
export class App extends PureComponent {
render() {
const { count } = this.props;
return (
<div>
<div>App count:{count}</div>
<div className="panel">
<Home />
<Profile />
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
export default connect(mapStateToProps, null)(App);
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
import { StoreContext } from "./hoc/StoreContext";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<StoreContext.Provider value={store}>
<App />
</StoreContext.Provider>
</Provider>
);
图片:
手写connect,provider
import { PureComponent } from "react";
// import store from "../store";
import { StoreContext } from "./StoreContext";
/**
*
* @param {函数} mapStateToProps
* @param {函数} mapDispatchToProps
* @returns 函数=>高阶组件
*/
export function connect(mapStateToProps, mapDispatchToProps) {
//返回高级组件:函数
return function (OriginCpn) {
class NewCpn extends PureComponent {
constructor(props, context) {
super(props);
// this.state = mapStateToProps(store.getState());
this.state = mapStateToProps(context.getState());
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
// this.forceUpdate()
this.setState(mapStateToProps(this.context.getState()));
});
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const stateObj = mapStateToProps(this.context.getState());
const dispatchObj = mapDispatchToProps(this.context.dispatch);
return <OriginCpn {...this.props} {...stateObj} {...dispatchObj} />;
}
}
NewCpn.contextType = StoreContext;
return NewCpn;
};
}
export { connect } from "./connect";
export { StoreContext } from "./StoreContext";
import { createContext } from "react";
export const StoreContext = createContext();
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
import { StoreContext } from "./hoc/StoreContext";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<StoreContext.Provider value={store}>
<App />
</StoreContext.Provider>
</Provider>
);