学习React之redux-toolkit
通过构建一个小案例进行学习。
需求:1、开发一个计数器。2、异步获取数据并展示
实现计数器:
步骤一:使用@reduxjs/toolkit库中的createSlice() API初始化state数据并定义加法和减法的reducer,暴露这个切片对象的reducer和actions
新建一个feature文件夹专门管理组件的状态,在文件夹下新建counter.js
import { createSlice } from "@reduxjs/toolkit"
const counterSlice = createSlice({
// 为切片命名
name: "counter",
// 初始化state
initialState: {
counter: 0,
},
// 注意是reducers,同时是一个对象
reducers: {
// 在这里函数名addNumber就对应上一节中redux中的action
// 用户派发action时可以传参数,用户传来的参数就是这里的payload,运用了解构操作
// 用户派发action时redux-toolkit会默认给action传入当前的state,便于用户使用state
addNumber(state, {payload}) {
// 可以直接操作state而不用像redux一样重新返回一个对象
// 原因:使用了immerjs,采用了持久化数据结构和结构共享,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过结构共享等方式大幅提高性能
state.counter += payload
},
subNumber(state, {payload}) {
state.counter -= payload
}
}
})
// 暴露actions
export const { addNumber, subNumber } = counterSlice.actions
// 暴露reducer
export default counterSlice.reducer
步骤二:利用configureStore() API创建store对象,并将counterSlice的reduce添加到store中
import {configureStore} from '@reduxjs/toolkit';
import counterReducer from './features/counter'
import bannerReducer from './features/banner'
const store = configureStore({
reducer: {
counter: counterReducer,
banner: bannerReducer
}
})
export default store;
步骤三:书写组件逻辑
import React, { PureComponent } from 'react'
import { connect } from "react-redux"
import { addNumber, subNumber} from '../store/features/counter'
// 实现计数器
export class Home extends PureComponent {
render() {
return (
<div>
<h2>Home</h2>
<h3>当前计数:{this.props.counter}</h3>
<button onClick={e => this.props.addNumberWithHome(1)}>+1</button>
<button onClick={e => this.props.subNumberWithHome(1)}>-1</button>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
// 这里要注意
counter: state.counter.counter
}
}
const mapDispatchToProps = (dispatch) => {
return {
addNumberWithHome(num) {
dispatch(addNumber(num))
},
subNumberWithHome(num) {
dispatch(subNumber(num))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Home)
实现异步请求:
import {createSlice, createAsyncThunk} from "@reduxjs/toolkit"
import axios from "axios"
export const fetchBannerDataAction = createAsyncThunk(
"fetch/homeBannerData",
async (extraInfo, {dispatch, getState}) => {
console.log(extraInfo, dispatch, getState)
const res = await axios.get("http://123.207.32.32:8000/home/multidata")
const banners = res.data.data.banner.list
// 不写extraReducers的方法的写法
dispatch(changeBanners(banners))
// 写extraReducers的方法的写法得到res之后直接return res.data即可
// 但是在slice中要写对应的extraReducer
return res.data
})
const bannerSlice = createSlice({
name: "banner",
initialState : {
banners: []
},
reducers: {
changeBanners(state, {payload}) {
// 原因:使用了immerjs,Immutable.js 采用了持久化数据结构和结构共享,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过结构共享等方式大幅提高性能
state.banners = payload
}
},
// extraReducers写法一
extraReducers: {
[fetchBannerDataAction.pending](state, action) {
console.log("fetchBannerDataAction pending")
},
[fetchBannerDataAction.fulfilled](state, {payload}) {
console.log("fetchBannerDataAction fulfilled",payload)
state.banners = payload.data.banner.list
},
[fetchBannerDataAction.rejected](state, action) {
console.log("fetchBannerDataAction rejected")
},
}
// extraReducers写法二
// extraReducers: (builder) => {
// builder
// .addCase(fetchBannerDataAction.pending, (state, action) => {
// console.log("fetchBannerDataAction pending")
// })
// .addCase(fetchBannerDataAction.fulfilled, (state, {payload}) => {
// console.log("fetchBannerDataAction fulfilled", payload)
// state.banners = payload.data.banner.list
// })
// .addCase(fetchBannerDataAction.rejected, (state, {payload}) => {
// console.log("fetchBannerDataAction rejected")
// })
// }
})
export const {changeBanners} = bannerSlice.actions
export default bannerSlice.reducer
组件代码:
import React, { PureComponent } from 'react'
import {connect} from "react-redux"
import {fetchBannerDataAction} from '../store/features/banner'
export class Profile extends PureComponent {
// 在这里进行异步获取数据请求
componentDidMount() {
this.props.fetchBannerData()
}
render() {
return (
<div>
<h2>Profile</h2>
<ul>
{
this.props.banners.map((item, index) => {
return <li key={index}>{item.title}</li>
})
}
</ul>
</div>
)
}
}
const mapStateToProps = state => ({
banners: state.banner.banners
})
const mapDispatchToProps = dispatch => ({
fetchBannerData() {
dispatch(fetchBannerDataAction({name: "张华栋"}))
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Profile)
以后直接看官方文档即可