Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4주차] 이희원 미션 제출합니다. #18

Open
wants to merge 74 commits into
base: master
Choose a base branch
from

Conversation

hiwon-lee
Copy link

@hiwon-lee hiwon-lee commented Nov 2, 2024

배포 링크
피그마 링크

기능

  • 친구목록
  • 친구 선택시 친구 프로필 볼 수 있음
  • 채팅목록
  • 채팅방입장
  • 채팅방입장 후 프로필 클릭시 사용자 토글
  • 더블클릭시 이모지 선택창나옴

될것처럼 생겼는데 안되는 거

  • 우측상단 ...메뉴
  • 검색
  • +버튼 누른 후 동작
  • 메일, 전화보내기
  • 이모지 삭제는 안됨

느낀점

  • 세세한 디자인 맞추는게 번거로웠다. 그래서 다 못맞춘 부분이 있다. 시간나면 조금씩 더 해봐야겠다....
  • 디자이너랑 계속 얘기하긴했는데, 빠른 수정이 안되어서 그냥., 임의대로 진행한 부분이 많다.
  • 나중에 팀플할땐 꼭꼭 디자인시스템대로 하자고 디자이너랑 잘 상의해서 진행해야겠다.
  • 지난 번엔 테일윈드만을 사용했고, 그 결과 나는 스타일드 컴퍼넌트가 아주 조금 더 편했다.
  • 테일윈드에 스타일드 컴퍼넌트를 추가 적용하다보니 두개가 섞여서 보기가 좀 난잡하다
  • 하지만 두 개를 동시에 써보니 테일윈드와 스타일드 컴퍼넌트 각각의 장단점이 확실히 느껴졌다.
    • 테일윈드 : 장 - 개발자도구로 확인할 때, 클래스명이 분명해서 빠르게 고칠 수 있다. 관련 스타일 함수 작성하면 재사용성도 있다. 단 - 코드가 지저분해진다. 잘 쓰지 않는 스타일속성이나 사이즈는 여전히 찾아봐야함
    • 스타일드 컴퍼넌트 : 장- 코드가 깔끔해진다. 활용 및 재사용하기 좋다. 단 - 개발자도구에서 임의의 스타일 명이라 다소 불편할 수 있다.
  • 타입 및 인터페이스가 난무해서 좀 복잡했다.. 데이터 구조를 어떻게 짤 지 그냥 머릿속으로만 생각하고 구현한 것이 실수였던 것 같다. 덕분에 구현하면서 매우 골치아팠다.
  • 동적 라우팅할 때 useParam을 갖고 넘긴 정보들을 가져올 수 있는데, 항상 undefined가 타입에 끼어들어와서 그거 처리해주는게 매우 번거롭고 귀찮았다.
  • 복잡하고 긴 코드는 따로 빼서 모듈성을 높이자..

1. React Router의 동적 라우팅(Dynamic Routing)이란 무엇이며, 언제 사용하나요?

동적 라우팅: 사용자가 방문하는 페이지에 따라 다른 데이터를 기반으로 렌더링되는 라우트를 만드는 기능
이번 채팅 앱에서 사용자의 ID에 따라 다른 페이지로 이동하는 데, 여기서 동적 라우팅이 사용된다.
URL의 특정 부분을 변수처럼 처리하여 여러 페이지를 하나의 경로로 관리할 수 있다.
useParams 훅을 사용하여 URL에서 파라미터를 받아와서 컴포넌트 내에서 그 값을 활용할 수 있다.
이때 해당 훅으로 받아오는 값들은 항상 undefined도 타입으로 같이 반환하기 때문에 이 부분을 신경써서 구현해야 한다.

2. 네트워크 속도가 느린 환경에서 사용자 경험을 개선하기 위해 사용할 수 있는 UI/UX 디자인 전략과 기술적 최적화 방법은 무엇인가요?

UI/UX 디자인 전략:

  • 로딩 인디케이터 및 스켈레톤 스크린: 느린 네트워크 환경에서 로딩 상태를 사용자에게 명확히 보여주어 페이지가 로드 중임을 인식시키고, 스켈레톤 스크린을 사용해 페이지가 마치 로딩된 것처럼 보이게 한다.
  • 점진적 로딩(Lazy Loading): 전체 페이지를 한 번에 로딩하지 않고, 중요한 콘텐츠부터 먼저 로딩하며 나머지는 사용자가 필요할 때 로드되도록 설정
  • 이미지와 비디오 압축: 미디어 파일을 압축하거나 낮은 해상도 이미지를 우선 로딩한 후, 고해상도로 교체하여 로딩 시간을 단축

