Redux Toolkit 介绍
Redux Toolkit 是 Redux
官方强烈推荐,开箱即用的一个高效的 Redux 开发工具集。它旨在成为标准的 Redux 逻辑开发模式,我们强烈建议你使用它。
概览
The Redux Toolkit package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux
:
“Configuring a Redux store is too complicated”
“I have to add a lot of packages to get Redux to do anything useful”
“Redux requires too much boilerplate code”
We can’t solve every use case, but in the spirit ofcreate-react-app
, we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.
Redux Toolkit also includes a powerful data fetching and caching capability that we’ve dubbed "RTK Query"
. It’s included in the package as a separate set of entry points. It’s optional, but can eliminate the need to hand-write data fetching logic yourself.
These tools should be beneficial to all Redux users. Whether you’re a brand new Redux user setting up your first project, or an experienced user who wants to simplify an existing application, Redux Toolkit can help you make your Redux code better.
起步
1. 安装
npx create-react-app my-app --template redux
npm install @reduxjs/toolkit
注:删除不需要的文件和代码,在文章末尾我将把本次 Demo 演示的放到 GitHub 上,以供大家参考。
2. Redux Toolkit 包含哪些 APIs?
configureStore()
: wraps createStore to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.createReducer()
: that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses theimmer library
to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.createAction()
: generates an action creator function for the given action type string. The function itself has toString() defined, so that it can be used in place of the type constant.createSlice()
: accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.createAsyncThunk
: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promisecreateEntityAdapter
: generates a set of reusable reducers and selectors to manage normalized data in the store
ThecreateSelector
utility
from theReselect
library, re-exported for ease of use.
3.开始
- 文件目录结构
.
|-- ./README.md
|-- ./package-lock.json
|-- ./package.json
|-- ./public
| |-- ./public/favicon.ico
| |-- ./public/index.html
| |-- ./public/logo192.png
| |-- ./public/logo512.png
| |-- ./public/manifest.json
| `-- ./public/robots.txt
`-- ./src
|-- ./src/App.js
|-- ./src/app
| `-- ./src/app/store.js
|-- ./src/features
| `-- ./src/features/pets
| |-- ./src/features/pets/BuyPets.jsx
| |-- ./src/features/pets/buyPetsSlice.js
| `-- ./src/features/pets/petsAPI.js
`-- ./src/index.js
// ./src/index.js
import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./app/store";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
// ./src/App.js
import React from "react";
import BuyPets from "./features/pets/BuyPets";
function App() {
return (
<div className="App">
<header className="App-header">
<h2>Hello React Toolkit</h2>
</header>
<main>
<BuyPets />
</main>
</div>
);
}
export default App;
// ./src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
import buyPetsReducer from "../features/pets/buyPetsSlice";
export const store = configureStore({
reducer: {
pets: buyPetsReducer,
},
});
// ./src/features/pets/BuyPets.jsx
import React, { useEffect } from "react";
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import {
buyPetsAction,
filetrPetsAction,
getDataAsyncAction,
selectState,
} from "./buyPetsSlice";
function BuyPets() {
// 获取宠物数据
const { pets, data } = useSelector(selectState, shallowEqual);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getDataAsyncAction());
}, [dispatch]);
function handleChange(e) {
const { value, checked } = e.target;
if (checked) {
// 选中就发送
dispatch(buyPetsAction(value));
} else {
// 取消就发送
dispatch(filetrPetsAction(value));
}
}
return (
<div>
<div>
<h3>买宠物</h3>
<form>
<input
style={{ marginLeft: "20px" }}
type="checkbox"
id="cat"
value="猫"
onChange={handleChange}
/>
<label htmlFor="cat">猫</label>
<input
style={{ marginLeft: "20px" }}
type="checkbox"
id="dog"
value="狗"
onChange={handleChange}
/>
<label htmlFor="dog">狗</label>
<input
style={{ marginLeft: "20px" }}
type="checkbox"
id="rabbit"
value="兔子"
onChange={handleChange}
/>
<label htmlFor="rabbit">兔子</label>
</form>
</div>
<h3>
我买到的宠物是:
{pets?.map((item) => (
<span
key={item}
style={{ marginRight: "10px" }}
>
{item}
</span>
))}
</h3>
<hr />
<div>
<h3>Pets页面请求的数据:</h3>
{data.at(-1)
? data.map((user) => {
return <li key={user.id}>{user.name}</li>;
})
: "loading..."}
</div>
</div>
);
}
export default BuyPets;
// ./src/features/pets/buyPetsSlice.js
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { fetchData } from "./petsAPI";
const initialState = {
pets: [],
data: [],
status: "fulfilled",
};
export const getDataAsyncAction = createAsyncThunk(
"pets/fetchData",
async () => {
const res = await fetchData();
return res.data;
}
);
export const buyPetsSlice = createSlice({
name: "pets",
initialState,
reducers: {
// 买宠物的 action
buyPetsAction(state, { payload }) {
state.pets = state.pets.concat(payload);
},
// 取消宠物的 action
filetrPetsAction(state, { payload }) {
state.pets = state.pets.filter((animaly) => animaly !== payload);
},
},
extraReducers: (builder) => {
builder.addCase(getDataAsyncAction.fulfilled, (state, action) => {
state.data = action.payload;
});
},
});
export const selectState = (state) => state.pets;
export const { buyPetsAction, filetrPetsAction } = buyPetsSlice.actions;
export default buyPetsSlice.reducer;
// ./src/features/pets/petsAPI.js
import axios from "axios";
export function fetchData() {
return axios.get("https://jsonplaceholder.typicode.com/users");
}
本次 Demo git 地址:https://github.com/paomo5515/redux-toolkit-demo.git
页面展示: