본문 바로가기
Project/Client

첫 리액트 개발 도전기(2) - 일을 시작하는 순간, motiiv

by 세이(Sayer) 2021. 2. 17.
728x90

본 포스트는 리액트로 개발하는 과정에서 했던 고민에 대한 이야기를 담고 있습니다.

다크 모드가 정말 예쁜 모티브 구경 가기 : www.motiiv.site/



💡
상태 관리💡

처음 배우는 리액트로 프로젝트를 진행하면서 가장 어려웠던 것은 state 관리였다. 우리가 프로젝트를 진행하면서 사용한 기술 스택은 아래와 같다.

* React
* Redux
* Redux-Saga
* styled-components

리덕스(redux)를 찾아보면 높은 확률로 아래의 이미지를 만날 수 있다. 리액트에서 props를 필요한 곳으로 내려보내기 위해 해당 props 를 사용하지 않는 컴포넌트를 거쳐가야 하는 경우 불필요한 리렌더링이 발생하는 문제가 있다. 리덕스는 간단히 말하면 그런 상태들을 따로 빼놓는 저장소(스토어)를 제공해 이러한 문제점을 해결하는 방법이다.

store에 state를 업데이트하는 이벤트가 발생했을 때 dispatch(액션 생성 함수 호출)하면 ➡ 해당 액션 생성 함수에서 생성된 액션의 type에 따라 Reducer에서 state의 변화를 일으키는 방식으로 사용된다. 처음엔 개념이 잘 이해가 안돼서 store라는 별도의 state 저장 공간 있음! useSelector로 꺼내오고 dispatch 찔러서 업데이트함! 이라고 외웠던 기억이 난다.

그렇다면 리덕스 사가(redux-saga)는? 리덕스의 미들웨어로 비동기 작업, 로깅 등의 확장적인 작업들을 할 수 있게 해준다. 액션을 모니터링하고 있다가, 특정 액션이 발생하면 이에 따라 정해진 작업을 하는 방식이다. 특정 액션이 발생했을 때 상태 값이나 응답 상태 등에 따라 다른 액션을 디스패치 하거나 추가적인 로직을 적용 해야될 때 사용한다.

모티브에서는 아래와 같은 순서로 store의 state를 조회 및 업데이트했다.

1. 성공,실패 액션을 생성
2. 액션 호출 함수 생성
3. 해당하는 액션 호출시 Saga 실행
4. 요청된 것들 중 가장 마지막 요청만 처리 (여러 번 클릭 시 모두 처리되면 매우 비효율적!)
5. state 초기값 선언
6. 액션을 store에 저장하는 리듀서를 handleActions로 처리 ⬅ createRequestSaga에서 put(특정 액션을 dispatch)한 type에 따라 수행

예시로 회원가입의 경우를 작성해보았다. 위와 같은 흐름으로 store의 state를 관리했다.

나는 유저와 관련된 부분(프로필 조회, 프로필 수정, 회원 가입, 로그인)을 맡았기 때문에 스토어에서 state를 관리하는 코드를 작성할 일이 많았다. 프로필 조회의 경우 app.js 파일에서 useSelector로 store에 저장되어 있는 state들을 가져오면 되어서 간단했는데, 문제는 회원가입 과정이 순탄치 않았다^^...


---



💡소셜 로그인 & 회원가입💡

반응형 작업까지 완료한 소셜 로그인 모달창

영상을 보면 알 수 있듯이, 로그인 버튼을 누를 경우 카카오 계정으로 로그인해서 카카오 서버에서 정보를 받아온 뒤
➡ 그 정보들을 store에 찌르고 서버로 보내서
만약 DB에 해당 회원 정보가 있을 경우 해당 정보를 받아와 store에 넣고 useSelector로 유저 정보를 가져와 화면에 뿌려주고
DB에 회원 정보가 없을 경우에는 직군 선택 뷰로 넘어가서 선택한 직군 정보를 store에 저장해두고
다음 뷰에서 선택한 관심사 정보까지 모두 선택한 후 완료 버튼을 누르면 이 모든 정보를 store에 넣고 한 번에 서버로 넘겨주고
그 정보를 useSelector로 프로필 정보가 필요한 부분에 뿌려주어야 했다.

