본문 바로가기
코드리뷰

[카카오톡 클론코딩]2022.08.04

by 치우치지않는 2022. 8. 4.
>components >chattignRoom>Content.tsx
 
// 마지막 채팅인 경우
if (idx === chattingList.length - 1) {
// 내가 보낸 채팅인 경우
if (senderId === myId) {
return (
<MyChat
msg={chat.message}
notRead={chat.not_read}
localeTime={removeSecond}
content={date}
key={chat.id}
/>
);
}

// 이전에 보낸 채팅과 사람, 날짜가 동일한 경우
if (isPrevSender && isSameDate) {
return (
<FriendChat
msg={chat.message}
notRead={chat.not_read}
localeTime={removeSecond}
key={chat.id}
/>
);
}
return (
<FriendChatWithThumbnail
msg={chat.message}
user={sender}
notRead={chat.not_read}
localeTime={removeSecond}
content={date}
onImgClick={() => showProfile(sender)}
key={chat.id}
/>
);
}
 
//보충 필요

>components >chattignRoom>Footer.tsx

카톡 채팅방에서 전송 버튼이 있는 최하단 부분을 구현함. Footer 컴포넌트 하나와 Props 인터페이스 하나의 심플한 구성. Footer 을 export 한다. 

return (
<Wrapper>
<form onSubmit={onSubmit}>
<textarea
value={message}
autoFocus={true}
onChange={onMessageChange}
onKeyPress={onEnterPress}
/>
<button className={btnClassName} type="submit">
전송
</button>
</form>
</Wrapper>
);

그리고 위와 같은 리턴값을 가진다. 여기서는 import 해 온 외부 컴포넌트는 없는 것 같고, 해당 컴포넌트 안에 필요한 함수들은 다 정의 되어 있다. requestSubmit 험수는 onSubmit 과 onEnterPress 함수 내부에서 호출된다. 이때 한 가지 특징적인 것, 그리고 이 카톡 클론이 굉장히 구체적으로 구현되엇다고 느낀 부분은 

const onEnterPress = (event: KeyboardEvent<HTMLTextAreaElement>) => {
// shift + enter 이면 줄바꿈이 되고, enter키만 누르면 채팅 전송이 됩니다.
if (!event.shiftKey && event.key === 'Enter') {
event.preventDefault();
requestSubmit();
}
};

위와 같이 조건문을 사용해서 엔터 키만 눌렀을 경우만 채팅 전송이 되게끔 했다는 점이었다. 

 

>components >chattignRoom>Header.tsx

채팅방 상단에 채팅방 이름과 뒤로가기 버튼을 구현했다. props 인터페이스 하나와 Header 컴포넌트 하나로 구성되어 있으며 Header 를 디폴트로 export 중이다. 이 부분은 너무 간단해서, 자꾸 눈에 밟혔던 부분을 추가적으로 공부할 여유가 생겨

React.FC<Props

위 코드에 대해 공부를 해 보았다. 우선 FC 는 function component 의 준말. 

https://woobiblog.com/Javascript/Typescript_FunctionComponent_FC_%EC%82%AC%EC%9A%A9_%EC%A4%84%EC%9D%B4%EA%B8%B0

 

[Typescript] FunctionComponent (FC) 사용 줄이기

React + Typescript 조합으로 개발을 하면서 자주 사용하는 타입 중 하나가 FC 이다. FC 는 FunctionComponent 타입의 줄임말로 리액트에서 함수형 컴포넌트의 타입을 선언할 때 사용할 수 있게 React 에서 제

woobiblog.com

여러 단점이 있어서 대부분 props 에 직접 타입을 선언해 주는 방식으로 진행한다. 그런데 여기서는 왜 .FC 를 많이 썼을지 의문. 

 

>components >chattingRoom >InfoBlock.tsx 

InfoBlock 이라는 파일명 답게 여러가지 정보를 알려주는 블록들을 저장해 둔 파일이다. 총 네 개의 컴포넌트를 export 하고 있고, 

1. 날짜를 표시하는 등 채팅방의 경계를 나타내는 컴포넌트

2. 친구가 아닐 경우, 상단에 경고 창을 띄우는 컴포넌트

3. 채팅방의 스크롤이 일정 이상 올라가면 Down 버튼을 나타내는 컴포넌트

4. 채팅방의 스크롤이 일정 이상 올라가 있는 상태에서, 메시지가 도착하면 이를 알려주는 컴포넌트

그 기능들은 위와 같다. 이제 코드를 하나하나 살펴 보자. 

// 날짜를 표시하는 등 채팅방의 경계를 나타냅니다.
export const SeparationBlock: React.FC<SeparationBlockProps> = ({
content
}) => {
return (
<BorderBlock>
<span>{content}</span>
</BorderBlock>
);
};

1. 먼저, 날짜를 표시하는 등 채팅방의 경계를 나타내는 코드이다.

