韶关网站建设科技有限公司,目前最火的互联网项目,做网站投诉要钱吗,泰国清迈房产网站大全文章目录 一、项目起航#xff1a;项目初始化与配置二、React 与 Hook 应用#xff1a;实现项目列表三、TS 应用#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook… 文章目录 一、项目起航项目初始化与配置二、React 与 Hook 应用实现项目列表三、TS 应用JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook路由与 URL 状态管理八、用户选择器与项目编辑功能九、深入React 状态管理与Redux机制12345~891011.用redux-thunk管理登录状态 学习内容来源React React Hook TS 最佳实践-慕课网 相对原教程我在学习开始时2023.03采用的是当前最新版本
项版本react react-dom^18.2.0react-router react-router-dom^6.11.2antd^4.24.8commitlint/cli commitlint/config-conventional^17.4.4eslint-config-prettier^8.6.0husky^8.0.3lint-staged^13.1.2prettier2.8.4json-server0.17.2craco-less^2.0.0craco/craco^7.1.0qs^6.11.0dayjs^1.11.7react-helmet^6.1.0types/react-helmet^6.1.6react-query^6.1.0welldone-software/why-did-you-render^7.0.1emotion/react emotion/styled^11.10.6
具体配置、操作和内容会有差异“坑”也会有所不同。。。 一、项目起航项目初始化与配置 一、项目起航项目初始化与配置 二、React 与 Hook 应用实现项目列表 二、React 与 Hook 应用实现项目列表 三、TS 应用JS神助攻 - 强类型 三、 TS 应用JS神助攻 - 强类型 四、JWT、用户认证与异步请求 四、 JWT、用户认证与异步请求(上) 四、 JWT、用户认证与异步请求(下) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(下) 六、用户体验优化 - 加载中和错误状态处理 六、用户体验优化 - 加载中和错误状态处理(上) 六、用户体验优化 - 加载中和错误状态处理(中) 六、用户体验优化 - 加载中和错误状态处理(下) 七、Hook路由与 URL 状态管理 七、Hook路由与 URL 状态管理(上) 七、Hook路由与 URL 状态管理(中) 七、Hook路由与 URL 状态管理(下) 八、用户选择器与项目编辑功能 八、用户选择器与项目编辑功能(上) 八、用户选择器与项目编辑功能(下) 九、深入React 状态管理与Redux机制
12 九、深入React 状态管理与Redux机制(一) 34 九、深入React 状态管理与Redux机制(二) 5~8 九、深入React 状态管理与Redux机制(三) 910 九、深入React 状态管理与Redux机制(四) 11.用redux-thunk管理登录状态
既然模态框使用 redux 来管理了而 redux 与 context 是竞争关系那可以尝试将之前管理登录状态的 context 改为 redux
新建 src\store\auth.slice.ts
import { User } from screens/ProjectList/components/SearchPanel;
import { createSlice } from reduxjs/toolkit;
import * as auth from auth-provider
import { AuthForm, initUser as _initUser } from context/auth-context;
import { AppDispatch, RootState } from store;interface State {user: User | null
}const initialState: State {user: null
}export const authSlice createSlice({name: auth,initialState,reducers: {setUser(state, action) {state.user action.payload}}
})const { setUser } authSlice.actionsexport const selectUser (state: RootState) state.auth.userexport const login (form: AuthForm) (dispatch: AppDispatch) auth.login(form).then(user dispatch(setUser(user)))
export const register (form: AuthForm) (dispatch: AppDispatch) auth.register(form).then(user dispatch(setUser(user)))
export const logout () (dispatch: AppDispatch) auth.logout().then(() dispatch(setUser(null)))
export const initUser () (dispatch: AppDispatch) _initUser().then(user dispatch(setUser(user)))需要提前将 src\context\auth-context.tsx 中的 interface AuthForm 和 initUser(视频中对应bootstrapUser) 导出 最后在 src\store\index.ts 中统一注册
...
import { authSlice } from ./auth.slice;// 集中状态注册
export const rootReducer {projectList: projectListSlice.reducer,auth: authSlice.reducer
};
...接下来使用 redux 中的 auth 相关功能替换原有 context 提供的 auth 的功能
重构需要找代码上游中集中的一个点useAuth
修改 src\context\auth-context.tsx import { ReactNode, useCallback } from react;
...import * as authStore from store/auth.sliceimport { useDispatch, useSelector } from react-redux;import { AppDispatch } from store;- interface AuthForm {export interface AuthForm {username: string;password: string;
}- const initUser async () {export const initUser async () {let user null;const token auth.getToken();if (token) {// 由于要自定义 token 这里使用 http 而非 useHttpconst data await http(me, { token });user data.user;}return user
};- const AuthContext React.createContext
- | {
- user: User | null;
- login: (form: AuthForm) Promisevoid;
- register: (form: AuthForm) Promisevoid;
- logout: () Promisevoid;
- }
- | undefined
- (undefined);- AuthContext.displayName AuthContext;export const AuthProvider ({ children }: { children: ReactNode }) {// 这里要考虑到初始值的类型与后续值类型取并组成一个泛型const {
- data: user,error,isLoading,isReady,isError,run,
- setData: setUser,} useAsyncUser | null();// const dispatch: (...args: unknown[]) PromiseUser useDispatch()// const dispatch: AppDispatch useDispatch()// 这种写法虽然消除了代码中的报错但是控制台会有报错// useMount(async () run(dispatch(await initUser())));// useMount(() run(dispatch(initUser())));// 还原后登录保持功能已经是不好使的了useMount(() run(initUser()));- const login (form: AuthForm) auth.login(form).then(setUser);
- const register (form: AuthForm) auth.register(form).then(setUser);
- const logout () auth.logout().then(() setUser(null));if (isReady || isLoading) {return FullPageLoading /;}if (isError) {return FullPageErrorFallback error{error} /;}- return (
- AuthContext.Provider
- children{children}
- value{{ user, login, register, logout }}
- /
- );return div{ children }/div
};export const useAuth () {
- const context React.useContext(AuthContext);
- if (!context) {
- throw new Error(useAuth 必须在 AuthProvider 中使用);
- }
- return context;// 这种写法有报错// const dispatch: (...args: unknown[]) PromiseUser useDispatch()const dispatch: AppDispatch useDispatch()const user useSelector(authStore.selectUser)const login useCallback((form: AuthForm) dispatch(authStore.login(form)), [dispatch])const register useCallback((form: AuthForm) dispatch(authStore.register(form)), [dispatch])const logout useCallback(() dispatch(authStore.logout()), [dispatch])// const login useCallback((form: AuthForm) authStore.login(form), [])// const register useCallback((form: AuthForm) authStore.register(form), [])// const logout useCallback(() authStore.logout(), [])// login({ username: 123, password: 123 }).then()return { user, login, register, logout };
};这种写法会报错 const dispatch: (...args: unknown[]) PromiseUser useDispatch()
不能将类型“DispatchAnyAction”分配给类型“(...args: unknown[]) PromiseUser”。参数“action”和“args” 的类型不兼容。不能将类型“unknown”分配给类型“AnyAction”替换为 const dispatch: AppDispatch useDispatch() 后正常
useMount(async () run(dispatch(await initUser()))) 中不加 async..await 的话会有如下报错提示
没有与此调用匹配的重载。第 1 个重载(共 3 个)“(thunkAction: ThunkActionPromiseUser | null, { projectList: State; auth: State; }, undefined, AnyAction): PromiseUser | null”出现以下错误。类型“Promiseany”的参数不能赋给类型“ThunkActionPromiseUser | null, { projectList: State; auth: State; }, undefined, AnyAction”的参数。类型“Promiseany”提供的内容与签名“(dispatch: ThunkDispatch{ projectList: State; auth: State; }, undefined, AnyAction, getState: () { projectList: State; auth: State; }, extraArgument: undefined): Promise...”不匹配。第 2 个重载(共 3 个)“(action: AnyAction): AnyAction”出现以下错误。类型“Promiseany”的参数不能赋给类型“AnyAction”的参数。类型 Promiseany 中缺少属性 type但类型 AnyAction 中需要该属性。第 3 个重载(共 3 个)“(action: AnyAction | ThunkActionPromiseUser | null, { projectList: State; auth: State; }, undefined, AnyAction): AnyAction | Promise...”出现以下错误。类型“Promiseany”的参数不能赋给类型“AnyAction | ThunkActionPromiseUser | null, { projectList: State; auth: State; }, undefined, AnyAction”的参数。不能将类型“Promiseany”分配给类型“AnyAction”。ts(2769)
auth-context.tsx(41, 31): 是否忘记使用 await?
index.d.ts(19, 3): 在此处声明了 type。
auth-context.tsx(41, 31): 是否忘记使用 await?
auth-context.tsx(41, 31): 是否忘记使用 await?最终运行结果登录注册登出功能都正常只有登录保持不正常 部分引用笔记还在草稿阶段敬请期待。。。