Week3
- 대화기록이 없을 때는 상대방의 프로필이 화면에 뜨게함
- 클릭 여부에 따라 입력칸의 너비가 변하고 버튼 구성이 변함
- 입력창 자동 포커싱
- 메세지 전송과 사용자 토글 기능에 framer 라이브러리를 사용해서 애니메이션 효과를 구현함
- 모바일 뷰에서는 아이폰 헤더와 하단바를 숨김
- 메세지 전송시 스크롤바 하단으로 자동 이동
- 1분을 기준으로 메세지들을 그룹화해서 꼬리물기 기능 구현
- 메세지 전송 시각과 상대방의 프로필 사진은 각 그룹의 첫번째 메세지에만 뜨도록 함
- 상대방의 메세지에만 감정표현을 할 수 있는 기능
- 메세지 더블클릭시 이모티콘 리스트가 뜨고, 선택한 이모티콘으로 메세지 하단에 아이콘이 뜸. 이모티콘 선택 혹은 외부 클릭시 모달창이 닫힘
- 메세지를 더블클릭할 때 텍스트 선택이 안되게 방지함
Week4
- 사용자 1명의 시점에서 여러명과 개인 대화를 한 형태로 대화 로직을 변경함
- 대화 목록 화면, 친구 목록 화면, 마이페이지 화면, 통화 화면을 구현하고 라우팅함
- 대화 목록과 친구 목록에서의 검색 기능을 구현함
- 친구 목록에서 이름을 누르면 그 친구화 나눈 대화창으로 이동함
- 대화 내역이 있으면 내역을 불러오고 없으면 친구의 프로필을 띄움
- 친구 목록에서 이름 옆의 전화 아이콘을 누르면 전화 화면으로 라우팅되고 그 친구의 전화번호가 inputValue로 설정됨. 전화번호는 표준형(010-0000-0000)을 따름.
- 대화 목록에서는 친구의 이름, 대화내용으로 검색이 가능함
- 대화 목록은 대화 내역이 있는 친구들만 랜더링됨.
- 기존의 꼬리물기 방식을 마지막 메세지와 시간차가 1분 이상일시 새 그룹으로 묶이게 설정했는데, 분 단위로 다르면 그룹화 하는 방식으로 수정함
- 대화목록 최신순으로 정렬
- 새로운 대화 버튼 클릭시 대화내역 없는 친구 모달 뜨고 모달에서 사용자 선택시 채팅방으로 라우팅
타입스크립트를 처음 사용해봤는데, 자바스크립트와 문법이 비슷하지만 에러 사전 방지나 코드 자동완성 기능에 굉장한 편리함을 느꼈습니다! 왜 사람들이 타입스크립트 쓰라고 하는지 알 것 같았습니다,,
기본 문법만 익히고 개발을 시작해서 일단 부딪혀보자! 라는 마음가짐으로 미션을 진행해보았습니다. 그래서 타입스크립트, rcoil을 100% 활용해서 개발하지 못한 것 같고 아직 모르는 것들 투성이라서 공부를 열심히 해야겠다고 생각했습니다. 그래도 뭔가… 새로운 언어를 사용해 개발한다는 것에 의의를 두는 나 자신에게 거는 도전(??)이라고 생각했던 것 같습니다.
세오스에 들어와서 처음으로 하는 협업이고 디자이너님에게 빨리 배포링크를 드리고 피드백을 받고 싶은 마음이 커서 욕심을 가지고 작업했습니다!!! 디자이너님이 답장도 빨리 해주시고 요청사항도 뚝딱뚝딱 만들어 주셔서 너무 재밌었어요!!!
Week4
저번 미션 때 대화창만 만들었고 대화 상대가 둘 뿐이라서 user id를 하드코딩해서 대화창을 구현했었는데.. 이걸 user 0 (로그인한 사용자)가 다대일로 바꿔서 구현하려고 하니까 잘 안됐습니다. 그 대화 안에서 프로필을 누르면 송수신자가 토글되는데, user 0을 고정 발신자라고 생각하고 해서 바로잡는데까지 오래걸렸습니다..ㅠㅠ 아직 타입스크립트를 사용하는게 어색하고 recoil도 잘 활용하지 못하는거 같아서 공부를 많이 해야겠다고 생각했습니다.
이 과정에서 처음 코드를 짤 때 애초에 라우팅이나 연동을 고려해서 예쁘게 짜놔야 됨을 깨달았습니다. 그리고 이미지 파일명도 귀찮아서 피그마에서 다운받은대로 했었는데 이렇게 하니까 나중에 수정할 일이 있을 때 너무 불편했습니다!
귀차니즘을 극복해야 멋지고 편하게 개발을 할 수 있는 것 같습니다... 이번 과제는 구현하는 화면이 여러개라서 더 재밌었습니다!
Week3
- JavaScript를 사용할때에 비해 TypeScript를 사용할 때의 장점은 무엇인가요?
많은 장점들이 있겠지만 저에게 가장 크게 다가온 장점은 ‘에러의 사전 방지’와 ‘코드 자동완성과 가이드기능’ 이었습니다!
자바스크립트로 개발을 할 때에는 에러가 있어도 디버깅이 잘 되어서 직접 콘솔에 찍어보면서 값이 잘 전달되었는지 검토하면서 에러를 찾았었는데, 이 과정이 없어도 터미널에서 어디서 에러가 발생했는지 바로 알려줘서 시간을 많이 절약했던 것 같습니다.
그리고 파일명을 바꾸면 import한 다른 파일에서도 자동으로 바꿔줘서 너무너무 편하게 작업할 수 있었습니다.
-
디자이너로부터 전달받은 피그마 링크 혹은, 피그마 캡처본
-
컴포넌트를 분리한 기준은 무엇인가요?
저는 컴포넌트를 화면 구성 요소들로 분리한 것 같습니다. 크게는 헤더, 채팅창, 입력창으로 나눴고 채팅창 내에서는 감정표현을 할 수 있는 이모티콘 컴포넌트와 대화내용이 없을 때 채팅창에 뜨는 상대방의 프로필(기본 dummy data 때문에 현재는 볼 수 없는 화면이지만..)을 컴포넌트로 분리하여 사용하였습니다.
하나의 컴포넌트 내에(특히 ChatMessages.tsx) 너무 많은 기능이 들어있는 것 같아서 아쉬움이 남습니다. 기능별로도 컴포넌트화하는 습관을 들이고 싶어서 의식하려고 노력했는데, 이번에는 잘 안됐던 것 같습니다 ㅠㅠ
또 디자이너님이 요청하신 아이폰 header, footer을 컴포넌트로 분리해서 모바일 뷰에서는 쉽게 숨길 수 있도록 하였습니다!
- 디자인 시스템을 적용하면서 느낀 점은 무엇인가요?
따로 디자인을 구상하고 수정하며 개발했던 1,2주차와는 달리 주어진 디자인에 최선을 다할 수 있어서 이번 주차에는 공상의 시간이 적었던 것 같습니다~! 그리고 더 예쁜 디자인을 구현할 수 있어서 감사할 따름이었고 padding이나 margin값이 일정해서 css를 만지는 것도 이전보다 수월했습니다~!! (이번 주 미션은 정말 너무 재밌어서 주변 친구들한테 세오스를 홍보하고 다녔습니다 흐흐)
- 디자이너와 소통하며 느낀점은 무엇인가요?
이렇게 실력있는 디자이너님이랑 단둘이서 협업할 수 있다는 흔치 않는 기회를 얻어서 행복하다(?) 라는 생각이 제일 먼저 들었습니다. ㅎㅎ
소통에 있어서 큰 어려움은 없었지만, 정확한 명칭?이 없는 요소들을 뭐라고 지칭할지 몰라서 수정을 부탁드릴 때 고민들 많이 했던 것 같습니다..ㅠㅠ 그래서 피그마 댓글로 소통하는게 편했지만 알림이 메일로 오다보니 즉각적으로 답장을 못해서 소통 텀이 좀 있었습니다.
또, 제가 개발을 하는 시각과 디자이너님이 디자인을 수정하시는 시각이 다르기 때문에 중간에 붕 뜨는 시간을 줄이는 것이, 개발 속도 향상을 위한 중대한 고려사항이라는 생각이 들었습니다!
Week 4
라우팅은 여러 분야에서 쓰이는 용어지만 다 비슷한 의미를 가지고 있는 것 같다. React에서 다루는 routing이란, 사용자가 다양한 url을 통해서 App의 다른 페이지나 component 로 이동할 수 있게 해주는 과정이다.
리액트에서는 라우팅 기능이 없어서 React Router 라이브러리를 사용한다.
React Router을 사용해서 경로를 설정하는 방식에 대해 알아봤다.
- path란?
- Dynamic Segment란?
- Optional Segment란?
- Splats란?
를 사용하기만 해도 페이지 간에 링크를 만들 수 있지만, 사용자가 링크를 클릭할 때마다 새로운 페이지로 '전체' 로드가 발생한다. 이러면 웹 페이지의 로딩 속도를 늦추고, 리소스 낭비가 심해지고, 사용자 경험 측면에서도 완전 안좋다.
하지만 SPA 방식을 사용하면 이 문제를 해결할 수 있다.
SPA: Single Page Application 단일 페이지 애플리케이션 (Single-page application, SPA)은 단일 웹 문서만 로드한 다음 다른 콘텐츠가 표시될 때 XMLHttpRequest 및 Fetch와 같은 JavaScript API를 통해 해당 단일 문서의 본문 콘텐츠를 업데이트하는 웹 앱 구현체.
초기 로드 시 애플리케이션에 필요한 모든 HTML, JavaScript, CSS가 한 번에 로드되며, 이후의 사용자 상호작용은 이 페이지 내에서 AJAX와 HTML5 API를 통해 동적으로 처리됨.
장점: 사용자는 서버에서 완전히 새로운 페이지를 로드하지 않고도 웹사이트를 사용할 수 있으므로, 성능이 향상되고 보다 동적인 경험을 얻을 수 있다.
단점: SEO와 같은 일부 절충이 되는 단점이 있음
즉 routing을 통해서 spa의 핵심 기능을 구현할 수 있다. 페이지 전체를 리로딩하는게 아니라 필요한 부분이나 데이터만 동적으로 갱신해주기 때문
애플리케이션의 다양한 부분(사용자 인터페이스 상태, 사용자 입력, 서버 응답 등)에서 필요한 데이터의 흐름과 변화를 중앙에서 조정하고 관리하는 과정.
React에서의 상태 관리 방법
- React 내장 Hook (useState, useEffect 등등)
- Hook 규칙
-
최상위(at the Top Level)에서만 Hook을 호출해야함 반복문, 조건문 혹은 중첩된 함수 내에서 Hook 호출 X
-
오직 React 함수 내에서만 Hook을 호출
-
모든 렌더링에서 Hook의 호출 순서는 같아서 React는 Hook이 호출되는 순서에 의존한다.
-
- Recoil
Recoil은 atom을 통해 selectors를 거쳐 React 컴포넌트로 흐르는 데이터 흐름 그래프를 생성할 수 있다.
- atom: 컴포넌트가 구독할 수 있는 상태의 단위 이렇게 생성됨 const fontSizeState = atom({ key: 'fontSizeState', default: 14, });
Atom에는 디버깅, 지속성 및 모든 Atom의 맵을 볼 수 있는 특정 고급 API에 사용되는 고유 key가 필요함. React 구성 요소 상태와 마찬가지로 default도 있음
구성 요소에서 원자를 읽고 쓰려면 useRecoilState 이라는 훅을 사용함. React의 useState와 비슷하지만 atom은 여러 컴포넌트에서 공유될 수 있는 전역 상태임
function FontButton() { const [fontSize, setFontSize] = useRecoilState(fontSizeState); return ( <button onClick={() => setFontSize((size) => size + 1)} style={{fontSize}}> Click to Enlarge ); }
function Text() { const [fontSize, setFontSize] = useRecoilState(fontSizeState); return
This text will increase in size too.
; }버튼을 클릭하면 버튼의 글꼴 크기가 1씩 늘어나는데 다른 구성 요소도 동일한 글꼴 크기를 사용할 수 있음.
- Selectors: 파생된 상태 또는 상태 기반의 계산을 정의하는데 사용 atom의 값을 입력으로 받아 계산을 수행하고, 그 결과를 반환함
최소 상태 세트가 atom에 저장되고 다른 모든 것은 해당 최소 상태의 함수로 효율적으로 계산되므로 중복 상태를 피할 수 있음
const fontSizeLabelState = selector({ key: 'fontSizeLabelState', get: ({get}) => { //get: 계산할 함수 const fontSize = get(fontSizeState); const unit = 'px';
return `${fontSize}${unit}`;
}, });
useRecoilValue() : 읽기 전용 -> 상태를 변경할 필요가 없고 오직 읽기만 필요한 경우 사용 useRecoilState() : 읽고 쓸 수 있음 -> 상태를 읽고 변경해야 하는 경우 사용
- TypeScript를 사용해봅시다.
- useState로 컴포넌트의 상태를 관리합니다.
- useEffect와 useRef의 사용법을 이해합니다.
- styled-components를 통한 CSS-in-JS 및 CSS Preprocessor의 사용법에 익숙해집니다.
2024년 3월 29일 금요일
- 피그마를 보고 결과화면과 같이 구현합니다.
- 디자인 시스템을 구축합니다.
- 채팅방 상단의 프로필을 클릭하면 사용자를 변경할 수 있습니다.
- 메세지를 보내면 채팅방 하단으로 스크롤을 이동시킵니다.
- 메세지에 유저 정보(프로필 사진, 이름)를 표시합니다.
- user와 message 데이터를 json 파일에 저장합니다.
- UI는 반응형을 제외하고 피그마파일을 따라서 진행합니다.
react-messenger-19th ├─ package-lock.json ├─ package.json ├─ public │ ├─ assets │ │ │ └─ index.html ├─ README.md ├─ src │ ├─ App.tsx │ ├─ components │ │ ├─ chat │ │ │ ├─ ChatInput.tsx │ │ │ ├─ ChatMessages.tsx │ │ │ ├─ EmojiModal.tsx │ │ │ └─ UserProfile.tsx │ │ ├─ fakedata │ │ │ │ ├─ messages.json │ │ │ └─ users.json │ │ ├─ list │ │ │ ├─ Call-icon.png │ │ │ ├─ ChatList.tsx │ │ │ ├─ ChatListHeader.tsx │ │ │ ├─ FriendList.tsx │ │ │ ├─ FriendListHeader.tsx │ │ │ ├─ MyPage.tsx │ │ │ ├─ MyPageHeader.tsx │ │ │ ├─ NavigateFooter.tsx │ │ │ ├─ NewChatModal.tsx │ │ │ └─ PhoneCall.tsx │ │ ├─ main │ │ │ ├─ ChatApp.tsx │ │ │ ├─ Header.tsx │ │ │ ├─ IphoneFooter.tsx │ │ │ └─ IphoneHeader.tsx │ │ ├─ state │ │ │ ├─ currentUserState.ts │ │ │ ├─ messageState.ts │ │ │ ├─ selectedUserState.ts │ │ │ └─ userState.ts │ └─ style │ │ └─ GlobalStyle.tsx │ ├─ index.tsx │ └─ react-app-env.d.ts └─ tsconfig.json