export const SeparationBlock: React.FC<SeparationBlockProps> = ({

보다시피 SeparationBlockProps 형식의 props 를 받아오는데, 이는 인터페이스로 

interface SeparationBlockProps {
content: string;
}

이렇게 정의되어 있다. 이때 content 는 

export const MyChat: React.FC<ChatProps> = props => {
const { content } = props;
return (
<React.Fragment>
{content ? <SeparationBlock content={content} /> : null}
<RightBlock>
<div>
<Chat {...props} />
</div>
</RightBlock>
</React.Fragment>
);
};

보다시피 ChatProps 형식이고, ChatProps 는 

interface ChatProps {
msg: string;
localeTime: string;
notRead: number;
content?: string;
}

요렇게 생겻다. 즉 SeperationBlock 은 props 의 타입이 SeperationBlockProps 로 content:string 인데 props 로 받아온 것은 구조체 content 이다.. (여기서 하나 의문인 게 그럼 string 타입의 content 만 받아왔다는 것인지 아니면 ChatProps 전체를 다 받아왔다는 것인지 그도 아니면 구조체로 받아온 것을 string으로 타입변환 한 것인지 하는 것이다.. 이 문제는 일단 차치하고,, -> 완. es6 구조분해할당)  

 

2. 친구가 아닐 경우, 상단에 경고 창을 띄우는 컴포넌트

// 친구가 아닐 경우, 상단에 경고 창이 뜨게 됩니다.
export const NotFriendWarning: React.FC<NotFriendWariningProps> = props => {
const { onAddFriendClick } = props;
return (
<WarningAreaBlock>
<NotFriendBlock>
<ActionBlock>
<span onClick={onAddFriendClick}>
<i className="fas fa-user-plus" /> 추가
</span>
</ActionBlock>
<WarningBlock>
<i className="fas fa-exclamation-triangle" />
<p>
{' '}
친구로 등록되지 않은 사용자입니다. 금전 요구 등으로 인한 피해를 입지
않도록 주의해주세요.
</p>
</WarningBlock>
</NotFriendBlock>
</WarningAreaBlock>
);
};

우선 props 로 받아오는 것이 무엇인지부터 봐 보면, 

<NotFriendWariningProps>

를 받아오고 있고 (이 이름이 반드시  props 이름과 일치하지는 않아도 되는 것 같다.)

<NotFriendWarning
onAddFriendClick={() =>
onAddFriendClick(chatState.participant[0])
}
/>

아 위 코드 보면서 이해 안되었던 것을 이 코드 보면서 이해를 했다. 구조분해 할당이라는 것에 대해 잠시 알아보고 넘어가자. 

https://sang12.co.kr/228/const-%7B%7D-%3D-props-es6-%EB%AC%B8%EB%B2%95-%EA%B5%AC%EC%A1%B0%EB%B6%84%ED%95%B4%ED%95%A0%EB%8B%B9%28Destructuring-assignment%29%EC%9D%B4%EB%9E%80

 

const {} = props es6 문법 구조분해할당(Destructuring assignment)이란

React Native에서 화면을 전환할때 파라미터를 전달하는 방법을 공부하던 중 아래와 같은 const { itemId } = route.parms란 문법을 보게 되었다. /*

sang12.co.kr

기존 js 문법에서는 구조체 안에서 특정한 하나의 변수를 지정하고 싶을 때 object.a 이런 식으로 썼는데 ES6 문법에서는 const {a} = object 라고 쓴다. 즉 위에서 해결 안되었던 문제의 답은 구조체 안의 string 타입을 갖는 content를 가져왔다 이다. 

 

다시 돌아와서, NotFriendWarning 은 prop으로 onAddFriendClick 에 ondAddFreindClick 함수를 받아오고 있는데, 이 함수는 파라미터로 chatState.participant[0] 을 받아오고 있다. 

 

이때 chatState 는, 

const chatState = props.rootState.chat;

이렇게 생겼고, 

rootState: RootState;

이므로, RootState 를 찾아보면, 

export interface RootState {
auth: AuthState;
user: UserState;
profile: ProfileState;
chat: ChatState;
}

요렇게 생겼다는 것을 알 수 있다. 그럼 rootState.chat 은 RootState 의 chat 을 의미하므로 다시 ChatState 를 찾아가 보면, 

const initialState: ChatState = {
room_id: -1,
type: undefined,
identifier: '',
room_name: '',
participant: [],
chatting: [],
last_read_chat_id: -1,
isChattingRoomShown: false,
isFetchChattingLoading: false
};

ChatState 는 요렇게 생겼다는 것을 알 수 있다. 

onAddFriendClick(chatState.participant[0])

그럼 이 ChatState 의 첫번째 participant 를 onAddFriendClick 함수에 파라미터로 넘겨주었다는 얘기가 된다. 

onAddFriendClick 함수를 봐 보자. 

'코드리뷰' 카테고리의 다른 글

[카카오톡 클론코딩]2022.08.07  (0) 2022.08.08
[카카오톡 클론코딩]2022.08.06  (0) 2022.08.07
[카카오톡 클론코딩]2022.08.05  (0) 2022.08.06
[카카오톡 클론코딩]2022.08.03  (0) 2022.08.03
코드리뷰 - 카카오톡  (0) 2022.07.30

댓글