이 과정 중에서 가장 어려운 부분이 회원가입 마지막 단계에서 관심사를 고르는 부분이었는데, 처음엔 직군 정보와 관심사 정보를 하나씩 store에 저장하지 않고 해당 페이지에서 별도의 state를 선언해 저장해둔 다음에 한 번에 store에 dispatch로 찌르는 방식으로 코드를 작성했었는데 동기화가 정말 어려웠다. 사용자가 버튼을 다시 한 번 누르면 state에서 내용이 빠져야 하는데 한 박자씩 늦게 빠지거나 두 개 이상의 키워드가 한 번에 사라지는 등 너무 많은 문제가 발생해서 최후의 방법으로 버튼이 클릭될 때마다 store에 state를 찔러 넣도록 했다!

버튼 컴포넌트에 onClick이 발생할 때마다 해당 버튼의 이름을 dispatch로 store에 넣었고, 만약 버튼 컴포넌트가 onClick 되었는데 해당 이름이 이미 store에 존재하는 이름일 경우에는 삭제 처리했다. 이 작업은 삼항 연산자를 활용해서 처리했는데, 그 과정에서 리액트에서는 state가 변했다는 것을 감지해야 리랜더링이 되기 때문에 원본이 아닌 사본을 만드는 filter나 concat과 같은 방식을 사용해야 된다는 것을 알게 되었다. 정말이지 온몸으로 부딪쳐가며 배운 리액트 지식이었다. 이외에도 store에 저장된 관심사 개수가 1개 이상일 때만 완료 버튼이 활성화 되고, 3개 이상일 때는 또 다른 관심사를 추가할 수 없도록 하는 작업을 모두 처리했다. 카카오 로그인이 성공했을 때의 그 짜릿함은 아직도 생생하다. 아, 나도 소셜로그인 해본 개발자다! ( 작성하고 나니 간단한 코드지만 이걸 생각해내는 과정은 치열했다...)

어떻게든 해결하겠다고 반나절을 잡고 늘어져 완성해낸 handleActions 코드!

생각했던 것보다 리액트에서 카카오 소셜 로그인 API를 붙이는 작업은 어렵지 않았다. 나중에 나처럼 헤매는 초보 개발자들을 위해서 소셜 로그인 API 연결 방법과 예제 코드로 이해하는 리덕스를 정리해서 포스팅을 할까 계획중이다. 정말이지 안 해본 시도가 없을 정도로 모든 경우의 수를 시도해가며 완성해낸 기능이었다. 막내의 삽질을 답답해하지 않고 응원의 눈빛으로 기다려준 모티브 웹팟에게 정말 감사의 인사를 보낸다. 이런 문제를 해결해가는게 또 프로그래밍의 묘미지. 그렇고 말고. 아무쪼록 리액트 자체도 러닝 커브가 높은 편인데, 이렇게 짧은 기간 안에 상태 관리 방법까지 이것 저것 시도해 볼 수 있어서 정말 좋았다. 리액트의 엑기스를 제대로 맛본 느낌이랄까? (물론 엑기스를 정복하진 못했음.)

디자이너가 열심히 그린 뷰를 모니터에 그대로 옮겨놓는 작업도 state 관리만큼 신경 써서 진행했던 부분이었다! 여러가지 뷰 작업을 하면서 마진값 하나하나까지 디자인 시안과 똑같이 구현될 수 있도록 열심히 뷰를 구현했다. 우리 팀 디자이너들이 유저의 닉네임이 한글일 때와 영어일 때 프로필 모달에 뜨는 글씨 크기를 다르게 작업해뒀을 정도로 디자인을 너무 섬세하게 해둬서 나도 덩달아 눈에 불을 켜고 뷰를 구현했던 것 같다. 마지막 날 내가 작업한 뷰를 보면서 디자이너 영진 언니가 "아유 반응형까지 알아서 너무 잘해줬네."라는 말을 들었을 때의 그 안도감이란. 디자이너님들의 노고가 헛되지 않도록 정말 열심히 구현했습니다. 어흑.

요약하자면 정말 열심히 했고, 많이 배웠다는 말이다!


---



💡원활한 소통을 위하여
💡

두 번째 앱잼이어서 그랬는지는 몰라도 이번 앱잼은 완성에 대한 압박감을 느끼는 기간보다는 여러 사람과의 협업을 즐기는 기간으로 남았으면 좋겠다고 생각했다. 나는 물론이고, 우리 팀 모두에게도. 특히 같은 파트에 4명씩이나 함께 하게 된 것은 처음이라서 어떻게 해야 서로간에 소통이나 진행 상황 공유도 빠르게 할 수 있을까 고민했다. 그리고 내가 생각한 방법은 노션을 알차게 사용하는 것이었다!

