react-native 캠핑 어플 클론 프로젝트

김동하·2021년 1월 10일
2

react-native

목록 보기
5/9
post-thumbnail

프로젝트 영상

전체 동영상

프로젝트 요약

1) 소개

  • react native expo 기반 캠핑 장소를 찾는 어플리케이션 개발 프로젝트

2) 기간

  • 20.12.18 ~ 21.01.08 (14일간)

3) 인원

  • 프론트엔드 1명

4) 역할

  • 프론트엔드

사용 스택

1) react-native expo

  • react-native 입문이라 CLI대신 런닝커브가 낮은 expo를 사용함

2) redux

  • 전역 상태 관리로 redux를 사용함

디렉토리 구조

1) App.js

login.js에서 로그인에 성공하면 Home으로 넘어간다.

2) ScreenNavigator.js

  • bottom-tab 기능을 하는ScreenNavigator.js 에서 name에 따라 route 설정을 해준다.

  • 삼항 연사자를 통해 active 상태(클릭 했을 때) 다른 아이콘을 렌더한다.

3) 스크린

총 4개의 screen으로 구성되는데 사실 filter detail에 스택에 있어야 하는데 navigation 공부가 부족해서 tab과 stack을 만드는 것이 부족해 tab으로 놔뒀다. navigation 기술 부채다!

기능 소개

0) Social Login

  • 소셜 로그인을 후 사용자 정보를 AsyncStorage에 저장

  • async await을 통해 비동기적으로 실행

1) Home UI

  • Theme Color에 맞춰 이미지를 골랐다.

    1-1) Category List

  • 백엔드가 없었기 때문에 더미 데이터를 사용했다.Tab의 경우는

이렇게 키로 id와 name, place를 가지고 있는 배열을 flatList로 돌렸다. dispatch로 onPress할 때 id값을 가져오고 부모 컴포넌트인 Home.js에서 find를 이용해서 해당 id를 가진 객체를 state에 넣었다.

그리고 실제 해당 tab에 뿌려지는 컴포넌트에 그 리스트를 props로 넘긴다.

백엔드와 통신을 한다면 클릭할 때마다 query string을 보내서 탭에 맞는 데이터를 받아오면 되지만 더미 데이터를 사용해야 해서 이렇게 로직을 짰다.

2) Map

react-native-map에 제공하는 MapView 컴포넌트를 사용했다. 처음에 구조를 제대로 안 짜서 map tab, map container 그리고 map list가 각각 다른 컴포넌트가 되어버려 데이터를 주고 받는 데 아주 아주 골치가 아팠다. 시작하기 전에 구조를 잘 짜기...

  • Tab을 눌렀을 때 지도에 type에 맞는 데이터 렌더하기

이것도 home.js에서 tab을 눌렀던 것과 비슷하다.

먼저 하드 코딩으로 tab list를 만들고 부모 컴포넌트인 Detail.js에서 props로 내려준다. 이제 필요한 것은 리덕스와 useState다. 리덕스에서 state를 정의해준다.

reducer.js

필요한 것은 초기 state의 filters.type에 주입하는 것!

함수를 정의하고 onPress했을 때 해당 tab을 인자로 가져온다. 가장 아름다운 순간인데 setSelectedTabType이란 액션에 tab을 주는 것이 아니라 {type: tab.type} 이런 식으로 reducer로 넘어갔을 때를 고려해서 미리 할당한다!

이게 무슨 말이냐하면

reducer.js

filters에 있는 하나의 키만 수정하는 것이니까 전개 연산으로 다 flat으로 만들고 type:action.payload가 아니라 ...action.payload로 정의한다. 이렇게 되면 dispatch로 키 값만 잡아주면 state에 얼마나 많은 키가 있는지 상관없이 확장할 수 있다!!!

나는 닥터 스트레인지가 손을 휙휙 저어서 공간을 뚫고 거기에 손을 뻗어서 원하는 물건을 쏙 가져오는 느낌으로 이해했다.

  • 선택된 tab의 type을 적용해서 지도 렌더하기

