相对原教程,我在学习开始时(2023.03)采用的是当前最新版本:
项 | 版本 |
---|---|
react & react-dom | ^18.2.0 |
react-router & react-router-dom | ^6.11.2 |
antd | ^4.24.8 |
@commitlint/cli & @commitlint/config-conventional | ^17.4.4 |
eslint-config-prettier | ^8.6.0 |
husky | ^8.0.3 |
lint-staged | ^13.1.2 |
prettier | 2.8.4 |
json-server | 0.17.2 |
craco-less | ^2.0.0 |
@craco/craco | ^7.1.0 |
qs | ^6.11.0 |
dayjs | ^1.11.7 |
react-helmet | ^6.1.0 |
@types/react-helmet | ^6.1.6 |
react-query | ^6.1.0 |
@welldone-software/why-did-you-render | ^7.0.1 |
@emotion/react & @emotion/styled | ^11.10.6 |
具体配置、操作和内容会有差异,“坑”也会有所不同。。。
一、项目起航:项目初始化与配置
二、React 与 Hook 应用:实现项目列表
三、TS 应用:JS神助攻 - 强类型
四、JWT、用户认证与异步请求
五、CSS 其实很简单 - 用 CSS-in-JS 添加样式
六、用户体验优化 - 加载中和错误状态处理
1~2
3.登录注册页面 Loading 和 Error 状态处理,与 Event Loop 详解
列表页的 异步状态 弄完,接下来是登录注册页了
修改 src\unauthenticated-app\index.tsx
(新增 error
状态处理,将 error
j监听操作 交给 登录注册页):
...
import { Card, Button, Divider, Typography } from "antd";
...
export const UnauthenticatedApp = () => {
...
const [error, setError] = useState<Error | null>(null);
return (
<Container>
...
<ShadowCard>
<Title>{isRegister ? "请注册" : "请登录"}</Title>
{ error ? <Typography.Text type="danger">{error.message}</Typography.Text> : null }
{isRegister ? <Register onError={setError}/> : <Login onError={setError}/>}
<Divider />
...
</ShadowCard>
</Container>
);
};
...
修改 src\unauthenticated-app\login.tsx
(传入 onError
并在异步操作后 catch
中使用):
...
export const Login = ({onError}: { onError: (error: Error) => void }) => {
...
const handleSubmit = (values: { username: string; password: string }) => {
login(values).catch(e => onError(e))
};
...
};
...
同理修改 src\unauthenticated-app\register.tsx
:
...
export const Register = ({onError}: { onError: (error: Error) => void }) => {
...
const handleSubmit = (values: { username: string; password: string }) => {
register(values).catch(e => onError(e))
};
...
};
...
使用非预设用户名密码检验:没反应。。。但是控制台打印出了刚输入的用户名和密码。。。
通过登录的调用链可以找到 导致这个问题的原因:src\auth-provider.ts
!res.ok
时,返回了Promise.reject(data)
,而data
是请求入参,这显然不是预想的效果(注册同理),修改这部分为Promise.reject(await res.json())
修改后再次检验,成了!
Promise.catch
固然好用,但接下来换个思路,使用 try..catch
并引出 Event Loop
。
先修改 src\unauthenticated-app\login.tsx
试试水:
...
export const Login = ({onError}: { onError: (error: Error) => void }) => {
...
const handleSubmit = (values: { username: string; password: string }) => {
try {
// login(values).catch(e => onError(e))
login(values);
} catch(e: Error | any) {
onError(e)
}
};
...
};
...
控制台输出正常,但是界面没有效果。。。
问题出在 login 是异步操作,程序中会优先执行同步操作,然后才会异步操作,所以 onError 优先执行,并没有拿到后端返回的报错信息
再次修改 src\unauthenticated-app\login.tsx
(使用 async await 处理异步操作):
...
export const Login = ({onError}: { onError: (error: Error) => void }) => {
...
const handleSubmit = async (values: { username: string; password: string }) => {
try {
// login(values).catch(e => onError(e))
await login(values);
} catch(e: Error | any) {
onError(e)
}
};
...
};
...
这样便正常啦!
接下来给注册页新增确认密码功能
修改 src\unauthenticated-app\register.tsx
(新增确认密码的 Form.Item
和 相关处理逻辑):
...
export const Register = ({onError}: { onError: (error: Error) => void }) => {
const { register, user } = useAuth();
const handleSubmit = ({ cpassword, ...values }: { username: string, password: string, cpassword: string }) => {
if (cpassword === values.password) {
register(values).catch(e => onError(e));
} else {
onError(new Error('请确认两次的输入密码相同'))
return
}
};
return (
<Form onFinish={handleSubmit}>
<Form.Item
name="username"
rules={[{ required: true, message: "请输入用户名" }]}
>
<Input placeholder="用户名" type="text" id="username" />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: "请输入密码" }]}
>
<Input placeholder="密码" type="password" id="password" />
</Form.Item>
<Form.Item
name="cpassword"
rules={[{ required: true, message: "请确认密码" }]}
>
<Input placeholder="确认密码" type="password" id="cpassword" />
</Form.Item>
<Form.Item>
<LongButton htmlType="submit" type="primary">
注册
</LongButton>
</Form.Item>
</Form>
);
};
再接着为 登录注册页 添加异步状态 Loading
的处理:
...
import { useAsync } from "utils/use-async";
export const Login = ({onError}: { onError: (error: Error) => void }) => {
const { login, user } = useAuth();
const { run, isLoading } = useAsync()
const handleSubmit = async (values: { username: string; password: string }) => {
try {
// login(values).catch(e => onError(e))
await run(login(values))
} catch(e: Error | any) {
onError(e)
}
};
return (
<Form onFinish={handleSubmit}>
...
<Form.Item>
<LongButton loading={isLoading} htmlType="submit" type="primary">
登录
</LongButton>
</Form.Item>
</Form>
);
};
...
### 最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
### 资料预览
给大家整理的视频资料:
![](https://img-blog.csdnimg.cn/img_convert/6bb6d2236b7e959a1de5dcdcbdea0c3f.png)
给大家整理的电子书资料:
![](https://img-blog.csdnimg.cn/img_convert/994c2f8cb14c2eacce209d7a4507c657.png)
**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
[外链图片转存中...(img-kQMZgcNJ-1714326235150)]
给大家整理的电子书资料:
[外链图片转存中...(img-UrCa3Fdq-1714326235151)]
**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**