1. 회원가입 로직 구현

회원가입 페이지의 input값과 유효성 검사에 따라 에러메세지를 보여줘야 하므로 이를 상태로 관리해줘야한다.

상태 변경함수와 상태를 props로 전달해준다. 유효성 검사 로직을 true, false 값을 구현하는데 헷갈렸다.

Lodash 구현 실패…

페어 프로그래밍을 할 때는 lodash 잘 썼는데, server랑 연동을 하니 왜 lodash 안써지냐 ?

내일 해결하자.

2. 라우터 구현

라우터 구현을 며칠째 쓰는지 모르겠다…

라우터를 제대로 이해해야만 했다…

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
// App.js
const isSigned = async () => {
const { data } = await axios.get("/auth");

return data.success;
};

const routes = [
{ path: "/", component: Home },
{ path: "/rank", component: Rank, guard: isSigned, redirectTo: Signin },
{ path: "/signin", component: Signin },
{ path: "/signup", component: Signup },
{ path: "/matching", component: MatchingCards },
];

class App extends Components {
...
router(path = window.location.pathname) {
// header 에서 클릭이벤트로 href 를 받아서 path에 담는다.
const route = routes.find(route => route.path === path);

// change url path
(async () => {
!route.guard || (await route.guard())
? this.setState({ Page: route.component })
: this.setState({ Page: route.redirectTo });
})();
}
}
  • “pjax 방식으로 라우터를 구현하기 위해서 서버와 도움이 필요하다”라는 말이 이제는 이해가 된다. ajax 방식은 url이 변경되지 않아 seo에 문제가 있어서 이를 해결하기 위해서 pushState를 통해 history API를 구현해준다.

  • 그리고 router 함수는 path를 받아서 해당 path의 컴포넌트를 가지는 route를 찾아서 현재 페이지로 렌더링해준다.

  • 이 때, routes 배열안의 어떤 라우터는 접근 권한이 필요한 라우터가 있는데, 이들한테는 guard라는 프로퍼티가 존재한다. 그러므로 router 함수에서도 guard라는 프로퍼티가 있을 때, 또 guard 프로퍼티의 값이 true, false냐에 따라 컴포넌트를 다르게 보여줘야하는 로직을 짜야한다.

이 개념이 CSR(Client Side Rendering)이다. 서버에서는 다음과 같이 코드를 구현해주었다.

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
32
33
34
35
36
37
38
39
// server.js
const auth = (req, res, next) => {
const accessToken = req.headers.authorization || req.cookies.accessToken;

try {
const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_KEY);
console.log(`😀 사용자 인증 성공`, decoded);
next();
} catch {
console.error("😱 사용자 인증 실패..");
console.log(accessToken);
return res.redirect("/signin");
}
};

const isSigned = (req, res) => {
const accessToken = req.headers.authorization || req.cookies.accessToken;

try {
const decoded = jwt.verify(accessToken, process.env.JWT_SECRET_KEY);
console.log(`😀 사용자 인증 성공`, decoded);
res.send({ success: true });
} catch {
console.error("😱 사용자 인증 실패..");
res.send({ success: false });
}
};

// auth route
app.get("/signin", (req, res) => {
res.sendFile(path.join(__dirname, "./public/index.html"));
});

app.get("/auth", isSigned);

app.get("*", auth, (req, res) => {
// auth 미들웨어
res.sendFile(path.join(__dirname, "./public/index.html"));
});
  • 서버에서는 모든 경로에서 get 요청이 들어오면 auth 함수의 내부의 로직을 기준으로 사용자가 JWT 토큰이 있는지 유무를 판단하여 결과를 반환한다. 이 결과에 따라 rootContainer를 응답으로 보내주고 클라이언트는 이를 받아서 조건에 맞게미리 구현해둔 router 함수로 화면에 렌더링을 해준다.

  • 그리고 서버에서 또 다른 함수로 JWT 토큰 유무에 따라 성공, 실패 결과를 전달해줘야하므로 auth 와 별개인 isSignin() 함수를 만들어줬다.

우리는 이 부분에서 auth 라는 함수 하나로만 해결하려고 하다 보니 res.send로 오류를 보내면 /rank URL로 직접 요청시 오류 페이지가 보이게 되고 redirect 를 해주자니 오류가 안보내져서 클라이언트에서 router 함수 로직을 구현할 수 없는 딜레마를 겪었다.

그 결과 클라이언트의 isSigned 비동기 함수가 axios로 get 요청을 보내서 data(boolean)를 반환해준 값을 guard 프로퍼티에 등록해주었다.

이를 사용해 router 함수에서 로직을 구현해주었다.

소감

오늘은 월요일이라서 그런지 머리도 잘 안돌아가고 주말에 푹 쉬어서 죄책감이 약간 들어서 자존감도 떨어지는 하루였다.

그래도 늘 이런 생각을 하면 달라지는 것은 없다. 이런 생각을 할 시간에 좀 더 연구하고 공부하는 게 나의 미래에 더 도움이 된다.

이제 미니 프로젝트 마감이 이번주 금요일로 다가왔으니 앞으로 며칠만 더 힘내서 열심히 공부하고 배운것을 꼼꼼하게 정리하도록 해야겠다.