기술적 최적화 방법:

  • 코드 스플리팅(Code Splitting): Webpack이나 React의 React.lazy를 사용하여 코드를 여러 파일로 분리하고, 필요할 때만 로딩하여 초기 로딩 시간을 단축
  • 캐싱(Caching): 데이터를 로컬 스토리지, 세션 스토리지 또는 서비스 워커를 통해 캐싱하여, 사용자가 재방문할 때 로드 시간을 단축
  • 사전 로드(Prefetching): 사용자가 방문할 가능성이 높은 페이지나 필요한 리소스를 미리 로드하여 사용자가 요청하기 전에 준비
  • 네트워크 요청 최적화: 요청 횟수를 줄이고 필요한 데이터를 한 번에 가져오거나, 요청을 병렬로 처리하여 전체 로딩 시간을 단ㅊ

3. React에서 useStateuseReducer를 활용한 지역 상태 관리와 Context API 및 전역 상태 관리 라이브러리의 차이점을 설명하세요.

  • useState와 useReducer: 컴포넌트 내부에서 지역 상태를 관리하는 데 사용된다.

    • useState: 상태 변경 함수(setState)를 통해 상태 값을 업데이트
    • useReducer: 복잡한 상태 로직이 필요한 경우 사용되고 리듀서 함수와 액션을 통해 상태를 관리한다. 상태 업데이트가 여러 단계에 걸쳐 일어나거나 다양한 조건에 따라 변경될 때 유용하다.
  • Context API: Context API는 전역 상태를 관리하는데 사용하고 상태를 직접 부모-자식 컴포넌트로 전달하지 않고 Context를 통해 공유할 수 있다. 많은 상태나 빈번한 상태 변경이 필요한 경우에서 적절하지 못할 수 있다.

  • useState와와 useReducer : 상대적으로 작은 애플리케이션에서는 충분할 수 있지만, 상태가 여러 컴퍼넌트에 걸쳐 복잡하게 얽히게 되면 관리가 어려워질 수 있다.

  • Redux나 Recoil : 애플리케이션의 상태를 중앙 집중화하여, 복잡한 상태 변경을 보다 쉽게 추적하고 관리할 수 있도록 도와준다.

Copy link

@billy0904 billy0904 left a comment

Choose a reason for hiding this comment

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

제가 사용해보지 않은 방식으로 (button과 같이 비슷한 컴포넌트를 한 파일에 작성하는 등 ) 구현하셔서 보면서 많이 공부할 수 있었던 코드였습니다! 그리고 주석으로 TODO를 작성해주시고 코드 설명을 상세하게 적어주셔서 리뷰하기 좋았던 것 같습니다! 👍🌟

4주차 과제도 정말 수고 많으셨습니다! 🍀

Comment on lines +6 to +11
plugin: CracoAliasPlugin,
options: {
source: 'tsconfig',
baseUrl: './src',
tsConfigPath: './tsconfig.paths.json',
},

Choose a reason for hiding this comment

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

오 Craco를 사용하셨네요! 확실히 절대경로를 사용하니까 import문이 간결하고 깔끔해서 보기 좋은 것 같아요👍저도 다음번엔 CracoAlias 라이브러리를 사용해봐야겠습니다

Comment on lines +27 to +28
width: 375px;
height: 100vh;

Choose a reason for hiding this comment

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

전체 화면크기를 width는 픽셀로 고정하고 height은 vh로 설정하신 이유가 따로 있으신가요?

// Clock : 상단 바 시간

