Search K
Appearance
Appearance
ReduxToolkit 是官方推荐的编写 Redux 逻辑的方法。
安装@reduxjs/toolkit
npm install @reduxjs/toolkit react-redux
or
yarn add @reduxjs/toolkit react-redux
安装react-redux
yarn add react-redux
store/feature/counter.js
import {createSlice} from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: {
count: 100
},
reducers: {
addNumber: (state, {payload}) => {
state.count += payload
},
subNumber: (state, {payload}) => {
state.count -= payload
}
}
})
export const {addNumber, subNumber} = counterSlice.actions
export default counterSlice.reducer
store/index.js
import {configureStore} from "@reduxjs/toolkit";
import CounterReducer from "./feature/counter"
const store = configureStore({
reducer: {
counter: CounterReducer
}
})
export default store
到这里store
已经初始化完成了,接下来我们使用react-redux
来读取数据
应用入口文件
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 React, {PureComponent} from 'react';
import {connect} from "react-redux";
import {addNumber} from "../store/feature/counter";
class Home extends PureComponent {
render() {
return (
<div>
<h2>
Home counter: {this.props.count}
</h2>
<div>
<button onClick={() => {
this.props.addNumber(1)
}}>+1
</button>
<button onClick={() => {
this.props.addNumber(5)
}}>+5
</button>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.counter.count
})
const mapDispatchToProps = (dispatch) => ({
addNumber(count) {
dispatch(addNumber(count))
},
// 两种写法都可以
// addNumber: (count) => dispatch(addNumber(count))
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);
最新版本已经舍去了第一种方式,这里用的是builder
的方式
代码示例:
store/feature/home.js
import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
// 模拟网络请求
function fetchDemo() {
return new Promise((resolve, reject) => {
const data = [
{
id: 1,
title: " title1"
},
{
id: 2,
title: " title2"
},
{
id: 3,
title: " title3"
}
]
setTimeout(() => {
resolve(data)
}, 3000)
})
}
// 使用createAsyncThunk创建异步函数
export const fetchHomeMultidataAction = createAsyncThunk("fetch/homemultidata", async () => {
const res = await fetchDemo()
return res
})
const homeSlice = createSlice({
name: "home",
initialState: {
banner: []
},
reducers: {
changeBanner: (state, {payload}) => {
state.banner = payload
}
},
// 已经移除
// extraReducers: {
// [fetchHomeMultidataAction.pending](state, action) {
// console.log("fetchHomeMultidataAction pending", action)
// },
// [fetchHomeMultidataAction.rejected](state, action) {
// console.log("fetchHomeMultidataAction rejected", action)
// },
// [fetchHomeMultidataAction.fulfilled](state, {payload}) {
// console.log("fetchHomeMultidataAction fulfilled", payload)
// state.banner = payload
// }
// }
extraReducers: (builder) => {
builder.addCase(fetchHomeMultidataAction.pending, state => {
console.log("fetchHomeMultidataAction pending", state)
}).addCase(fetchHomeMultidataAction.fulfilled, (state, {payload}) => {
console.log("fetchHomeMultidataAction fulfilled", payload)
// 对banner数据进行赋值
state.banner = payload
})
}
})
export const {changeBanner} = homeSlice.actions
export default homeSlice.reducer
store/index.js
import {configureStore} from "@reduxjs/toolkit";
import HomeReducer from "./feature/home"
const store = configureStore({
reducer: {
home: HomeReducer
}
})
export default store
借助react-redux
的connect
函数进行使用
pages/Profile.jsx
import React, {Component} from 'react';
import {fetchHomeMultidataAction} from "../store/feature/home";
import {connect} from "react-redux";
class Profile extends Component {
componentDidMount() {
this.props.fetchMultiData();
}
render() {
const {banner} = this.props
const list = banner ? (
banner.map(item => {
return (
<li key={item.id}>{item.title}</li>
)
})
) : null
return (
<div>
<h2>
Profile
</h2>
<div>
home banner :
{list}
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
banner: state.home.banner
})
const mapDispatchToProps = (dispatch) => ({
fetchMultiData() {
dispatch(fetchHomeMultidataAction())
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
除了使用builder
进行赋值外,还可以直接在createAsyncThunk
中进行赋值
pages/Profile.jsx
import React, {Component} from 'react';
import {fetchHomeMultidataAction} from "../store/feature/home";
import {connect} from "react-redux";
class Profile extends Component {
componentDidMount() {
this.props.fetchMultiData();
}
render() {
...
}
}
const mapStateToProps = (state) => ({
banner: state.home.banner
})
const mapDispatchToProps = (dispatch) => ({
fetchMultiData() {
// fetchHomeMultidataAction中支持传递额外参数
dispatch(fetchHomeMultidataAction({page: 1}))
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Profile);
store/feature/home.js
import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
function fetchDemo() {
return new Promise((resolve, reject) => {
const data = [
{
id: 1,
title: " title1"
},
{
id: 2,
title: " title2"
},
{
id: 3,
title: " title3"
}
]
setTimeout(() => {
resolve(data)
}, 3000)
})
}
export const fetchHomeMultidataAction = createAsyncThunk("fetch/homemultidata", async (extraInfo, {
dispatch,
getState
}) => {
const res = await fetchDemo()
// 调用时不传extraInfo则为undefined
console.log("extraInfo",extraInfo) // { page: 1 }
console.log("getstate",getState())
// 可以在这里直接调用dispatch赋值
dispatch(changeBanner(res))
return res
})
const homeSlice = createSlice({
name: "home",
initialState: {
banner: []
},
reducers: {
changeBanner: (state, {payload}) => {
state.banner = payload
}
}
})
export const {changeBanner} = homeSlice.actions
export default homeSlice.reducer
在react
开发过程中,我们总是会考虑到数据不可变性(直接赋值对象引用导致带来的问题),而redux-tooltik
中很多场景是直接对源数据惊醒修改,也不符合纯函数的要求,但其实redux-toolkit
满足了数据不可变性,它借助了一个第三方库,来保证数据不可变性。
类似的两个库: