-
Notifications
You must be signed in to change notification settings - Fork 65
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팀 장철희] [Chapter 1-2] 프레임워크 없이 SPA 만들기 #32
base: main
Are you sure you want to change the base?
Conversation
Create v node
Normalize v node
Create element
이벤트 메니저 로직 작성
Render element
This reverts commit 7ac8e38.
Render element bug fix
Update element
* } | ||
* } | ||
*/ | ||
const eventListeners = new Map(); |
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.
처음에는 단순하게 eventListeners를 배열로 만들고, addEvent할 때 event 등록에 필요한 값들을 push해서 관리하려고 했습니다.
배열로 관리하게 될 경우 removeEvent함수에서 특정 이벤트를 제거하기 위해 eventListeners를 계속 순회해야하는 로직이 필요한데, 등록된 이벤트가 많아질 수록 계속 순회하는 것은 좋지 않을 것 같아서 eventListeners의 구조를 중첩된 Map형태로 변경하였습니다.
const { loggedIn, currentUser, posts } = globalStore.getState(); | ||
|
||
const handleLikeClick = () => { | ||
if (!loggedIn) { | ||
alert("로그인 후 이용해주세요"); | ||
return; | ||
} | ||
|
||
let newLikeUsers = []; | ||
if (!likeUsers.includes(currentUser.author)) { | ||
newLikeUsers = [...likeUsers, currentUser.author]; | ||
} else { | ||
newLikeUsers = likeUsers.filter((user) => user !== currentUser.author); | ||
} | ||
|
||
globalStore.setState({ | ||
posts: posts.map((post) => { | ||
if (post.id === id) { | ||
return { | ||
...post, | ||
likeUsers: newLikeUsers, | ||
}; | ||
} | ||
return post; | ||
}), | ||
}); | ||
}; |
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.
전역 상태관리를 하고 있고, click에 대한 로직이 페이지에 있는 것보다 post 컴포넌트에 있는 것이 관심사가 맞다고 생각하여
로직에 필요한 값들(loggedIn, currentUser, posts)을 pops로 받지않고 스토어로 가지고 왔습니다.
props받지 않는 이유에 대한 적절한 논리가 될 수 있을까요?
const newVNodeChildren = mergeConsecutiveStrings(newVNode.children ?? []); | ||
const oldVNodeChildren = mergeConsecutiveStrings(oldVNode.children ?? []); |
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.
children이 ["좋아요", "0"]일 때, 엘리먼트에 "좋아요 0"이 되어야 하지만, 엘리먼트에 "0"만 노출되고 있었습니다. 금요일 새벽에 과제마감까지 시간이 얼마 남지 않아서 급하게 mergeConsecutiveStrings
함수를 추가하였습니다.
어거지로 떼운 느낌이어서 개선을 하고 싶은데.. 어떤 방향으로 하는 것이 좋을까요?
과제 체크포인트
기본과제
가상돔을 기반으로 렌더링하기
이벤트 위임
심화 과제
1) Diff 알고리즘 구현
2) 포스트 추가/좋아요 기능 구현
과제 셀프회고
비록 과제였지만 react 초기 부터 중요 개념 중 하나인 virtual dom을 구현해보았다. 아쉬운 점은 과제를 통과하는 것에 급한 나머지 개념적인 부분을 더 딥다이브하지 못한 것 같다. 과제 통과에 너무 매몰되지 말고 시간 분배를 적절히 해서 개념적인 부분도 보충할 수 있도록 해야겠다.
과제를 진행하면서 객체를 다루는 일이 많았는데, 재귀함수에서 다루다 보니 런타임에러가 꽤 빈번하게 발생하면서 타입스크립트를 사용하는 이유 중 하나를 체감하였다. 타입스크립트 였다면 타입 정의하다가 머리 깨졌을지도 있지만 휴먼 에러를 방지하는 것이 더 DX가 좋아지는 것 같다.
기술적 성장
createVNode를 로직을 구현하면서 jsx를 어떻게 트랜스파일하는지 궁금증이 생기게 되었습니다.
조사를 해보니 vite의 esbuild는 babel 없이도 jsx를 사용할 수 있는데,
jsxFactory의 기본 값이 React.createElement를 사용하는 것으로 동작하기 때문이라고 이해하였습니다.
따라서 react를 설치하지 않았을 경우에는 동작하지 않는데,
과제에 설정한 것 처럼 jsxFactory에 함수를 정의해서 jsx 변환 때 사용이 되도록 할 수 있습니다.
파일별로 구성하려면
// @jsx createVNode
와 같이 주석을 사용하여 구성할 수도 있습니다. JSX가automatic
으로 설정된 경우에는 이 설정이 적용되지 않습니다.automatic이 아닐 때
// @jsx createVNode
를 jsx파일에 넣지 않으면 트랜스파일을 하지 못하는 것을 확인 했습니다.코드 품질
학습 효과 분석
리뷰 받고 싶은 내용