redux的快速开始
安装环境依赖
//使用CRA创建react项目 使用typescipt进行编写
npx create-react-app 项目名 --template typescript
//安装redux环境依赖
npm install @reduxjs/toolkit react-redux
//安装axios支持异步操作
npm install axios
创建 Redux State Slice
创建 src/store/modules/channelStore 文件(文件所放置的位置可以自定义,最好有一个好的结构)。在该文件中从 Redux Toolkit 引入 createSlice API。
创建 slice 需要一个字符串名称来标识切片、一个初始 state 以及一个或多个定义了该如何更新 state 的 reducer 函数。slice 创建后 ,我们可以导出 slice 中生成的 Redux action creators 和 reducer 函数。
import { createSlice } from "@reduxjs/toolkit"
import { AppDispatch } from "../index";
import axios, {AxiosResponse} from "axios"
interface dataType {
id: number,
name: string,
}
interface ChannelState {
channelList: dataType[];
}
interface ResponseType {
data: {
channels: dataType[];
};
}
const initialState: ChannelState = {
channelList: [{id: 1, name: "前端"}]
}
const channelStore = createSlice({
name: "channel",
initialState,
reducers: {
changeChannel: (state, action: PayloadAction<dataType[]>) => {
state.channelList = action.payload
}
}
})
const { changeChannel } = channelStore.actions
//异步请求
export const getChannelList = () => {
return async (dispatch: AppDispatch) => {
const res:AxiosResponse<ResponseType> = await axios.get("http://geek.itheima.net/v1_0/channels")
const data = await res.data.data.channels;
dispatch(changeChannel(data))
}
}
export default channelStore.reducer
初始状态initialState说明
对于redux管理的初始状态initialState你需要的所有状态,比如name,age什么的
interface dataType {
id: number,
name: string,
}
interface ChannelState {
channelList: dataType[];
//name: string,
//age: number
}
const initialState: ChannelState = {
channelList: [{id: 1, name: "前端"}],
//name: '123',
//age: 17
}
reducers状态管理函数
对于reducer中的状态管理函数 changeChannel: (state, action: PayloadAction<dataType[]>) => {
state.channelList = action.payload
}来说, state用来管理你所定义的状态,而action能够接收你所传递过来的参数 action中定义了type的playload两个参数,playload能够接收到你所传递过来的参数
changeChannel: (state, action: PayloadAction<dataType[]>) => {
state.channelList = action.payload
}
}
//点击action crl + 鼠标点击就可以查看关于其的说明
export type PayloadAction<P = void, T extends string = string, M = never, E = never> = {
payload: P;
type: T;
} & ([M] extends [never] ? {} : {
meta: M;
}) & ([E] extends [never] ? {} : {
error: E;
});
action: PayloadAction<dataType[]>会将PayloadActiion中的泛型传递给payload 这样使数据的类型可控
关于axios异步获取数据的类型说明
dispatch调用定义的函数方法
//dispatch: AppDispatch 类型后面会进行说明
export const getChannelList = () => {
return async (dispatch: AppDispatch) => {
//
const res:AxiosResponse<ResponseType> = await axios.get("http://geek.itheima.net/v1_0/channels")
const data = await res.data.data.channels;
dispatch(changeChannel(data))
}
}
AxiosResponse说明如下 将ResponseType赋予给与的数据
如何你开始不清楚后端返回的数据类型可以暂时写成any,然后根据后端所提供数据编写相应的数据类型
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
创建Redux Store
在src/store/index.tsx中编写导出的store数据
import { configureStore } from "@reduxjs/toolkit";
import channelStore from "./modules/channelStore";
const store = configureStore({
reducer: {
channel: channelStore
},
});
// 从 store 本身推断出 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>
// 推断出类型: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export default store;
定义Hook类型 --以便在react项目中调用
在src中定义 hooks.tsx
尽管你可以将 RootState 和 AppDispatch 类型导入每个组件, 更好的方式是创建 useDispatch 和 useSelector 钩子的类型定义,以便在你的应用程序中使用 有几个重要的原因:
- 对于 useSelector ,它不需要你每次输入(state: RootState)
- 对于 useDispatch ,默认的 Dispatch 类型不知道 thunk 。为了正确调度 thunk ,你需要使用 store 中包含 thunk 中间件类型的特定自定义 AppDispatch 类型,并将其与 useDispatch 一起使用。添加一个预先输入的 useDispatch 钩子可以防止你忘记在需要的地方导入 AppDispatch。
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './index'
// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
为 React 提供 Redux Store
创建 store 后,便可以在 React 组件中使用它。
在 src/index.js 中引入我们刚刚创建的 store , 通过 React-Redux 的 将 包裹起来,并将 store 作为 prop 传入。
root.render(
//
<Provider store={store}>
<App />
</Provider>
);
在react中使用redux
import { useEffect } from "react";
import { useAppSelector, useAppDispatch } from "../store/hooks";
import {getChannelList } from "../store/modules/channelStore";
const StoreText = () => {
const {channelList} = useAppSelector((state) => state.channel);
const dispatch = useAppDispatch();
//
useEffect(() => {
dispatch(getChannelList())
}, []);
return (<div>
<ul>
{channelList.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>);
};
export default StoreText;