Skip to content

Conversation

@rmdnps10
Copy link

@rmdnps10 rmdnps10 commented Nov 3, 2023

배포링크

기능 설명

저번 과제에서 구현한 내용

  • 채팅방 구현 ( 로컬스토리지 연동 )
  • 자신이 보낸 메시지, 상대가 보낸 메시지가 구분되며 이 기준이 되는 주체를 변경할 수 있었음

이번 과제에서 추가적으로 구현한 내용

  • 프로필 페이지, 채팅 목록 페이지, 채팅방 페이지, 연락처 목록 페이지 퍼블리싱
  • 채팅 목록 페이지에서 총 2개의 채팅방 존재
  • 각각의 채팅방에서 메시지 읽음 처리 구현( 채팅방에서 주체를 '정인영' 에서 상대방으로 바꾼 뒤에 다시 주체를 '정인영' 으로 바꾸었을 때 보낸 메시지를 읽음 처리되게 함 )
  • 채팅 목록 페이지에서 각각의 채팅방의 마지막 메시지, 읽지 않은 메시지의 개수 표시
  • 채팅방을 제외한 다른 페이지에서 HomeNav (내비게이션) 의 검색 아이콘 누를 시 채팅방, 연락처를 검색할 수 있고, 검색 목록에서 채팅방 클릭 시 해당 채팅방으로 이동
  • 검색이 활성화되어 있는 상태에서 다른 페이지로 넘어갈 시 검색을 비활성화하고, 활성화할 경우 입력값에 포커스되게 구현

구현 과정

목표

이번 과제의 가장 큰 목표는 디자이너 분의 생각과, 작업물을 그대로 구현하는 것 이었습니다. 디자이너분의 Q&A 는 따로 없었으나, 기존의 피그마 작업물로는 기능 구현을 하기 어려워 특정 기능 구현에 대한 새 디자인에 대한 요청을 지속적으로 드리면서, 이에 대한 디자이너 분의 생각을 반영하여 개발을 진행하였습니다.

파일 구조

component 폴더 안의 파일 구조는 이렇습니다.
스크린샷 2023-11-03 오후 4 40 10

저번에 사용했던 아토믹 디자인 패턴 (atom, molecule, organism, template 으로 컴포넌트를 구분하여 생성 ) 을 계속해서 사용하였는데, molecules, organism에 해당하는 컴포넌트의 경우에는 각각 molecules,organism 폴더 안에 페이지별로 폴더(chat, chatroom, profile, contact) 를 또 따로 만들어서 구분해놓았습니다. 다른 페이지에서도 공통으로 쓰이는 컴포넌트의 경우 molecules 바로 아래에 위치하게 하였습니다.

상태 관리

컴포넌트를 세분화하였기 때문에, 과도한 Props Drilling을 방지하기 위해 전역 상태 관리를 사용해야 되겠다고 생각하였습니다. 많은 상태 관리 라이브러리 중 Recoil을 사용하였는데, 상태를 받아오기만 할 땐 useRecoilValue,상태를 갱신하기만 할 땐 useSetRecoilState를 사용하였습니다. 관리하고자 하는 전역 상태들의 경우 recoil폴더 안에 atom.ts에 한꺼번에 모아 export 하여 사용하였습니다.

Challenges

  • 폴더 구조가 복잡해지고, 컴포넌트가 세분화되니 개발적인 효율성과 가독성이 떨어진다고 느꼈습니다. 하지만 디자인 패턴을 바꾸기에는 이미 먼 길을 가버린 (...) 상태여서 일단은 진행하였는데, 다음에는 좀 더 agile한 방법을 통해 디자인 패턴을 적용하고 싶습니다. 많이 아쉬웠네요 ㅠ
  • "나는 지금 타입스크립트를 잘 쓰고 있는가?" 에 대한 고민이 많이 들었는데, 다른 분들의 과제 구현한 것을 보며 많이 참고하며 배우게 될 거 같습니다.

프로젝트 디렉토리 구조 완성 및 필요한 이미지와 폰트 추가
- assets: 다운로드 받은 폰트와, 필요한 이미지
- components: 아토믹 디자인 패턴 적용한 컴포넌트들 모음
- pages: 페이지들 (현재는 하나밖에없음)
- recoil: atoms 모음
- style: 스타일 초기화와 전역적으로 사용할 색깔 변수, 폰트 가져오기
- Flex, Icon, Space, Text 컴포넌트 작업 완료
- StatusBar AppContainer 밖에서 안으로 변경
- Segoe 폰트 추가
아토믹 디자인 패턴 적용하여 스타일링
- 재사용성을 고려하여 일반적으로 많이 사용되는 속성을 atoms으로써 선언함
- Flex ( display: flex 사용할경우), Icon (24x24 아이콘 사용시), Input(텍스트 입력창), Space (Margin 대용), Text (텍스트)
전역 변수로 선언한 isUser1이 true일 때 로컬스토리 'user1Message'에 메시지 저장, false 일 때는 'user2Message' 에 메시지 저장
유저 토글에 따른 메시지 렌더링 완료
maxWidth로 prop수정, Text align 속성 Left로 변경
코드 가독성 증진을 위한 함수 추가
디자이너와의 소통을 통해 줄바꿈 단위를 단어에서 글자로 변경
- 시간 표시보다 메시지 컨텐츠 길이가 적을 시, 메시지 정렬을 좌측으로 고정
atom들이 받는 수많은 props들을 인터페이스로 지정하고 Flex의 defaultProps 값을 빼고 코드를 간결하게 리팩토링하였음
그밖에 여러 코드를 타입스크립트 형식으로 리팩토링함
DummyList 컴포넌트를 선언하여 ChatArea에 추가했다.
assets/images/아이콘.svg들의 Module not found Error가 발생하여 이름으 모두 영어로 바꾸고 다시 import 하였다.
가독성을 위해 개별 채팅방 페이지의 이름을 Chat에서 ChatRoom으로 바꾸고 Chat을 채팅방 목록 페이지로 바꾸었다.
컴포넌트가 많아질 거 같아서 molecules과 organism에 페이지 별 폴더를 추가하여 컴포넌트를 넣었으며 공통으로 사용할 컴포넌트는 폴더 밖으로 뺐다.
더미리스트도 삭제하였다.
Link 컴포넌트를 통해 라우팅을 구현하였으며 useLocation()을 통해 얻은 현재 경로로 현재 페이지를 나타내는 메뉴를 파란색으로 표시함
useEffect에 검색상태여부를 의존성 배열로 추가하여 구현
Copy link
Member

@leejin-rho leejin-rho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제 정말 수고하셨습니다~! 여러가지 디테일들을 신경쓰신게 보여서 저도 다음에는 더 신경써서 코드를 작성해야겠다고 생각했어요. 수고하셨습니다~!

@@ -0,0 +1,6 @@
import dayjs from "dayjs";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 라이브러리는 사용을 안해봤는데 배워갑니다~

text={el.text}
time={dayjs(el.time).format("h:mm a")}
key={el.id}
isRead={el.isRead}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isRead 만들어서 메시지가 새로오면 +1 표시해주신게 디테일이 대단하신 것 같습니다. 새로운 메시지 수만큼 따로 표시해준 거랑, 메시지 풍선 내부에도 읽음 표시 해주신게 진짜 디테일 하신 것 같아요!!

setUserBMessage(userBMessage.map((obj) => ({ ...obj, isRead: true })));
} else if (params.roomID === "2") {
setUserCMessage(userCMessage.map((obj) => ({ ...obj, isRead: true })));
setUserDMessage(userDMessage.map((obj) => ({ ...obj, isRead: true })));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

읽음표시 설정하신 부분 코드 배워갑니다..!

// 채팅방의 주체 (정인영) 입장에서 각각의 채팅방에서 읽지 않은 메시지의 개수 count1, count2
let count1 = 0;
let count2 = 0;
// 마지막 채팅방에서 자신의 메시지가 마지막일 경우에는 읽지 않은 카운트에서 제외
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주석을 잘 써주셔서 읽기 편했어요

let count2 = 0;
// 마지막 채팅방에서 자신의 메시지가 마지막일 경우에는 읽지 않은 카운트에서 제외
if (!isUser1InFirstRoom) {
room1SortedMessages.forEach((obj) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 방의 메시지들에서 isRead가 false일 경우에만 세어서 표시해주신 것 배워갑니다~

<Flex direction="column" gap="15" width="335px" margin="0 auto">
<Space height="4px" />
{filterContactList.length === 0 ? (
<Text>결과가 없습니다.</Text>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 결과가 없을 경우에는 아무 표시를 안했는데, 이런 디테일 저도 참고해서 표현해보겠습니다!

""
) : (
<Flex direction="column" gap="15" width="335px" margin="0 auto">
<Text weight="600">채팅방</Text>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

친구, 채팅방 두가지 모두 한페이지에서 한번에 검색 가능하게 구현하신거 배워갑니다~

Copy link

@silverain02 silverain02 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

새로운 방식 많이 배워갑니다~ 읽음 표시 기능까지 구현하신 것 멋있어요!!
이번주도 고생하셨습니당~!

<Route path="/chat/:roomID" element={<ChatRoom />}></Route>
<Route path="/profile" element={<Profile/>}></Route>
{/* 다른 경로 접속시 chat으로 이동*/}
<Route path="/*" element={<Navigate to="/chat" />} />

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정해둔 경로 외 다른 url 접근까지 신경써서 예외 처리해주신 것 좋은 것 같아요~

Comment on lines +15 to +19
const [isBlue, setIsBlue] = useState({
contact: false,
chat: false,
profile: false,
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 이 부분 각각 삼항연산자로 CSS 처리해줬는데 이렇게 State로 분리하니까 가독성이 더 좋은 것 같네요 배워갑니다~

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자주쓰는 함수 이렇게 hook으로 분리하면 사용하기 편할 것 같네요! dayjs 라이브러리도 처음봤는데 다음에 저도 활용해보겠습니다 ㅎㅎ

function Chat() {
return (
<>
<ChatTemplate />

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

템플릿 폴더 따로 분리하는 방식 훨씬 깔끔하고 좋은 것 같아요 배워갑니다~

Comment on lines +20 to +27
<Flex
width="327px"
height="56px"
margin="0 auto"
gap="12"
cursor="pointer"
onClick={onClick}
>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 각 컴포넌트에서 따로 styled-component만들었는데 이렇게 atom파일로 css데이터 넘기는 스타일 시스템 적용하면 코드 중복을 줄일 수 있을 것 같네요 배워갑니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants