카테고리 없음
20240531_모놀리틱) 타입스크립트로 전환
일일일코_장민기
2024. 5. 31. 23:56
728x90
타입스크립트
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { NavLink, useNavigate } from 'react-router-dom';
interface MemberData {
id: number;
username: string;
email: string;
country: string;
area: string;
}
const MyPage: React.FC = () => {
const [memberData, setMemberData] = useState<MemberData | null>(null);
const navigate = useNavigate();
useEffect(() => {
axios.get('http://localhost:8888/MyPage', { withCredentials: true })
.then(response => {
if (response.status === 200) {
setMemberData(response.data);
} else if (response.status === 401) {
navigate('/LoginPage');
}
})
.catch(error => {
console.error('There was an error!', error);
navigate('/LoginPage');
});
}, [navigate]);
if (!memberData) {
return <div>Loading...</div>;
}
return (
<div>
<h1>My Page</h1>
<p>ID: {memberData.id}</p>
<p>Username: {memberData.username}</p>
<p>Email: {memberData.email}</p>
<p>Country: {memberData.country}</p>
<p>Area: {memberData.area}</p>
<h2>Cloth</h2>
<h2>Weather</h2>
<h2>Dust</h2>
<h2>GPT</h2>
<p>
<NavLink to="/ClothEditPage">옷장</NavLink><br/>
<NavLink to="/ChangePasswordPage">비밀번호 변경</NavLink><br/>
<NavLink to="/ChangeEmailPage">이메일 변경</NavLink><br/>
<h2>로그아웃</h2>
</p>
</div>
);
}
export default MyPage;
자바스크립트
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import {NavLink, useNavigate} from 'react-router-dom';
function MyPage() {
const [memberData, setMemberData] = useState(null);
const navigate = useNavigate();
useEffect(() => {
axios.get('http://localhost:8888/MyPage', { withCredentials: true })
.then(response => {
if (response.status === 200) {
setMemberData(response.data);
} else if (response.status === 401) {
navigate('/LoginPage');
}
})
.catch(error => {
console.error('There was an error!', error);
navigate('/LoginPage');
});
}, [navigate]);
if (!memberData) {
return <div>Loading...</div>;
}
return (
<div>
<h1>My Page</h1>
<p>{memberData.id}</p>
<p>Username: {memberData.username}</p>
<p>Email: {memberData.email}</p>
<p>Country: {memberData.country}</p>
<p>Area: {memberData.area}</p>
<p><h2>Cloth</h2></p>
<p><h2>Weather</h2></p>
<p><h2>Dust</h2></p>
<p><h2>GPT</h2></p>
<p>
<NavLink to="/ClothEditPage">옷장</NavLink><br/>
<NavLink to="/ChangePasswordPage">비밀번호 변경</NavLink><br/>
<NavLink to="/ChangeEmailPage">이메일 변경</NavLink><br/>
<h2>로그아웃</h2>
</p>
</div>
);
}
export default MyPage;
interface MemberData {
id: number;
username: string;
email: string;
country: string;
area: string;
}
인터페이스를 생성해서 커스텀 타입 생성
const MyPage: React.FC = () => {
리엑트에서 타입스크립트를 사용하기 위한 React.FC
- 다만 이 경우에는 children Props의 타입 체킹이 되지 않기 때문에 지양하라는 글이 많기도 했다.
- 다음 작업부터는 사용하지 않고 명시적으로 타입을 입력할 것
const [memberData, setMemberData] = useState<MemberData | null>(null);
인터페이스를 useState에 타입 지정
기타 변경된 코드
더보기
LoginPage
import {NavLink, useNavigate} from "react-router-dom";
import React, {useState, FormEvent, ChangeEvent} from "react";
import axios from "axios";
const LoginPage: React.FC = () => {
const [username, setUsername] = useState<string>('');
const [password, setPassword] = useState<string>('');
const navigate = useNavigate();
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
axios.defaults.withCredentials = true;
try {
const response = await axios.post('/login', {
username: username,
password: password
}, {
headers: {
'Content-Type': 'application/json'
}
});
if (response.status === 200) {
navigate('/MyPage');
} else {
console.log('로그인 실패');
navigate('/LoginPage');
}
} catch (error) {
console.error('Error:', error);
}
};
const handleUsernameChange = (event: ChangeEvent<HTMLInputElement>) => {
setUsername(event.target.value);
};
const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {
setPassword(event.target.value);
};
return (
<div>
<h1>로그인 페이지</h1>
<form id="loginForm" onSubmit={handleSubmit}>
<label>username: <input type="text" value={username} onChange={handleUsernameChange}/></label>
<label>password: <input type="password" value={password} onChange={handlePasswordChange}/></label>
<span id="loginErrorField"></span><br/>
<div>
<input type="submit" value="로그인"/>
</div>
</form>
<p>
<NavLink to="/RegisterPage">회원가입 페이지</NavLink><br/>
<NavLink to="/FindUserInfo">회원 정보 찾기 페이지</NavLink><br/>
</p>
</div>
);
}
export default LoginPage;
RegisterPage
import React, { useEffect, useState } from "react";
import { NavLink, useNavigate } from "react-router-dom";
import axios from "axios";
const RegisterPage: React.FC = () => {
const [username, setUsername] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [email, setEmail] = useState<string>("");
const [country, setCountry] = useState<string>("");
const [area, setArea] = useState<string>("");
const [countryList, setCountryList] = useState<string[]>([]);
const [areaList, setAreaList] = useState<string[]>([]);
const [existUsername, setExistUsername] = useState<string>("");
const [existEmail, setExistEmail] = useState<string>("");
const [checkAuthorizationCodeField, setCheckAuthorizationCodeField] = useState<string>("");
const [code, setCode] = useState<string>("");
const navigate = useNavigate();
useEffect(() => {
fetch("/findCountries")
.then((response: Response) => response.json())
.then(function(result: string[]){
setCountryList(result);
if(result.length > 0){
setCountry(result[0]);
}
})
}, []);
useEffect(() => {
fetch(`/findAreasByCountry?country=${country}`)
.then((response: Response) => response.json())
.then(function(result: string[]){
setAreaList(result);
setArea(result[0]);
})
}, [country]);
// 아이디 중복 체크
const usernameAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
const newUsername = event.target.value;
setUsername(newUsername);
try {
const response = await axios.post<boolean>(`/usernameAjax?username=${newUsername}`, {}, {
headers: {
"Content-Type": "application/json"
}
});
if (response.status === 200) {
setExistUsername(response.data ? "아이디 중복" : "");
}
} catch (error) {
console.error('Error checking username:', error);
}
}
// 이메일 중복 체크
const emailAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
const newEmail = event.target.value;
setEmail(newEmail);
axios.defaults.withCredentials = true;
try {
const response = await axios.post<boolean>(`/emailAjax?email=${newEmail}`, {}, {
headers: {
"Content-Type": "application/json"
}
});
if (response.status === 200) {
setExistEmail(response.data ? "이메일 중복" : "");
}
} catch (error) {
console.error(error);
}
}
// 이메일 인증 코드 요청
const emailAuthorizationCode = async () => {
axios.defaults.withCredentials = true;
try {
const response = await axios.post(`/emailAuthorizationCode?email=${email}`, {}, {
headers: {
"Content-Type": "application/json"
}
});
if (response.status === 200) {
alert("인증번호가 메일로 전송되었습니다.");
}
} catch (error) {
console.error(error);
}
}
// 인증 코드 확인
const codeAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
const newCode = event.target.value;
setCode(newCode);
const cookies = document.cookie.split(";").map(cookie => cookie.split("=")).find(([name]) => name.trim() === "authorizationCode");
if (cookies && cookies[1] === newCode) {
setCheckAuthorizationCodeField("확인되었습니다.");
} else {
setCheckAuthorizationCodeField("인증번호 오류");
}
}
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
let errorMessage = '';
switch (true) {
case existUsername === "아이디 중복":
errorMessage = '아이디 중복 상태입니다.';
break;
case existEmail === "이메일 중복":
errorMessage = '이메일 중복 상태입니다.';
break;
case checkAuthorizationCodeField === "인증번호 오류":
errorMessage = '코드 불일치 상태입니다.';
break;
default:
axios.defaults.withCredentials = true;
try {
const response = await axios.post("/saveUser", {
username: username,
password: password,
email: email,
country: country,
area: area
}, {
headers: {
"Content-Type": "application/json"
}
});
if (response.status === 200) {
navigate("/LoginPage");
} else {
navigate("/RegisterPage");
}
} catch (error) {
console.error("Error: ", error);
}
}
if (errorMessage !== "") {
alert(errorMessage);
}
}
return (
<div>
<form id="registerForm" onSubmit={handleSubmit}>
username:
<input type="text" id="username" name="username"
onChange={usernameAjax}
required minLength={3} /><br />
<span id="existUsername">{existUsername}</span><br />
password:
<input type="password" id="password" name="password"
onChange={(event) => setPassword(event.target.value)}
required minLength={3} /><br />
email:
<input type="email" id="email" name="email"
onChange={emailAjax}
required minLength={3} /><br />
<span id="existEmail">{existEmail}</span><br />
인증번호:
<input type="text" id="authorizationCode" onChange={codeAjax} />
<input type="button" id="sendEmail" value="인증번호 보내기" onClick={emailAuthorizationCode} /><br />
<span id="checkAuthorizationCodeField">{checkAuthorizationCodeField}</span><br />
country:
<select id="country" value={country} onChange={(event) => setCountry(event.target.value)}>
{countryList && countryList.map((country: string, index: number) => (
<option key={index} value={country}>{country}</option>
))}
</select><br />
area:
<select id="area" value={area} onChange={(event) => setArea(event.target.value)}>
{areaList && areaList.map((area: string, index: number) => (
<option key={index} value={area}>{area}</option>
))}
</select>
<input type="submit" value="회원가입" />
</form>
<p>
<NavLink to="/loginPage">로그인 페이지</NavLink>
</p>
</div>
);
}
export default RegisterPage;
App
import main from './images/main.jpg';
import LoginPage from './path/beforeLogin/LoginPage';
import ClothEditPage from './path/afterLogin/ClothEditPage'
import RegisterPage from "./path/beforeLogin/RegisterPage"
import './App.css';
import React, { useState, useEffect, FormEvent } from "react";
import {HashRouter, Routes, Route, NavLink, useNavigate, useLocation} from "react-router-dom";
import MyPage from "./path/afterLogin/MyPage";
import axios from "axios";
const App: React.FC = () => {
return (
<HashRouter>
<div className="App">
<header className="mainImage">
<NavLink to='/loginPage'><img src={main} className="App-logo" alt="logo" height={"100px"}/></NavLink>
</header>
<Routes>
<Route path='/' element={'MainPage'}/>
<Route path='/LoginPage' element={<LoginPage></LoginPage>}/>
<Route path='/RegisterPage' element={<RegisterPage></RegisterPage>}/>
<Route path='/FindUserInfo' element={<FindUserInfo></FindUserInfo>}/>
<Route path='/ViewUsername' element={<ViewUsername></ViewUsername>}/>
<Route path='/ViewChangedPassword' element={<ViewChangedPassword></ViewChangedPassword>}/>
<Route path='/MyPage' element={<MyPage></MyPage>}/>
<Route path='/ClothEditPage' element={<ClothEditPage></ClothEditPage>}/>
<Route path='/ChangePasswordPage' element={<ChangePasswordPage></ChangePasswordPage>}/>
<Route path='/ChangeEmailPage' element={<ChangeEmailPage></ChangeEmailPage>}/>
<Route path='/*' element={'Not Found'}/>
</Routes>
</div>
</HashRouter>
);
}
function FindUserInfo() {
const [email, setEmail] = useState<string>("");
const [username, setUsername] = useState<string>("");
const [passwordEmail, setPasswordEmail] = useState<string>("");
const navigate = useNavigate();
const handleUsernameSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
axios.defaults.withCredentials = true;
try{
const response = await axios.post(`/ViewUsername?email=${email}`, {}, {
headers: {
"Content-Type": "application/json"
}
});
if (response.status === 200) {
navigate("/ViewUsername", { state: { username: response.data } });
} else {
navigate("/FindUserInfo")
}
} catch (error: any){
console.error("Error: ", error.response ? error.response.data : error.message);
navigate("/FindUserInfo");
}
}
const handlePasswordSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
axios.defaults.withCredentials = true;
const response = await axios.post("/SendPassword", {
username: username,
email: passwordEmail
}, {
headers: {
"Content-Type": "application/json"
}
});
if(response.status === 200){
console.log(response.data)
navigate("/ViewChangedPassword")
} else {
navigate("/FindUserInfo")
}
}
return (
<div>
<form method="post" action="/FindUsernameByEmail" onSubmit={handleUsernameSubmit}>
email: <input type="email" name="email" onChange={(event) => setEmail(event.target.value)}/><br/>
<input type="submit" value="아이디 찾기"/>
</form>
<form method="post" action="/UpdatePasswordByEmail" onSubmit={handlePasswordSubmit}>
id: <input type="text" name="username" onChange={(event) => setUsername(event.target.value)}/>
email: <input type="email" name="email" onChange={(event) => setPasswordEmail(event.target.value)}/><br/>
<input type="submit" value="비밀번호 찾기"/>
</form>
<p>
<NavLink to="/loginPage">로그인 페이지</NavLink>
</p>
</div>
)
}
function ViewUsername(){
const [username, setUsername] = useState<string>('');
const navigate = useNavigate();
const location = useLocation();
useEffect(() => {
const usernameFromState = location.state?.username;
if (usernameFromState) {
setUsername(usernameFromState);
} else {
navigate("/FindUserInfo");
}
}, [location.state, navigate]);
return(
<div>
<h1>아이디 출력</h1>
<p>username: {username}</p>
<p>
<NavLink to="/loginPage">로그인 페이지</NavLink><br/>
<NavLink to="/RegisterPage">회원가입 페이지</NavLink><br/>
<NavLink to="/FindUserInfo">회원 정보 찾기 페이지</NavLink><br/>
</p>
</div>
)
}
function ViewChangedPassword(){
return(
<div>
임시비밀번호로 변경되었습니다.
<p>
<NavLink to="/loginPage">로그인 페이지</NavLink>
</p>
</div>
)
}
function ChangePasswordPage() {
const [password, setPassword] = useState<string>("");
const navigate = useNavigate();
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
axios.defaults.withCredentials = true;
try {
const response = await axios.post("/UpdatePasswordByUsername",
{password: password},
{headers: {'Content-Type':'application/json'}
});
if(response.status === 200){
navigate('/=========================');
} else {
console.error("비밀번호 변경 실패")
navigate('/=========================');
}
} catch (error) {
console.error("Error: ", error)
}
}
return (
<div>
<form id="ChangePasswordForm" onSubmit={handleSubmit}>
New Password: <input type="text" value={password}
onChange={(event) => setPassword(event.target.value)}/>
<input type="submit" value="변경"/>
</form>
<p>
<NavLink to="/MyPage">돌아가기</NavLink><br/>
</p>
</div>
)
}
function ChangeEmailPage() {
const [email, setEmail] = useState<string>("");
const navigate = useNavigate();
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
axios.defaults.withCredentials = true;
try{
const response = await axios.post("/UpdateEmailByUsername",
{email: email},
{
headers: {
'Content-Type':'application/json'
}
});
if(response.status === 200){
navigate('/=========================');
} else {
console.error("이메일 변경 실패")
navigate('/=========================');
}
} catch (error) {
console.error("Error: ", error)
}
}
return(
<div>
<form id="ChangeEmailForm" onSubmit={handleSubmit}>
email: <input type="text" value={email} onChange={(event) => setEmail(event.target.value)}/>
<input type="submit" value="변경"/>
</form>
<p>
<NavLink to="/MyPage">돌아가기</NavLink><br/>
</p>
</div>
)
}
export default App;