일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Vue.js
- 알고리즘
- Flutter
- 모션비트
- 티스토리챌린지
- Java
- 스택
- 리액트
- 나만무
- HTML
- TiL
- 코드트리
- 백준
- 사이드프로젝트
- JavaScript
- 소켓
- 크래프톤 정글
- 시스템콜
- 크래프톤정글
- userprog
- pintos
- 4기
- 자바
- 오블완
- CSS
- 큐
- corou
- 핀토스
- defee
- 자바스크립트
- Today
- Total
미새문지
24.09.03 day59 작업 일지 본문
타입 맞추는게 너무 거지같다. 로그인에서 계속 에러가 발생하는데 해결이 안되서 계속 붙잡다가 일단락은 됐다.
import React, { useState } from "react";
import "../../scss/login/emailLogin.scss";
import CommonInput from "../common/commonInput";
import PwVisible from "../common/pwVisible";
import axios from "axios";
import jwt_decode, { JwtPayload } from "jwt-decode";
interface MyTokenPayload extends JwtPayload {
exp: number;
iat?: number;
userId?: string;
email?: string;
}
const EmailLoginBox: React.FC = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [showPassword, setShowPassword] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const userData = {
email,
password,
};
console.log(userData);
const response = await axios.post("/api/user/login", userData);
console.log("로그인 성공", response.data);
const token = response.data.token;
const decodedToken = jwt_decode<MyTokenPayload>(token);
const expirationTime = decodedToken.exp * 1000;
sessionStorage.setItem("authToken", token);
sessionStorage.setItem("tokenExpiration", expirationTime.toString());
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
window.location.href = "/";
} catch (error) {
console.log("로그인 실패", error);
}
};
return (
<>
<div className="loginInputForm">
<form onSubmit={handleSubmit}>
<CommonInput
typeValue="email"
placeholderValue="이메일"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<CommonInput
typeValue={showPassword ? "text" : "password"}
placeholderValue="비밀번호"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<PwVisible onToggle={setShowPassword} />
<span className="forgotPw">
비밀번호를 잊으셨나요? <span>비밀번호 재설정</span>
</span>
<button className="loginBtn" type="submit">
로그인
</button>
</form>
</div>
</>
);
};
export default EmailLoginBox;
서버에 요청을 위해 api로 이메일과 비밀번호 정보를 보내는데 요청에 성공했을 시 서버에서는 토큰을 보내줄 거라 해당 토큰을 저장하는 방식을 작성했다. 세션스토리지에 토큰을 저장하는데 타입스크립트에서도 jwt적용할 수 있다고 해서 기본적인 세팅을 찾아서 작성했는데,
const decodedToken = jwt_decode<MyTokenPayload>(token);
이 코드에서 이 식은 호출할 수 없습니다.
'typeof import("c:/Users/user/Desktop/cosmetic_routine/corou-frontend/node_modules/jwt-decode/build/cjs/index")' 형식에 호출 시그니처가 없습니다.ts(2349)
라는 에러메세지가 떴다.
jwt를 사용하기 위해선 jwt-decode라는 라이브러리를 설치해줘야 하는데, 설치 후 jwt_decode로 토큰을 넣어주면 된다고 하더라
근데 위 에러가 계속 떠서 해결법을 찾아봤더니 타입을 호출할 수 없다고 모듈 설치를 제대로 했는지 확인하래서 라이브러리 설치와 해당 라이브러리 타입을 지정해주는 모듈도 설치했고
npm install jwt-decode
npm install @types/jwt-decode --save-dev
설정에서 타입을 못받아올수도 있다고 해서 tsconfig도 설정을 해주었다.
{
"compilerOptions": {
"typeRoots": ["node_modules/@types"], // 타입 경로를 지정해서 가져올 수 있게
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
그래도 타입을 못읽는 건지 여전히 인식이 안되서 지피티를 사용한 결과 타입을 강제로 지정해주면 된다해서 decodedToken의 타입을 강제로 지정해줬다.
const decodedToken = (jwt_decode as unknown as (token: string) => MyTokenPayload)(token);
토큰의 만료시간을 설정해줬는데 이건 서버에서 어떻게 들어오냐에 따라 다르기 때문에 작성만 해두고 필요없으면 이후에 지우면 될 것 같다.
그리고 token관련해서 지피티 좀 물어보면서 이것저것 찾아봤는데
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
이걸 작성하면 axios의 헤더에 Bearer token을 기본설정으로 잡아준다고 해서 작성해놨다.
로그인에 성공 시 메인페이지로 이동되고 실패하면 실패 메세지와 함께 error코드가 출력된다.
데이터를 요청하는 handleSubmit의 경우 처음에 로그인 버튼에 onClick으로 지정해놨는데 이건 form의 onSubmit에 작성해주는게 더 자연스럽다고 하여 코드를 수정해줬다.
로그인은 api연결할 때 더 확인해보고 마이페이지의 프로필 부분은 useEffect를 이용해 렌더링될 때 정보를 가져오게 작성했다.
get방식으로 /api/user/self로 데이터를 요청했다.
import { useEffect, useState } from "react";
import "../../scss/mypage/profile.scss";
import CommonTag from "../common/commonTag";
import axios from "axios";
interface userProfile {
nickname: string;
profileImg: string;
trouble: string[];
}
const Profile: React.FC = () => {
const [profile, setProfile] = useState<userProfile | null>(null);
useEffect(() => {
axios
.get("/api/user/self")
.then((response) => {
setProfile(response.data);
})
.catch((error) => {
console.error("프로필 조회 실패", error);
setProfile(null);
});
}, []);
return (
<>
<div className="profileWrapper">
<div className="profileImg">
<div>
<img
src={profile?.profileImg}
alt={`${profile?.nickname} 프로필`}
/>
</div>
<p>{profile?.nickname}</p>
</div>
<div className="selectFilter">
{/* <CommonTag tagName="건성" />
<CommonTag tagName="남성" />
<CommonTag tagName="30대" />
<CommonTag tagName="민감성" />
<CommonTag tagName="겨울쿨" />
<CommonTag tagName="등" />
<CommonTag tagName="등등" /> */}
{profile?.trouble.map((item, index) => (
<CommonTag key={index} tagName={item} />
))}
</div>
<button>프로필 수정</button>
</div>
</>
);
};
export default Profile;
이것도 서버에서 데이터가 어떻게 들어오냐에 따라 수정해야 하지만 기본적으로 이렇게 들어올 것 같고 기획중에 프로필 사진에 대한 기획을 깜빡해버려서 이건 나중에 회의로 결정해야 할 것 같다. 중요한 부분은 아니기 때문에 이 후 추가 기능으로 구현하려고 한다. 내일은 카카오 소셜 로그인을 구현해보고 재희님이 작성해준 api 명세서를 보면서 데이터 조회부분을 하나씩 적용시킬 예정이다.
'개발 TIL' 카테고리의 다른 글
24.09.05 day61 작업 일지 (0) | 2024.09.05 |
---|---|
24.09.04 day60 jwt 오류 해결, 카카오 로그인 구현 중 (3) | 2024.09.04 |
24.09.02 day58 작업 일지 (4) | 2024.09.02 |
24.08.30 day57 작업 일지 (0) | 2024.08.30 |
24.08.29 day56 작업 일지 (0) | 2024.08.29 |