From 6f6e6997ad8cef68a24fabf859d0c99dc071f99d Mon Sep 17 00:00:00 2001 From: callmeyan Date: Mon, 27 Feb 2023 21:45:44 +0800 Subject: [PATCH] feat: save login token to localStorage for test --- config.ts | 3 +++ src/App.tsx | 25 +++++++++++++++---------- src/components/Login.tsx | 8 ++++---- src/services/api.ts | 7 ++++--- src/services/request.ts | 16 ++++++++++------ src/utils/useEffectOnce.ts | 27 +++++++++++++++++++++++++++ src/vite-env.d.ts | 3 ++- 7 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 src/utils/useEffectOnce.ts diff --git a/config.ts b/config.ts index 43b7073..feec2ab 100644 --- a/config.ts +++ b/config.ts @@ -5,6 +5,7 @@ const AppConfig = { API_PREFIX: 'http://chat.wx.wm-app.xyz', DEPLOY_DIR: '/', PUBLIC_PATH: '/', + LOGIN_TOKEN_KEY: 'chat.user.token', }, test: { CLIENT_ID: 'uziRFTVYkcgnGjAx', @@ -12,6 +13,7 @@ const AppConfig = { API_PREFIX: 'http://chat.wx.wm-app.xyz', DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'), PUBLIC_PATH: (process.env.PUBLIC_PATH || './'), + LOGIN_TOKEN_KEY: 'chat.user.token', }, production: { CLIENT_ID: 'aVjsh87iWEuhZdWC', @@ -19,6 +21,7 @@ const AppConfig = { API_PREFIX: 'http://chat.wx.wm-app.xyz', DEPLOY_DIR: (process.env.DEPLOY_DIR || '/'), PUBLIC_PATH: (process.env.PUBLIC_PATH || './'), + LOGIN_TOKEN_KEY: 'chat.user.token', } } export default AppConfig diff --git a/src/App.tsx b/src/App.tsx index c33d9dd..6b0715d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,11 @@ import React, {useEffect, useState} from 'react' import Login from "./components/Login"; -import {useSetState} from "ahooks"; +import {useMount, useSetState} from "ahooks"; import {info, UserModel} from "./services/api"; import Vip from "./components/vip"; import Button from "./components/Button"; import {io} from 'socket.io-client' +import { useEffectOnce } from './utils/useEffectOnce'; type MessageItem = { @@ -14,7 +15,7 @@ type MessageItem = { content: string[]; avatar: string; } - +const LOGIN_TOKEN_KEY = APP_CONFIG.LOGIN_TOKEN_KEY; const avatar = 'https://www.cdnjson.com/images/2023/01/31/qwrgFf.jpg', avatar1 = 'https://www.cdnjson.com/images/2023/02/25/AI.png', globalMessageList: MessageItem[] = [ @@ -29,8 +30,10 @@ const avatar = 'https://www.cdnjson.com/images/2023/01/31/qwrgFf.jpg', avatar: avatar1 }, ], + socket = io(APP_CONFIG.API_PREFIX, { - autoConnect: false + autoConnect: false, + path:`/socket.io` }) let messageIndex = 5, lastMessage = 0, initSocket = false; @@ -51,7 +54,7 @@ function App() { function logout() { //TODO 调用注销登录接口 - localStorage.removeItem("chat-login") + localStorage.removeItem(LOGIN_TOKEN_KEY) setState({user: undefined}) } @@ -88,7 +91,7 @@ function App() { } function loadUserInfo() { - if (localStorage.getItem("chat-login")) { + if (!localStorage.getItem(LOGIN_TOKEN_KEY)) { return; } info().then(user => { @@ -147,7 +150,7 @@ function App() { })(); }; // 监听 - useEffect(loadUserInfo, []) + useEffectOnce(loadUserInfo) useEffect(() => { if (messageList.length == 0) return; scrollToBottom(); @@ -203,16 +206,18 @@ function App() { )} {state.user?.vip && -
setState({showVip: true})}>+增加次数<
} +
setState({showVip: true})}>+ 增加次数 >
} {state.showLogin && { + onClose={(logged,data) => { setState({showLogin: false}) - localStorage.setItem("chat-login", "yes") - logged && loadUserInfo() + if(logged && data){ + localStorage.setItem(LOGIN_TOKEN_KEY, data.token) + loadUserInfo() + } }} />} {state.showVip && { diff --git a/src/components/Login.tsx b/src/components/Login.tsx index 9852373..947583d 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -4,10 +4,10 @@ import IconClose from "./icons/IconClose"; import Button from "./Button"; import {useSetState, useCountDown} from "ahooks"; import Checkbox from "./Checkbox"; -import {login, sendCode} from "../services/api"; +import {login, sendCode, UserModel} from "../services/api"; export type LoginProps = { - onClose: (logged?: boolean) => void + onClose: (logged?: boolean,user?: UserModel) => void } const Login: React.FC = (props) => { @@ -45,8 +45,8 @@ const Login: React.FC = (props) => { return; } setState({error: '', loginLoading: true}) - login(data).then(() => { - props.onClose(true) + login(data).then((ret) => { + props.onClose(true,ret) }).catch(error).finally(() => { setState({ loginLoading: false diff --git a/src/services/api.ts b/src/services/api.ts index 7f5c0b1..19ba2de 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -11,10 +11,11 @@ export type UserModel = { export function login(data: any) { return post('/api/user/login', data) } -export function info() { - return get('/api/user/info') -} +export function info() { + const token = localStorage.getItem(APP_CONFIG.LOGIN_TOKEN_KEY) + return post('/api/user/info', {token}) +} export function sendCode(phone: string) { return post('/api/sendCode', {phone}) diff --git a/src/services/request.ts b/src/services/request.ts index d450add..6e116d5 100644 --- a/src/services/request.ts +++ b/src/services/request.ts @@ -15,17 +15,21 @@ const Axios = axios.create({ baseURL: APP_CONFIG.API_PREFIX, timeout: 20000, // 设置超时时长 headers: { - 'Content-Type': JSON_FORMAT, + 'Content-Type': JSON_FORMAT } }) // 请求前拦截 -// Axios.interceptors.request.use(config => { -// return config -// }, err => { -// return Promise.reject(err) -// }) +Axios.interceptors.request.use(config => { + const token = localStorage.getItem(APP_CONFIG.LOGIN_TOKEN_KEY) + if (token) { + config.headers['token'] = token; + } + return config +}, err => { + return Promise.reject(err) +}) // // // 返回后拦截 // Axios.interceptors.response.use(res => { diff --git a/src/utils/useEffectOnce.ts b/src/utils/useEffectOnce.ts new file mode 100644 index 0000000..9df10f3 --- /dev/null +++ b/src/utils/useEffectOnce.ts @@ -0,0 +1,27 @@ +import {useEffect, useRef, useState} from "react" + +export function useEffectOnce(effect:Function) { + const effectFn = useRef(effect) + const destroyFn = useRef() + const effectCalled = useRef(false) + const rendered = useRef(false) + const [, refresh] = useState(0) + + if (effectCalled.current) { + rendered.current = true + } + + useEffect(() => { + if (!effectCalled.current) { + destroyFn.current = effectFn.current() + effectCalled.current = true + } + + refresh(1) + + return () => { + if (rendered.current === false) return + if (destroyFn.current) destroyFn.current() + } + }, []) +} \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index db6a2af..63ef575 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -11,6 +11,7 @@ interface IAppConfigItem { * 静态资源目录 */ PUBLIC_PATH?: string + LOGIN_TOKEN_KEY: string } type IAPP_ENV = 'development' | 'test' | 'production' @@ -19,4 +20,4 @@ type IAppConfig = { }; // 常量配置类型 declare const APP_ENV: IAPP_ENV; -declare const APP_CONFIG: IAppConfigItem; \ No newline at end of file +declare const APP_CONFIG: IAppConfigItem; \ No newline at end of file