Appearance
React + Redux + Toolkit
介绍
Redux Toolkit 是一组工具,它为 Redux 开发者提供一系列的功能,包括创建 Redux store、reducers、actions、selectors、middleware、and more。它可以帮助你更有效地编写 Redux 应用,并减少样板代码。
特点
- 集成了 Redux 最佳实践,包括 Redux 核心、Redux DevTools、Immer、Thunk 等。
- 提供了创建 Redux store 的便捷函数,包括创建 store、添加 middleware、添加 reducer、创建 action。
- 提供了创建 reducer 的便捷函数,包括创建 reducer、添加 action 类型、添加默认值。
- 提供了创建 action 的便捷函数,包括创建 action、添加 action 类型、添加 payload。
- 提供了创建 selector 的便捷函数,包括创建 selector、添加输入参数、添加默认值。
- 提供了 Redux 异步操作的便捷函数,包括创建异步 action、创建异步 reducer、创建异步 selector。
- 提供了 Redux 工具函数,包括创建 Redux store、创建 Redux middleware、创建 Redux enhancer。
- 提供了 Redux 相关的工具,包括 Redux DevTools、Immer、Thunk 等。
安装
npm install redux react-redux @reduxjs/toolkit
基本用法
创建slice
javascript
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
创建store
javascript
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
使用store
javascript
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
}
export default Counter;
异步操作
javascript
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
const fetchUserById = createAsyncThunk(
'users/fetchUserById',
async (userId) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
return response.json();
}
);
const userSlice = createSlice({
name: 'users',
initialState: {
entities: {},
ids: [],
loading: 'idle',
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUserById.pending, (state) => {
state.loading = 'pending';
})
.addCase(fetchUserById.fulfilled, (state, action) => {
state.entities[action.payload.id] = action.payload;
state.ids.push(action.payload.id);
state.loading = 'idle';
})
.addCase(fetchUserById.rejected, (state, action) => {
state.loading = 'idle';
state.error = action.error.message;
});
},
});
export const { fetchUserById } = userSlice.actions;
export default userSlice.reducer;
javascript
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUserById } from './userSlice';
function User() {
const dispatch = useDispatch();
const { loading, error, entities } = useSelector((state) => state.users);
const user = entities[1];
return (
<div>
{loading === 'pending' && <div>Loading...</div>}
{error && <div>{error}</div>}
{user && <div>{user.name}</div>}
<button onClick={() => dispatch(fetchUserById(1))}>Load user</button>
</div>
);
}
export default User;