-
Notifications
You must be signed in to change notification settings - Fork 10
[4주차] 신용섭 과제 제출합니다. #15
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
base: main
Are you sure you want to change the base?
Conversation
chaeyoungwon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
과제하시느라 정말 수고 많으셨습니다!! 🙌
남겨둔 코멘트들 한 번씩 읽어보시고,
가볍게 리팩토링해보셔도 좋고 코드 구조를 깊게 고민해보셔도 좋습니다!
앞으로의 과제도 파이팅입니다🫡
package.json
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오잉 현재 react-messenger 폴더 외부에 package.json, package-lock.json, .gitignore 파일이 잘못 설치된 것 같아요! 이 파일들은 프로젝트 루트에 불필요하므로 삭제해주시면 좋을 것 같아요 ~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 Layout 컴포넌트는 라우터 경로 관리와 고정 레이아웃 역할이 함께 들어가 있는 구조인데요,
Layout 내부에서 <Routes>를 직접 정의하는 대신,
아래처럼 라우팅은 상위(App) 혹은 라우터용 파일에서 관리하고,
Layout은 <Outlet />으로 하위 페이지를 렌더링하는 구조로 변경할 수 있습니다!
컴포넌트의 역할 분리에 대해 한 번 더 고민해보시면 좋을 것 같아요 👍
<BrowserRouter>
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<Home />} />
<Route path="/chat" element={<Chat />} />
<Route path="/chat/:roomId" element={<ChatRoom />} />
<Route path="/chat/:roomId/participants" element={<Participants />} />
<Route path="/board" element={<Board />} />
<Route path="/benefit" element={<Benefit />} />
<Route path="/timetable" element={<TimeTable />} />
<Route path="/profile" element={<Profile />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
</BrowserRouter>
기존에 작성하셨던 Layout 내부의 영역에는 다음과 같이 을 넣어주면 됩니다 !
<div className="flex-1 overflow-y-auto">
<Outlet />
</div>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
동일한 이미지가 두 번 들어간 것 같아요! 더불어, SVG 형식의 장점을 활용해보시면 좋을 것 같습니다.
SVG 파일을 텍스트 에디터로 열어보면 fill="#F9F9F9"처럼 색상이나 width, height 등의 속성을 직접 확인할 수 있는데요,
예를 들어 fill="currentColor"로 지정해두면, 이후 컴포넌트에서 className="text-white"처럼 동적으로 색상을 변경할 수 있습니다.
또한 vite-plugin-svgr 설치를 하신 거 같은데, 컴포넌트 적용이 안되셨나용..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 이미지는 말풍선 형태까지만 export하고, 안에 들어가는 텍스트는 코드 상에서 직접 작성해주시는 게 좋습니다!
이미지에 코드 상으로도 작성할 수 있는 텍스트를 포함하면 문구 수정이 어렵고, 렌더링 시에도 코드 상에서 직접 작성한 텍스트보다 로딩 효율이 떨어집니다.
|
|
||
| /* Figma components */ | ||
| @theme { | ||
| --font-sans: "Pretendard"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--font-pretendard: "Pretendard", sans-serif;
이렇게 fallback 값을 작성해주시면, 프리텐다드가 로드되지 못했을 때 자동으로 sans-serif 계열 폰트로 대체되게 됩니다!
또한 정의하신 폰트를, 하단 :root 에서도font-family: var(--font-sans)처럼 변수로 연결해주면 좋을 거 같네용
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 파일도 삭제해주시면 될 거 같네용. ㅎㅎ
| <div className="mt-1 flex items-center gap-3 py-2 body2-sb text-neutral-400 text-[19px]"> | ||
| <span className="text-neutral-900 text-2xl">강의실</span> | ||
| <span className="text-neutral-200 text-2xl">그룹챗</span> | ||
| <span className="text-neutral-200 text-2xl">쪽지</span> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 실제 탭 형태로 동작하게 만들면 좋을 것 같아용
지금은 단순한 리스트 형태인데, 상태를 추가해서 강의실이 디폴트로 선택된 상태로 보이게요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
react-messenger/src/pages/Chat.tsx
Outdated
| </main> | ||
| </header> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
옹 프리티어가 제대로 작동을 하지 않는건가 싶네용
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제가 제출전에 까먹은 것 같아요! 다시 적용해서 push했습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전역 상태를 관리하는 파일에서는 데이터의 상태만 관리하도록 유지하고,
목데이터 fetch 함수나 타입 정의는 외부 파일로 분리하는 게 좋을 것 같아요 😊
hammoooo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
채팅방, 채팅 참여자 목록까지 잘 구현하셨고 이번에도 css변수명 처럼 배울 점이 많은 코드였습니다!
과제 고생하셨습니다!!
| try { | ||
| const response = await fetch("/data/users.json"); | ||
| const data = await response.json(); | ||
| set({ participants: data.users || [] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 이렇게 데이터를 가져왔는데 더 실전적이라 좋은 방법인 것 같아요
| const onChangeInput = (v: string) => { | ||
| setInput(v); | ||
| if (!inputRef.current) return; | ||
| inputRef.current.style.height = "auto"; | ||
| const baseH = 40; | ||
| const maxH = 120; | ||
| const finalH = Math.max(baseH,Math.min(inputRef.current.scrollHeight, maxH)) | ||
| inputRef.current.style.height = finalH + "px"; | ||
| }; | ||
|
|
||
| // 새 메시지 들어오면 스크롤 하단 | ||
| useEffect(() => { | ||
| listRef.current?.scrollTo({ top: listRef.current.scrollHeight }); | ||
| }, [messages.length]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 UX 디테일의 코드가 깔끔하고 좋은 것 같아요!
|
|
||
| function App() { | ||
| return ( | ||
| <div className="iPhone-frame"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 그냥 하드코딩했는데 이렇게 변수명을 활용하니까 한눈에 들어와서 너무 좋습니다
| useEffect(() => { | ||
| try { | ||
| localStorage.setItem(`messages:${roomId}`, JSON.stringify(messages)); | ||
| } catch (e) { | ||
| console.warn("Failed to save messages to localStorage:", e); | ||
| } | ||
| }, [messages, roomId]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다시 채팅방에 들어오면, 이전에 저장되었던 로컬스토리지 정보가 날아가는데 이 부분의 로직이
로컬스토리지 데이터를 가져오기 전에 useState의 default값을 저장해서 그런 게 아닐까 싶습니다!
| > | ||
| <img src="/icons/plus.svg" alt="" className="w-5 h-5 opacity-80" /> | ||
| </button> | ||
| <textarea |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
입력 부분의 글씨가 회색이라 가독성이 떨어지는 것 같아요


링크
배포 링크
피그마 링크
참여자 목록 페이지

내 프로필 페이지

느낀점
이번에는 컴포넌트 분리를 제대로 하기 위해 노력했다.

처음에는 전반적인 구현을 위주로 시작하고, 이후에 여러 채팅방에서 사용이 되기 위해서 컴포넌트를 분리를 어떻게 하면 좋을까를 고민을 했다.
뿐만아니라 3주차 과제때는 하드코딩으로 처리했던 데이터들을 json으로 분리하여 향후 수정에 도움이 될 수 있도록 하였다.
실제로 수정이 과제중에 필요했었는데 이전에는 tsx에서 찾는데 시간이 소모됐었다면 분리 이후 수정에서는 쉽게 수정할 수 있어 편리했다.
컴포넌트나 데이터 분리의 중요성을 깨달을 수 있었다.
4주차 과제에서 가장 크게 중요했던 것은 단순히 프로젝트 제출에서 끝이 아니라 3주차에 이어서 하기 때문에 단순히 돌아간다 라는 부분에서 넘어가기 어려운 것들이 많았다. 컴포넌트를 분리를 초기에 실천하며 진행했다면 더 수월한 과제였을 수도 있다는 생각에 향후 과제에서는 나만의 코드 규칙으로 출발해야한다는 생각이 많이 들었다.
Key Question
1. React Router의 동적 라우팅(Dynamic Routing)이란 무엇이며, 언제 사용하나요?
동적 라우팅(Dynamic Routing)은 웹 어플리케이션에서 클라이언트의 요청에 따라 동적으로 경로를 처리하는 라우팅 방식을 말한다.
이는 사용자의 입력, 상태 변화, 또는 다양한 조건에 따라 서버가 어떤 페이지나 리소스를 제공할지를 결정하는 것을 의미한다.
UI가 동일하고 데이터만 다른 경우의 상세 페이지를 구성할 때 쓰인다.
이번 과제에서 있던 예시
2. 네트워크 속도가 느린 환경에서 사용자 경험을 개선하기 위해 사용할 수 있는 UI/UX 디자인 전략과 기술적 최적화 방법은 무엇인가요?
낙관적 업데이트(Optimistic Update)를 활용한다!
API 호출과 같은 비동기 작업이 완료되기 전에 사용자 인터페이스(UI)를 먼저 업데이트하여, 사용자가 즉각적인 반응을 느낄 수 있도록 사용자 경험(UX)을 향상시키는 기법
사용을 통해 빠른 사용자 경험을 제공하고, 보다 자연스러운 상호작용, 복잡한 상태 관리 간소화의 이점이 있다.
3. React에서 useState와 useReducer를 활용한 지역 상태 관리와 Context API 및 전역 상태 관리 라이브러리의 차이점을 설명하세요.
언제: 단순하고 독립적인 컴포넌트 상태(토글, 입력 값, 모달 열림 등).
장점: 가장 간단, 보일러플레이트 최소.
단점: 관련 필드가 많아지고 업데이트 로직이 복잡해지면 관리가 어려움.
언제: 상태가 여러 필드로 구성되고 업데이트 규칙이 복잡하거나,
액션 기반으로 변경 내역을 명확히 하고 싶을 때(폼 마법사, 복합 편집기).
장점: 로직이 한 곳(reducer)에 모여 테스트/추론 용이. 디스패치 기반.
단점: 보일러플레이트 증가, 아주 단순한 상태에는 오버킬.
내장 기능, 간단한 전역 값 주입에 적합.
Zustand: 보일러플레이트 적고 선택적 구독으로 리렌더 최소화. (당신이 자주 쓰는 툴)
Redux Toolkit: 팀 규모↑, 엄격한 패턴/디버깅 도구 필요할 때 표준 솔루션.
Recoil/Jotai/MobX: 세분화된 구독이나 선언적 모델이 필요할 때.