umijs + dva +umi-request + js-cookie实现登录
*为了明年换工作,特地学习了react,所以使用umi搭建一个简易项目,学习下里面使用到的知识点,主要这次研究使用dva *
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,redux-saga 主要使用generator实现异步处理
dva链接: https://dvajs.com/guide/ link.
umijs链接:https://umijs.org/zh-CN/docs link.
umi-request链接: https://github.com/umijs/umi-request/link.
js-cookie链接: https://www.npmjs.com/package/js-cookielink.
使用umi创建项目我就不走步骤,直接上代码,里面有注解
一,在src下创建models文件夹,创建user.ts
下面展示一些 内联代码片
。
import { doLoign } from '@/service/login';
import { Subscription, Effect } from 'dva'
import { setCookie } from '@/utils/cookie'
interface UserModeType {
namespace: String,
state: {},
reducers: {},
effects: {},
subscriptions: {
setup: Subscription
}
}
const UserMode: UserModeType = {
namespace: 'users',
// state: 该 Model 当前的状态。数据保存在这里,直接决定了视图层的输出
state: {
token: "",
username: '',
},
// reducers: Action 处理器,处理同步动作,用来算出最新的 State
reducers: {
save(state, { payload: { token, username } }) {
return { ...state, token, username };
},
},
// effects,处理异步动作 call:执行异步函数 put:发出一个 Action,类似于 dispatch到reducers
effects: {
* fetch({ payload: { resolve, reject, userInfo } }, { call, put }) {
try {
const { data, code } = yield call(doLoign, { userInfo });
setCookie("TOKEN", data.token)
yield put({ type: 'save', payload: { token: data.token, username: userInfo.username } });
resolve(code);
}
catch (error) {
reject(error);
}
},
},
//改管理暂未用到,只是研究下用法
// subscriptions: {
// setup({ dispatch, history }) {
// return history.listen(({ pathname, values }) => {
// if (pathname === '/user/login') {
// values = { userInfo: { name: 'admin', password: '111' } }
// dispatch({ type: 'fetch', payload: values });
// }
// });
// },
// },
};
export default UserMode;
二,在pages下创建login文件下,组件使用函数创建
import { Form, Input, Button, Checkbox } from 'antd';
import { connect } from 'dva'
import React, { useState, useEffect } from 'react';
import { history } from 'umi';
const Demo = ({ users, dispatch }) => {
// const [count, setCount] = useState(0);
// 提交登录
const onFinish = async (values: any) => {
// 提交给dva 中的effects:Action 处理器
new Promise((resolve, reject) => {
dispatch({ type: 'users/fetch', payload: { resolve, reject, userInfo: values } });
}).then((data) => {
if (data === 'SUCCESS') { //跳转首页
history.push('/home')
}
});
};
// forme表单异常
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
// 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
useEffect(() => {
console.log(users, dispatch)
}, []);
return (
<Form
name="basic"
labelCol={{
span: 8,
}}
wrapperCol={{
span: 16,
}}
initialValues={{
remember: true,
}}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<Form.Item
label="Username"
name="username"
rules={[
{
required: true,
message: 'Please input your username!',
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="Password"
name="password"
rules={[
{
required: true,
message: 'Please input your password!',
},
]}
>
<Input.Password />
</Form.Item>
<Form.Item
name="remember"
valuePropName="checked"
wrapperCol={{
offset: 8,
span: 16,
}}
>
<Checkbox>Remember me</Checkbox>
</Form.Item>
<Form.Item
wrapperCol={{
offset: 8,
span: 16,
}}
>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
const mapStateToProps = ({ users }) => {
return { users, }
}
export default connect(mapStateToProps)(Demo)
三,创建cookie管理文件,和request.ts,添加路由
import Cookies from 'js-cookie'
export function getCookie(CookieName: String) {
return Cookies.get(CookieName)
}
export function setCookie(CookieName: String, CookieValue: any) {
return Cookies.set(CookieName, CookieValue)
}
export function removeCookie(CookieName: String,) {
return Cookies.remove(CookieName)
}
import request, { extend } from 'umi-request'
import { message } from 'antd'
import { getCookie } from '@/utils/cookie'
import { history } from 'umi';
// 请求拦截器
request.interceptors.request.use((url, options) => {
// 如果接口是登录放行
if (url === '/user/login') {
return {
url: `${url}`,
options: { ...options, interceptors: true },
};
} else {
if (getCookie('TOKEN') !== '' || getCookie('TOKEN') !== null) {
message.error("TOKEN 丢失,请重新登录");
history.push('/user/login');
// 平阻断请求 (暂时未写)
return {
url: `${url}`,
options: { ...options, interceptors: true },
};
} else {
// 请求头添加token
return {
url: `${url}`,
options: { ...options, interceptors: true },
};
}
}
});
// 响应拦截器
request.interceptors.response.use(async response => {
const data = await response.clone().json();
console.log(data)
// if (data.state && data.state === 200) {
// return response;
// }
return response;
});
export default request
export default [
{
path: '/user',
layout: false,
routes: [
{
name: 'login',
path: '/user/login',
component: '@/pages/login/index',
},
],
},
{
path: '/',
component: '@/layouts/LayoutSide/index',
routes: [
{
path: '/home', title: "首页", exact: false, component: '@/pages/home/index',
},
],
},
];
layouts不懂得可以看umi 关于layouts配置,希望给我在下下面评论,下章,研究request 阻断请求,以及动态路由实现