安装
创建react+redux的TS环境(最佳实践) 无须再安装redux、redux-thunk、react-redux、immer等,默认就已经集成了@reduxjs/toolkit的Redux架构。
create-react-app react-admin --template redux-typescript
使用Redux Toolkit完成react的状态管理
demo效果演示如下
生成一个子reducer (createAsyncThunk, createSlice)
/**
src/store/test/testSlice.ts
*/
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// 异步请求
import { fetchIp } from './testAPI';
// 设置类型
export interface testState {
value: number;
ip: object
}
// 设置初始化state
const initialState: testState = {
value: 1,
ip:{}
};
// createAsyncThunk这个API可以用来设置异步方法,我们可以通过这个API来让redux支持异步。
export const getIpAsync = createAsyncThunk(
'test/fetchIp',
async () => {
const response = await fetchIp();
console.log(response)
return response.data;
}
);
export const testSlice = createSlice({
name: 'test',
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: {
increment: (state) => {
// Redux Toolkit允许我们在reduce中编写“突变”逻辑.
//它实际上不会改变状态,因为它使用Immer库,
//检测到“派遣状态”的变化,并产生一个全新的基于这些变化的不可变状态
state.value += 1;
},
},
// "extraReducers"字段可以让slice处理在其他地方定义的action,
// 包括由createAsyncThunk或其他片段生成的操作.
extraReducers: (builder) => {
builder
.addCase(getIpAsync.pending, (state) => {
console.log('异步请求正在进行中!')
})
.addCase(getIpAsync.rejected,(state)=>{
console.log('异步请求失败!')
})
.addCase(getIpAsync.fulfilled, (state, action) => {
state.ip = action.payload;
});
},
});
export const { increment } = testSlice.actions;
export default testSlice.reducer;
异步方法的使用示例
/**
src/store/testAPI.ts
*/
//在utils/request.js文件中配置请求拦截与响应拦截
import http from "../../utils/request";
// 设置一个异步请求
export function fetchIp() {
return http({url:'/api',method:"GET"});
}
配置store (configureStore, ThunkAction, Action)
/**
src/store/index.tsx
*/
import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
// 导入子reducer
import testReducer from './test/testSlice'
export const store = configureStore({
// 合并子reducer
reducer: {
test:testReducer
},
})
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
使用Provider将store注入react的页面中
/**
index.tsx
*/
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById('root')
);
将redux.js中的useDispatch, useSelector适用于ts环境
/**
src/hooks/index.ts
*/
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from '../store';
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
react页面中使用
/**
APP.tsx
*/
import './App.css';
import { increment,getIpAsync } from './store/test/testSlice';
import { useAppSelector,useAppDispatch } from './hooks';
function App() {
// 获取store中的test空间的状态变量变量
const { test } = useAppSelector(state=>state)
// 获取dispath用于向store中派发方法
const dispatch =useAppDispatch()
return (
<>
<h1>学习@reduxjs/toolkit</h1>
<button onClick={()=>dispatch(increment()) }>{test.value} 加一</button>
<hr/>
<button onClick={()=>dispatch(getIpAsync())}>查询IP</button>
</>
);
}
export default App;
demo文件布局如下
ts环境常见问题
常用的npm包在引入ts环境后会报错
当我们习惯于js的弱类型开发后,在进行ts开发会遇到一些问题,因为现在一些比较流行的有些用的是JavaScript开发,而JavaScript没有像typescript一样使用于静态类型。所以这些包就会出现一些类型问题,而为了解决这些问题,我们可以编写一些**(*.d.ts)**文件来对一些JS 库中的静态类型进行定义。在d.ts中存放一些声明,类似于C/C++的.h头文件。
TypeScript作为JavaScript的超集,在开发过程中不可避免要引用其他第三方的JavaScript的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述JavaScript库和模块信息的声明文件。通过引用这个声明文件,就可以借用TypeScript的各种特性来使用库文件了。
当然,我们自己去编写可能考虑不够全面。所以,我们可以去npm官网安装对应js库的type类型包,其格式一般为 (@types/****)。例如,非常出名的 lodash包就有 @types/lodash
我们可以看到这个包下载量非常大。说明了,大多数人和我们一样习惯于使用成熟的第三方插件。
图片等非代码资源无法正常导入
出现这一原因是:typescript无法识别非代码资源 因此,我们可以在项目的src路径下新建一个ts声明文件
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
然后在ts项目的tsconfig.json中如下代码所示导入,这样无论你在src文件夹的任意位置新建ts声明文件,都会被ts或vscode自动解析。
"include": ["src"]
当然这样直接导入src整个路径可能会出现一些问题,在此,我还是建议大家将(d.ts)类型文件,放在一个文件目录下。 例如:
|