서버의 도움을 받아 회원가입 - 로그인 - 메인 페이지로 로그인 유저 넘기는 과정까지 진행해보았다. 목데이터가 아닌 실제 서버랑 통신하게 되면서 오류도 많이 봤지만, 이런저런 정보를 받아보면서 재밌었던 것 같다.
회원가입
const navigate = useNavigate();
const [id, setIdValue] = useState('');
const [pw, setPwValue] = useState('');
const onSubmit = (e) => {
// email : justpoy@email.com
// pasword : 11111
e.preventDefault();
fetch("http://localhost/users/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: id,
nickname: "FixedNickname",
password: pw,
}),
})
.then((res) => console.log(res))
.catch((error) => console.log(error));
navigate("/login");
}
input 태그에서 onChange()를 통해 id, pw 값을 받아두었다. 목데이터를 받을 때처럼 fetch를 작성했다가 400번대 에러를 한참 늦게 해결하게 되었는데, 헤더와 바디의 형식 때문이었다.
//오류
fetch("localhost:8000/users/signup", {
method: "POST",
body: {
email: id,
nickname: "FixedNickname",
password: pw,
},
})
.then((res) => console.log(res))
.catch((error) => console.log(error));
목데이터는 만들면서 JSON에 객체로 어떻게 받을지 다 정해뒀기 때문에 이렇게 받아도 문제는 없었다.
// 해결
fetch("localhost:8000/users/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: id,
nickname: "FixedNickname",
password: pw,
}),
})
.then((res) => console.log(res))
.catch((error) => console.log(error));
포스트맨으로 통신을 성공해왔기 때문에 헤더에 Content-Type으로 json 은 자동으로 담겨갈 것이라고 생각했다.. API 명세서에 header, body를 기재해주셨음에도 간과한 탓이 크다.
특히 body에서 JSON.stringify를 써주지 않으면, 객체가 아닌 String 덩어리가 되어서 받게 된다,, 주고받을 때 형식을 잘 지켜야 함에 유의해야 한다.
통신에 성공하면 다시 로그인 화면으로 돌려줘야 하므로, useNavigate 훅을 사용했다.
로그인
const onSubmit = (e) => {
e.preventDefault();
fetch("http://localhost:8000/users/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: idValue,
password: pwValue,
}),
})
.then((res) => res.json())
.then((res) => {
localStorage.setItem("Authorization", res.access_token);
navigate("/");
});
};
로그인 역시 회원가입과 마찬가지로 id, pw 인풋 태그에 입력한 값을 state로 받아두고 사용했다. 회원가입에서 겪었던 문제를 해결하기 위해 형식을 지켜서 보내주며, 통신에 성공했다면 로그인한 유저 아이디에 대한 토큰을 받게 된다.
id, pw에 맞는 유저 정보를 가져오기만 하면 되기 때문에 GET을 사용해야 하는 게 아닌가 했지만, GET 방식은 데이터가 header에 담겨가서 URL에 id와 pw가 노출되게 된다. POST는 데이터가 바디에 있어서 정보를 보낼 때 URL에 노출될 일이 없다.
// GET
http://localhost:8000/users/login?id=loginuser&pw=12345
// POST
http://localhost:8000/users/login
로그인을 성공해서 토큰을 받으면 localstorage에 담아두고 메인 페이지로 넘어간 다음, 메인 페이지에서 토큰을 꺼내 유저 정보를 통신하게 만들었다. localstorage에 넣으면서 쿠키를 발급하는 방법도 있다고 하는데 이번 방법에서는 구현하지 못했다.
fetch의 then으로 응답을 받는 부분을 보면 토큰을 저장하면서 navigate('/')를 통해 메인 페이지로 이동하고 있다. 처음 navigate는 fetch 밖에 있었는데 비동기로 인한 오류를 만나게 되었다. onSubmit 함수가 실행될 때 fetch로 토큰을 받는 동안 navigate('/')가 실행되어 메인 페이지로 넘어가기 때문.
해결책으로 .then 안에 넣어 통신이 끝나면서 넘어가도록 했지만, fetch와 navigate()가 같이 있는 구조가 안전해 보이지는 않는다.. 지금이야 단순한 로직이지만 조금 더 복잡해질 때도 비동기를 이렇게 해결하는 건 좋은 방법이 아닐 것 같다.
메인 페이지
const [userId, setUserId] = useState("LoginUser");
useEffect(() => {
fetch("http://localhost/users/me", {
method: "GET",
headers: {
Authorization: localStorage.getItem("Authorization"),
},
})
.then((res) => res.json())
.then((res) => (res.email ? setUserId(res.email) : navigate("/login")));
}, []);
userId에 초기값을 두고, 메인 페이지가 열린다면 최초 랜더링 후에, useEffect() 훅을 실행하면서 토큰을 불러온다. localStorage에 담아두었기 때문에, getItem으로 가져와 GET으로 로그인 정보를 받아오며, 받아온 정보에 email이 있다면 Id에 email을 보내며 다시 랜더링 한다. email이 없는 경우는 최초에 로그인 없이 메인 페이지에 접근 시 바로 로그인 창으로 보내기 위함이다.
axios로 사용해보고 싶었지만, fetch로 사용하는 방법에 대해 익숙해지는 것이 먼저라고 생각했다.
API 명세서... 꼭 먼저 확인할 것
fetch의 비동기에 대해 공부하기
'Programing > React' 카테고리의 다른 글
[React / TypeScript] Debouncing을 활용한 검색기능 구현 (0) | 2022.11.10 |
---|---|
[React] vite 프로젝트 만들기 (0) | 2022.11.03 |
[React] 댓글 입력 오류 (0) | 2022.08.19 |
[React] 소셜웹페이지 - 자바스크립트 ➡️ 리액트 변환 (0) | 2022.08.17 |
[React] css 모듈과 proptype (0) | 2022.07.29 |