export default function Clock() {
const timeRef = useRef<any>(null); // 일단 any써뒀는데, 아닌 것 같음

Choose a reason for hiding this comment

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

저도 궁금해서 찾아봤는데 HTMLParagraphElement를 쓰는 방법이 있는 것 같아요! 아래 코드처럼 작성하면 어떻게 되는지 궁금하네요!

Suggested change
const timeRef = useRef<any>(null); // 일단 any써뒀는데, 아닌 것 같음
const timeRef = useRef<HTMLParagraphElement | null>(null);

Comment on lines +35 to +75
export function MemberListItem(user: UserInterface) {
return (
<ListItem user={user}>
<div className="flex flex-col justify-center gap-1 grow">
<Link to={`${user.id}`}>
{/* 사용자 이름 */}
<div className="font-subtitle">{user.userName}</div>
</Link>
</div>
<Link
to={`/chat/${user.id}`}
className="flex items-center justify-center mx-3"
>
<img
src={CHAT}
alt="chat"
/>
</Link>
</ListItem>
);
}

export function ChatListItem(user: UserInterface) {
return (
<ListItem user={user}>
<div className="flex flex-col justify-center gap-1 grow">
{/* 사용자 이름 */}
<div className="font-subtitle">{user.userName}</div>
{/* item 내용 미리보기 */}
{user.lastMessage && (
<StyledMessagePreview className="text-body text-gray-500">
{user.lastMessage}
</StyledMessagePreview>
)}
</div>
<div className="text-caption text-gray-500">
{user.lastMessageTimeStamp}
</div>
</ListItem>
);
}

Choose a reason for hiding this comment

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

비슷한 기능을 하는 컴포넌트는 이렇게 한 파일로 작성하고 export 하는 방식은 한번도 생각해보지 못해서 너무 신기합니다 ㅎㅎ props drilling을 줄일 수 있는 좋은 방법이라는 생각이 드네요! 배워갑니다!

Comment on lines +12 to +28
// 스타일을 동적으로 결정
const setMessageStyle = () => {
let styleStr = '';
if (message.emoji) styleStr += 'mb-4 ';
if (message.sender === 'me') {
styleStr +=
currentUser.id === mainUser.id
? 'bg-gray-50 text-gray-900 me-auto'
: 'bg-primary text-white ms-auto';
} else {
styleStr +=
currentUser.id === mainUser.id
? 'bg-primary text-white ms-auto'
: 'bg-gray-50 text-gray-900 me-auto';
}
return styleStr;
};

Choose a reason for hiding this comment

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

확실히 tailwind는 스타일을 동적으로 구현하는데 한계가 있어서 이런 부분에 있어서는 다른 라이브러리를 사용하는 게 좋은 것 같아요. 저는 그냥 style 태그를 사용했는데 styled components를 사용할 수도 있겠네요!

Comment on lines +17 to +28
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
toggleUser: (state, action: PayloadAction<UserInterface>) => {
state.currentUser =
state.currentUser.id === state.mainUser.id
? action.payload
: state.mainUser;
},
},
});

Choose a reason for hiding this comment

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

채팅방 내에서 프로필 클릭 시 유저 전환 이외에 유저 토글 함수를 사용하는 페이지가 따로 없는 것 같은데 유저 토글 기능을 전역 상태로 관리하는 이유가 있으신가요? (제가 놓친 기능이 있을 수도...)

Comment on lines +47 to +49
const handleDoubleClick = (messageId: string) => {
setSelectedMessageId(messageId);
};

Choose a reason for hiding this comment

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

이모지 선택을 위해 메시지를 더블클릭하면 텍스트와 요소들이 파란색으로 드래그 되는 현상이 있더라구요! 저도 이번주에 이모지 기능을 구현하면서 똑같이 겪었던 문제인데 event.preventDefault();를 사용하여 해결했습니다. 혹시 도움되실까 해서 올려요~!!

Suggested change
const handleDoubleClick = (messageId: string) => {
setSelectedMessageId(messageId);
};
const handleDoubleClick = (index: number, event: React.MouseEvent) => {
event.preventDefault(); // 요 라인 추가
setSelectedMessageId(messageId);
};

@jsomnium
Copy link

jsomnium commented Nov 4, 2024

희원님 이번주차 과제도 고생 많으셨습니당 ⸜(ˊᗜˋ)⸝
디자인과 맞게 깔끔하게 잘 구현해주셨네요. 기능도 대부분 다 구현하신 것 같아 멋있습니다!!
코드 리뷰 하면서 제가 신경쓰지 못했던 부분도 여러 가지 알아가서, 많이 배워갑니다.
또, 주석 TODO로 구현 할 것 정리해두신 부분이 인상깊었고, 나머지 주석도 귀엽게 달아두시는 것 같아서 즐겁게 구경했습니다 ㅋㅋㅋㅋ
다시 한번 고생하셨고 다음주차, 그리고 프로젝트도 파이팅입니다!! ⭐ ⭐

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