이번에는 로그인 컴포넌트를 만들 차례이다. 그전에 저번에 회원가입 컴포넌트를 만들면서 2가지 이슈가 있었는데, 한가지는 axios이고 다른 건 keyboardavoidingview이다.
axios에 관한 것은 조금 있다가 다시 설명할 예정이고 keyboardavoidingview에 대해서 설명하려고한다.
회원가입 컴포넌트에서도 그렇고 이번에 만들 로그인 컴포넌트도 마찬가지이지만 input 컴포넌트를 이용해서 무엇인가를 입력할 때 키보드 창이 올라오게 된다.
input창이 키보드보다 위에 위치한 상태에서 input을 누르면 별 지장이 없다. 하지만 키보드 영역에 위치한 input의 경우에는 키보드에 가려져서 스크롤을 밑으로 내려줘야한다. 심지어 밑으로 내릴 스크롤이 없을 경우, 키보드에 완전히 가려져서 안보이게 된다. 그래서 이것을 해결해주기 위해서 리액트 네이티브의 KeyboardAvoidingView를 사용하였다.
우선 컴포넌트를 KeyboardAvoidingView로 감싸준다.
KeyboardAvoidingView에 주로 쓰이는 props는 몇가지가 있는데 주로 사용한 것은 다음의 2가지이다. (react native 공식문서)
- behavior : Specify how to react to the presence of the keyboard.
- keyboardVerticalOffset : This is the distance between the top of the user screen and the react native view, may be non-zero in some use cases. Defaults to 0.
behavior에는 3가지 option이 있다.
- height
- position
- padding
근데 이 3가지가 어떻게 동작하는지 여기저기 많이 찾아봤지만 명확한 설명이 없어서 3가지를 바꿔가면서 적용해본 결과 다음과 같이 동작했다.
- height는 input창이 키보드로부터 keyboardVerticalOffset 거리만큼 위치하게 된다.
input이 키보드가 나오는 영역에 위치하면 오프셋거리만큼 떨어져서 나오는 것 같았다.
- position은 input이 현재 위치한만큼 상대적으로 키보드로부터 위치하게 된다.
input이 현재 view의 맨 아래에 있으면 키보드에 딱 달라붙어서 나오고 조금 떨어져 있으면 그만큼 조금 떨어져서 나오는 것 같았다.
- padding은 키보드로부터 keyboardVerticalOffset만큼 padding을 만든다.
height와 비슷한데 패딩이 적용되서 그만큼 여백이 생기고 input이 위치하는 것(?) 같았다.
사실 KeyboardAvoidingView가 적용만하면 원하는 대로 잘 작동할 줄 알았는데, 스크롤뷰에서는 잘 작동하지 않아서 적용하는데 많이 애먹었다. 그래서 react-native-keyboard-aware-scroll-view 라이브러리를 적용해볼까 했는데, 타입스크립트 선언파일도 없는 것 같고 그래서 적용하지 못했다.
그래서 어찌어찌 해서 height로 결국 적용을 하였는데 키보드 영역에 input이 위치한 경우에는 그럭저럭(?) 작동을 하는 것 같은데 내가 원하는 그림대로 깔끔하게 작동하지는 않는 것 같다. 그래서 뭔가 많이 찝찝하게 구현이 되었다.
KeyboardAvoidingView의 정확한 작동 원리는 나중에 좀 더 심도있게 공부를 해야할 것 같다.
아무튼 KeyboardAvoidingView를 어설프게 적용을 했었다.
로그인 컴포넌트
로그인 컴포넌트의 구성은 크게 빌리집 로고, 이메일 input, 비밀번호 input, 로그인 버튼, 회원가입 버튼으로 구성되어 있다.
로그인 화면은 어플의 대문이자 처음 만나는 화면이기 때문에 디자인이나 이런 것을 좀 더 신경써서 만들어야겠다고 생각했다.
우선 우리 프로젝트의 컨셉 컬러가 보라색이기 때문에 rgb를 검색해서 깔끔한 느낌이 나는 보라색계열로 background color를 정해주었다.
Logo
어플 로고와 splash에 이용했던 기존 로고는 보라색으로 되있기 때문에 보라색 바탕에 적용할 경우, 보이지가 않아서 로고를 만들었던 홈페이지에서 하얀색으로 다시 만들었다. 그리고 elements의 image 컴포넌트를 이용해서 넣어주었다.
이메일 input, 비밀번호 input
회원가입 컴포넌트에 사용하였던 input과 똑같은 방식으로 만들어주었다. 조금 달라진 점은 좀 더 디자인을 신경써서 borderRadius를 적용하였고, 색깔도 보라색으로 깔맞춤을 해주었다.
여기에서도 KeyboardAvoidingView 를 적용했는데, 그 이유는 비밀번호 input이 키보드 창에 살짝 가려서 이다.
근데 그냥 KeyboardAvoidingView만 적용하니까 또 제대로 작동을 안해서 회원가입 컴포넌트를 만들 때처럼 임의로 스크롤뷰를 만들어주고 그걸 KeyboardAvoidingView로 다시 감싸주고 height를 적용시켜주었다. 여기에서는 스크롤 될것이 없어서 그런지 의도한대로 잘 작동하는 듯 했다. 비밀번호 input을 누르면 키보드에 안가리고 잘 나온다.
그리고 유저가 로그인 할때의 다양한 예외처리를 error 메시지를 통해 보여주게 하였는데 이건 밑에서 설명하려고 한다.
로그인 버튼
로그인 버튼을 누르게 되면 이메일에 입력한 값과 비밀번호에 입력한 값을 가지고 서버로 요청을 보내게 된다.
이때 고려한 것이 유저가 다양한 액션을 할 수가 있는데 예를들어 아무것도 입력안하고 로그인 버튼을 누른다던가, 틀린 이메일 또는 비밀번호 라던가, 존재하지않는 이메일이라던지.. 등등 그래서 이러한 사항에 대해서 예외처리를 해줄 필요성이 있었다. 그래서 조건문과 응답을 가지고 예외 처리를 다음과 같이 해주었다.
먼저 조건문을 통해 이메일이나 비밀번호를 입력하지 않고 로그인 버튼을 누를 때이다. input 컴포넌트에는 errorMessage props를 통해 에러 메시지를 컴포넌트 하단에 보여줄 수가 있다. 그래서 에러메시지를 state로 잡고 set함수를 만들어서 입력하지 않고 로그인 버튼을 누르면 해당하는 set함수로 인해서 에러 메시지가 set되게 되고 보여지게 된다.
그리고 만약 둘다 입력이 되어 있다면, 그 다음으로는 서버로 이메일과 비밀번호를 요청을 보낸다.
서버에서 로그인 api는 둘다 일치할 때 200 코드, 이메일이 존재하지않으면 404 (이메일이 틀림), 이메일은 맞지만 비밀번호가 틀린 경우 401 코드로 응답한다.
그래서 then과 catch를 이용해 각각 코드에 따라 분기해서, 404 코드로 응답이 오면 메시지를 이메일이 존재하지 않는다고 보여주고, 401일 경우에는 비밀번호 input의 에러메시지를 보여주도록 하였다.
그리고 둘다 일치할 경우에는 200 코드를 받고 then의 코드들이 실행된다.
then에서는 200코드를 받을 경우, 서버로부터 JWT와 로그인한 유저의 id, 이름을 같이 응답으로 받게 된다. 이것을 asyncstorage에 저장해주기 위해서 async로 비동기처리가 되도록 하였고, 그 이후에 app (bottom tab navigator)로 navigate되어 어플 홈 화면으로 넘어가게 된다. 앞서 switch navigator로 로그인과 app을 분기해줬기 때문에 로그인 이후에는 로그인 화면으로 다시 넘어오지 않는다.
회원가입 버튼
회원가입 버튼을 누를 시에는 모바일 인증 화면으로 navigate되고 여기서 인증을 거치면 전에 만들었던 회원가입 화면을 넘어가게 된다.
axios 및 asyncstorage
회원가입 컴포넌트와 로그인 컴포넌트를 만들면서 axios를 활용하였다. 이 과정들은 아직 JWT이 없는 인증 전 단계이므로 평범하게 axios로 할 수 있다. 하지만 로그인 이후의 요청들은 인증 상태를 확인하기 위해서 JWT를 계속 보내주어야 한다.
JWT는 로그인 시 asyncstorage에 위에처럼 저장이 되기 때문에 다른 axios요청 시마다 asyncstorage에서 JWT를 꺼내고 헤더에 다시 담아주는 코드를 작업해야한다. 이것은 매우 비효율적일 것 같은 생각이 들어서 방법이 없을까 하다가 찾은 것이 axios instance 및 interceptor를 활용한 방법이다.
util 폴더를 만들고 axios instance를 만들어 주었다.
기본적인 config 옵션으로 baseURL을 잡아주어서 axios 코드를 만들 때 url을 전부 입력안하고 서버의 endpoint만 깔끔하게 입력할 수 있도록 하였다. 헤더 또한 content type을 정해주어서 일일히 입력하지 않아도 된다.
interceptor는 가로채다라는 의미처럼 axios 요청을 보내기 직전 또는 응답을 받은 직후에 가로채서 어떤 기능이 동작하도록 해준다. 그래서 request를 이용해서 서버에 요청 직전에 asyncstorage의 JWT와 userId 등을 받아와서 헤더로 실어보내줄 수 있도록 만들어주었다.
이렇게 만들어주니 axios 코드를 만들 때 별도로 작업을 해주지 않아도, 알아서 JWT와 필요한 것들을 헤더에 담아주고, url 등 코드를 훨씬 간결하게 쓸 수 있게 되었다. 중복코드가 많이 줄어든 것이다. 정말 강력한 기능인 것 같다.
그래서 이때까지 axios 코드를 보면 그냥 axios가 아닌 axiosInstance를 쓰고 있던 것이다.
asyncstorageHelper도 asyncstorage에서 저장하고, 가져오는 것이 비동기 처리라서 따로 helper로 분리해서 만들어서 쓰게 하였다.
로그인 화면 자체는 많은 것이 없지만 어플의 시작점인 것과 중요한 인증에 대해서 다루는 컴포넌트라서 생각보다 많은 작업들을 했던 것 같다. 특히 디자인도 많이 신경써서 style을 엄청 고민하고 한땀한땀 작성했던것 같다.
'Project Devlog > BillyZip' 카테고리의 다른 글
Final Project - (13) 2020_0210 (0) | 2020.02.10 |
---|---|
Final Project - (12) 2020_0209 (0) | 2020.02.09 |
Final Project - (10) 2020_0207 (0) | 2020.02.07 |
Final Project - (9) 2020_0206 (0) | 2020.02.06 |
Final Project - (8) 2020_0205 (0) | 2020.02.05 |
댓글