웹팟 노션의 모습. 중간은 매일 적은 회의록이다. (왼쪽 : 갤러리뷰, 오른쪽 : 테이블뷰)

우선 리모트로 작업이 진행되고 있었기 때문에 카톡처럼 대화가 흘러가지 않고 서로 결정한 내용을 따로 정리해둘 공간이 필요했다. 언제든 찾아볼 수 있어야 하며, 공유한 자료들에 쉽게 접근이 가능해야 했다. 이러한 점들 때문에 회의록은 슬랙보다 노션에 남기는 것을 선택했다. 개발 막바지 기간에 정신 없이 제출 서류를 정리하는 것보다 미리 정리해두면 좋겠다 싶어서 아예 과제 제출용으로 페이지를 처음부터 정리했다. 제출과제를 언제든 바로 확인할 수 있도록 따로 탭을 마련해두었고, 회의에 참석하지 못해도 정확하게 팔로업이 가능하도록 매일 회의 내용을 기록으로 남겼고, 그 아래에는 언제든 개인 회고를 진행할 수 있도록 주차별로(웹팟의 경우 주마다 각자 개인 회고를 진행하고, 주말에 모여서 함께 회고를 나누며 파트 회고를 진행했다. 팀 작업에 있어 회고는 정말 중요하기 때문에 절대 빼먹지 않기로 약속했었다!) 개인 회고 탭을 만들어두었다.

특히 회의록의 경우 회의 시간에 공유했던 참고용 파일을 언제든 바로 확인할 수 있도록 테이블 뷰를 메인으로 했고, 여기에 갤러리뷰를 추가해서 매일 인상 깊은 사건이나 회의 마지막에 ZOOM을 캡쳐한 이미지를 꼭 넣어두었다. 지금 보니 꼭 타임 캡슐 같기도 하고 일기장 같기도 한게 회의록을 보면 어떤 농담을 했었는지도 모두 기억이 나서 이렇게 열심히 적어두길 참 잘했다고 생각하고 있다 ^-^ 가뜩이나 바쁜데 왜 이렇게 회의록을 굳이 매일 남기냐고 불만을 가질 법도 한데, 언제나 회의록을 남겨줘서 고맙다는 댓글을 잔뜩 달아주는 우리 웹팟 덕분에 정말 걱정 없이 즐겁게 개발할 수 있었다. 정말 고마워 우리 웹팟! 모디부 웹팟 최고야.


---



💡마
치며💡

motiiv는 내게 프론트의 매력을 흠뻑 느끼게 해주고, 서버 개발자로서 생각해봐야 할 부분들도 잔뜩 던져준 고마운 프로젝트다! 서버/프론트 모두 발 한 번씩은 담가봤으니 이제 나도 어디 가서 개발자라고 말해도 되는 걸까나? 👀 


SOPT의 엑기스 모음이라고 할 수 있는 멋진 우리 motiiv 팀! 코로나 때문에 한 공간에 모일 수 없어서 리모트로 작업을 해야 하는 어려운 상황에도 누구 하나 지친 기색 없이 매일 즐겁게 ZOOM에서 모이던 얼굴들이 새록새록 떠오른다. 짧은 시간 안에 이렇게 많은 것을 배울 수 있었던 건 정말 우리 팀이 멋진 선배들로 가득했기 때문이다. 기능 하나를 생각해내기까지 얼마나 많은 기획자의 고민이 있었는지, 버튼 모양 하나를 디자인하기까지 얼마나 많은 디자이너의 고민이 있었는지, DB의 테이블 관계 하나 하나를 연결하는 서버 개발자의 고민이 얼마나 치열했는지, 이 멋진 팀원들의 작업을 옆에서 지켜보며 깨달을 수 있었다. 클라이언트 개발자는 특히나 정말 모든 파트와의 소통이 중요한 파트였다. 그렇기 때문에 이렇게 각자의 자리에서 열심히 노력하는 모습을 제대로 볼 수 있었다고 생각하고, 이제야 조금 하나의 서비스를 만들어간다는게 어떤 사이클에 의해 진행되는 것인지 알게 된 것 같아서 클라 개발자에 도전하길 참 잘했다는 생각이 들었다.

최 강 모 디 부 11 인

이렇게 두 번째 앱잼도 성공리에 마무리!
아, 정말 어렵고 재밌었다!!

댓글