useSelector로 filters를 가져오고 실제 렌더될 map 컴포넌트에서 로직을 짠다!

일단 row 데이터는 campingData를 state에 넣고 거기에 filteredList라는 변수를 이용해서 가공한다. 그리고 filter된 list를 렌더하면 끝!!

🚒 Learn

  • 여러 가지 상태에 따라 다른 배열을 만들어야 할 때 초기값이 될 배열(campings)를 삼항 연산자의 true에 정의하고 false에 fillter나 find 메서드를 정의하면 조건에 따라 다른 배열을 얻을 수 있다. if나 switch 없이도 어마어마하게 확장이 가능하다!

  • 즉, 삼항이라고 해서 꼭 true / false 두 가지 경우만 들어가는 것이 아니라 false에 얼마든지 커스텀마이징이 가능하다는 것. true가 아니면 false를 return라는 기본 정의를 조금만 뒤집어 생각하면 얼마든지 다르게 사용할 수 있다.

2.5) Modal

  • 마커 클릭하면 정보 띄우기

기능이라고 할 것도 없어서 0.5를 주었다.. RN은 MODAL이 편하다..

3) Map filter

  • 사용자가 선택한 여러 조건에 따라 다르게 리스트 렌더하기

여태까지 했던 것의 마지막 버전! 필수적으로 리덕스가 필요하다. 일단 필터 버튼을 하드 코딩으로 만들어 준다. 여기서 name은 리덕스에서 키값으로 잡아야하니까 리덕스와 맞춰야 한다.

그리고 아까와 마찬가지로 dispatch로 state에 선택된 type을 가져온다.

{sort: button.name}을 통해 리듀서 state에 내가 원하는 키에 데이터를 할당할 수 있다!!

그리고 리스트를 렌더하는 컴포넌트에서 작업을 시작한다.

부끄럽지만 filter.js에서 발생한 이벤트를 전혀 다른 컴포넌트인 list.js에 어떻게 연결할 함수가 없어서 그냥 컴포넌트 안에 변수를 선언했다. 뭔가 되게 엉망인 거 같지만... 처음이니까 봐준다... 다음부터 열심히하자!

21.01.20 useEffect 안에 선언하고 lists 값이 달라질 때마다 렌더하게 하면 어떨까

아무튼 아무것도 선택하지 않으면 리덕스에 저장된 initial state의 filter의 조건이 적용되고 무언가 선택하면 저 변수를 통해서 새로운 list가 렌더된다. 삼항 + 함수 조합은 정말 꿀인 거 같다. lists는 row 데이터를 state시킨 것!

4) Book mark

북마크는 오직 리덕스를 사용한다! 어려웠던 점은 이미 하트를 두 번 클릭했을 때 삭제하는 로직이었는데 생각보다 아주 간단히 짜버렸다! 먼저 클릭하면 dispatch로 list를 통으로 리듀서로 가져간다.

요렇게 짰다. 추가할 때는 row 데이터를 기준으로 dispatch에 집어 넣고 이미 reducer안에 state에 해당 데이터가 있으면 filter로 삭제한다.

배웠던 점

  • 프로젝트를 진행하면서 새로운 것을 많이 배웠는데 public 관리하는 것을 제대로 익혔다!

1) image

이렇게 assets 폴더에 넣고 constant 폴더에 images.js에 정의해준다.

그리고 index에서 export

깔끔하다.

2) 삼항 + 스타일

배열 안에 삼항을 해주면 조건에 따라 추가적인 스타일이 적용된다! 뭔가 새로운 걸 발견한 거 같아서 신나서 next.js에서도 inline style로 해보려고 했지만 적용되지 않았다. 아마 RN에서만 가능한 것일까?

3) dispatch 에러

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app

dispatch 쓸 때 종종 이런 에러가 나왔는데 useCallback에 dispatch를 넣어야 한다는 스택오버플로우 글을 봤다. 해결하진 못했지만 callBack 공부와 리덕스 공부를 더 해야할 듯!!

후기

  • 첫 RN

