1) 소개
2) 기간
3) 인원
4) 역할
1) react-native expo
2) 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 기술 부채다!
소셜 로그인을 후 사용자 정보를 AsyncStorage
에 저장
async await
을 통해 비동기적으로 실행
Theme Color에 맞춰 이미지를 골랐다.
Tab
의 경우는 이렇게 키로 id와 name, place를 가지고 있는 배열을 flatList
로 돌렸다. dispatch로 onPress할 때 id값을 가져오고 부모 컴포넌트인 Home.js
에서 find를 이용해서 해당 id를 가진 객체를 state에 넣었다.
그리고 실제 해당 tab에 뿌려지는 컴포넌트에 그 리스트를 props로 넘긴다.
백엔드와 통신을 한다면 클릭할 때마다 query string
을 보내서 탭에 맞는 데이터를 받아오면 되지만 더미 데이터를 사용해야 해서 이렇게 로직을 짰다.
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에 얼마나 많은 키가 있는지 상관없이 확장할 수 있다!!!
나는 닥터 스트레인지가 손을 휙휙 저어서 공간을 뚫고 거기에 손을 뻗어서 원하는 물건을 쏙 가져오는 느낌으로 이해했다.
useSelector
로 filters를 가져오고 실제 렌더될 map 컴포넌트에서 로직을 짠다!
일단 row 데이터는 campingData
를 state에 넣고 거기에 filteredList
라는 변수를 이용해서 가공한다. 그리고 filter된 list를 렌더하면 끝!!
여러 가지 상태에 따라 다른 배열을 만들어야 할 때 초기값이 될 배열(campings
)를 삼항 연산자의 true에 정의하고 false에 fillter나 find 메서드를 정의하면 조건에 따라 다른 배열을 얻을 수 있다. if나 switch 없이도 어마어마하게 확장이 가능하다!
즉, 삼항이라고 해서 꼭 true / false 두 가지 경우만 들어가는 것이 아니라 false에 얼마든지 커스텀마이징이 가능하다는 것. true가 아니면 false를 return
라는 기본 정의를 조금만 뒤집어 생각하면 얼마든지 다르게 사용할 수 있다.
기능이라고 할 것도 없어서 0.5를 주었다.. RN은 MODAL이 편하다..
여태까지 했던 것의 마지막 버전! 필수적으로 리덕스가 필요하다. 일단 필터 버튼을 하드 코딩으로 만들어 준다. 여기서 name은 리덕스에서 키값으로 잡아야하니까 리덕스와 맞춰야 한다.
그리고 아까와 마찬가지로 dispatch로 state에 선택된 type을 가져온다.
{sort: button.name}을 통해 리듀서 state에 내가 원하는 키에 데이터를 할당할 수 있다!!
그리고 리스트를 렌더하는 컴포넌트에서 작업을 시작한다.
부끄럽지만 filter.js
에서 발생한 이벤트를 전혀 다른 컴포넌트인 list.js
에 어떻게 연결할 함수가 없어서 그냥 컴포넌트 안에 변수를 선언했다. 뭔가 되게 엉망인 거 같지만... 처음이니까 봐준다... 다음부터 열심히하자!
21.01.20 useEffect 안에 선언하고 lists 값이 달라질 때마다 렌더하게 하면 어떨까
아무튼 아무것도 선택하지 않으면 리덕스에 저장된 initial state
의 filter의 조건이 적용되고 무언가 선택하면 저 변수를 통해서 새로운 list가 렌더된다. 삼항 + 함수 조합은 정말 꿀인 거 같다. lists
는 row 데이터를 state시킨 것!
북마크는 오직 리덕스를 사용한다! 어려웠던 점은 이미 하트를 두 번 클릭했을 때 삭제하는 로직이었는데 생각보다 아주 간단히 짜버렸다! 먼저 클릭하면 dispatch로 list를 통으로 리듀서로 가져간다.
요렇게 짰다. 추가할 때는 row 데이터를 기준으로 dispatch에 집어 넣고 이미 reducer안에 state에 해당 데이터가 있으면 filter로 삭제한다.
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 공부와 리덕스 공부를 더 해야할 듯!!
React-Native로 첫 프로젝트를 끝냈다. 투두 리스트를 하나 만들고 바로 시작한 프로젝트라 거의 배우면서 동시에 만들었다고 할 수 있다. RN은 UI가 일단 작기 때문에 레이아웃에 손이 많이 가지 않아 기능적으로 신경을 더 써야 해서 재밌었다. 그리고 앱이라는 웹과는 또 다른 새로운 매체에 무언가를 만든다는 생각에 인턴십을 하는 와중에도 시간을 내서 재밌게 만들 수 있었던 것 같다. 프로젝트를 하면서 에러를 정말 많이 만날 것이라는 멘토님의 얘기를 듣고 떨리는 마음으로 시작했다. 사실이었다. 에러와 정말 많이 부딪혔고 중간에 컴포넌트가 얽히면서 에러 지뢰밭에 걸린 적이 있었는데 밤새서 다 엎었다. 만든 것을 엎고 다시 하는 것에 대한 두려움이 있었는데 이번 프로젝트를 통해 하도 많이 엎다 보니까 내성이 생긴 것 같다.
서버랑 통신 없이 혼자서 하는 건 오랜만이다. 1,2차 프로젝트 모두 서버랑 통신을 해서 사실 기능 로직을 구체적으로 짤 필요는 없었는데 더미 데이터로 내가 직접 기능을 짜면서 바닐라 자바스크립트의 기초의 중요성을 새삼 다시 느꼈다. 특히 다중 필터를 직접 짠 것은 처음인데 curry 함수를 이용해서 필터를 만들어 보려고 했지만 실패했다. 언젠간 성공할 것이다. 늘 그랬듯이..
그리고 리덕스 부분에서 애를 많이 먹었는데 아직도payload
를 주고받을 때 return 값이 어떻게 나와야 하는지 정확하게 그려지지 않는다. 공부할 것이 많다.
렌카 인턴십을 병행하면서 했던 첫 번째 사이트 프로젝트다. 렌카 프로젝트만 하기도 벅찼지만 최대한 시간을 쪼개 만들었다. 내일까지 끝내야 할 렌카 프로젝트의 내 파트가 있다면 오늘 안으로 끝내고 남는 시간에 RN 프로젝트를 하는 식으로 자칫하면 두 프로젝트 모두 이도저도 아니 될 뻔했지만 말 그대로 모든 걸 쏟으며 만들었다. 뿌듯하다.
첫 RN 프로젝트고 리덕스나 라이브러리를 사용하면서 배웠던 것들, 기술부채나 에러들을 기록하면서 진행하고 싶었는데 시간에 쫓겨 '일단 만들자'라는 생각으로 후다닥 코드를 쳐서 아쉬움이 남는다. 앞으로 실무에 가도 이런 경우가 많을 텐데(무언가 남기고 혹은 기록하면서 하고 싶은 프로젝트인데 시간에 쫓겨 후다닥 끝내야 할 때) 시간적 압박 속에서도 요점만 기록할 수 있는 연습을 해야겠다.
갓동하 못하는게 뭐람