React-Native로 첫 프로젝트를 끝냈다. 투두 리스트를 하나 만들고 바로 시작한 프로젝트라 거의 배우면서 동시에 만들었다고 할 수 있다. RN은 UI가 일단 작기 때문에 레이아웃에 손이 많이 가지 않아 기능적으로 신경을 더 써야 해서 재밌었다. 그리고 앱이라는 웹과는 또 다른 새로운 매체에 무언가를 만든다는 생각에 인턴십을 하는 와중에도 시간을 내서 재밌게 만들 수 있었던 것 같다. 프로젝트를 하면서 에러를 정말 많이 만날 것이라는 멘토님의 얘기를 듣고 떨리는 마음으로 시작했다. 사실이었다. 에러와 정말 많이 부딪혔고 중간에 컴포넌트가 얽히면서 에러 지뢰밭에 걸린 적이 있었는데 밤새서 다 엎었다. 만든 것을 엎고 다시 하는 것에 대한 두려움이 있었는데 이번 프로젝트를 통해 하도 많이 엎다 보니까 내성이 생긴 것 같다.

  • 부족한 점

서버랑 통신 없이 혼자서 하는 건 오랜만이다. 1,2차 프로젝트 모두 서버랑 통신을 해서 사실 기능 로직을 구체적으로 짤 필요는 없었는데 더미 데이터로 내가 직접 기능을 짜면서 바닐라 자바스크립트의 기초의 중요성을 새삼 다시 느꼈다. 특히 다중 필터를 직접 짠 것은 처음인데 curry 함수를 이용해서 필터를 만들어 보려고 했지만 실패했다. 언젠간 성공할 것이다. 늘 그랬듯이..

그리고 리덕스 부분에서 애를 많이 먹었는데 아직도payload를 주고받을 때 return 값이 어떻게 나와야 하는지 정확하게 그려지지 않는다. 공부할 것이 많다.

  • 첫 사이드 프로젝트

렌카 인턴십을 병행하면서 했던 첫 번째 사이트 프로젝트다. 렌카 프로젝트만 하기도 벅찼지만 최대한 시간을 쪼개 만들었다. 내일까지 끝내야 할 렌카 프로젝트의 내 파트가 있다면 오늘 안으로 끝내고 남는 시간에 RN 프로젝트를 하는 식으로 자칫하면 두 프로젝트 모두 이도저도 아니 될 뻔했지만 말 그대로 모든 걸 쏟으며 만들었다. 뿌듯하다.

첫 RN 프로젝트고 리덕스나 라이브러리를 사용하면서 배웠던 것들, 기술부채나 에러들을 기록하면서 진행하고 싶었는데 시간에 쫓겨 '일단 만들자'라는 생각으로 후다닥 코드를 쳐서 아쉬움이 남는다. 앞으로 실무에 가도 이런 경우가 많을 텐데(무언가 남기고 혹은 기록하면서 하고 싶은 프로젝트인데 시간에 쫓겨 후다닥 끝내야 할 때) 시간적 압박 속에서도 요점만 기록할 수 있는 연습을 해야겠다.

참고 : https://www.youtube.com/watch?v=PEI38Pa8ZYM

profile
프론트엔드 개발

6개의 댓글

comment-user-thumbnail
2021년 1월 11일

갓동하 못하는게 뭐람

1개의 답글
comment-user-thumbnail
2021년 1월 11일

당신 언제 정리까지.. 배울점이 많은분🙏

1개의 답글
comment-user-thumbnail
2021년 4월 23일

안녕하세요 저도 지금 프로젝트를 진행 중인데 글 리스트를 어떻게 해야될지 모르겠어요
혹시 괜찮으시면 참고할 수 있도록 git이나 저장소 주소 알려주실 수 있으신가요?

답글 달기
comment-user-thumbnail
2021년 11월 10일

안녕하세요!
너무 설명이 너무 좋아서 공부하는데 도움이 많이 됩니다.

저도 맵을 이용한 앱을 만드는데, 구조를 잘 몰라 어떻게 구조를 짰는지 혹시 알려주실 수 있으신가요?

혹은 코드를 공유해주실 순 있나요?ㅜㅜ

답글 달기