JunilHwang / blog-comment

TIL comments
1 stars 0 forks source link

TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/ #26

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

Vanilla Javascript로 가상돔(VirtualDOM) 만들기 | 개발자 황준일

React와 Vue에서 사용되고 있는 가상돔(VirtualDOM)을 Vanilla JS로 직접 만드는 과정에 대해 소개합니다.

https://junilhwang.github.io/TIL/Javascript/Design/Vanilla-JS-Virtual-DOM/

hg-pyun commented 2 years ago

재밌는 글 감사합니다! 잘 읽고가요😆

webtk commented 2 years ago

정말 깔끔하게 잘 정리를 하셨네요.

soopdop commented 2 years ago

정말 좋은 글 잘 봤습니다. 많은 시간이 들이신 것 같네요. 궁금한 점이 있는데요. Virtual DOM을 사용하는 목적이 부분적인 업데이트 이외에도 다수의 업데이트를 스케쥴링하는 역할도 하는 것인지에 대해서 궁금합니다. 예를 들면, 같은 트리 노드에 짧은 시간 너무 많은 업데이트가 있다면 그 것은 virtual DOM에서만 이루어지고, real DOM에 사용자 경험을 해치지 않는 선에서 지연 업데이트를 시킨다면 불필요한 렌더링을 줄일 수 있을 것 같아서요. 물론 저의 추측이고, 검색을 해봤지만 원하는 답을 찾을 수 없어서 질문 한번 드려 봤습니다.

JunilHwang commented 2 years ago

@soopdop 안녕하세요!

예를 들면, 같은 트리 노드에 짧은 시간 너무 많은 업데이트가 있다면 그 것은 virtual DOM에서만 이루어지고, real DOM에 사용자 경험을 해치지 않는 선에서 지연 업데이트를 시킨다면 불필요한 렌더링을 줄일 수 있을 것 같아서요.

이건 사실 가상돔이 아니더라도 렌더링을 최적화할 때 적용하면 좋답니다 ㅎㅎ 가령, react에서는 setState를 하는 시점에 돔이 변경됩니다. 그런데 만약에 setState가 동시다발적으로 발생한다면 어떻게 될까요? 불필요하게 dom이 업데이트 되는 일이 많지 않을까요? 이 때 requestAnimationFrame 같은 API를 사용하여 한 프레임의 시간 동안 발생하는 변화를 모아서 처리해주면 불필요한 렌더링을 방지할 수 있답니다!

만약 가상돔에 업데이트 하는 과정에 위와 같은 내용이 추상화 되어있다면 훨씬 최적화된 렌더링을 시스템을 구축할 수 있지 않을까 싶어요!

jaehyeon48 commented 2 years ago

안녕하세요 준일님! 우선 준일님 블로그가 정말 많은 도움이 되어 감사하다는 말씀 드리고싶습니다!! 다름이 아니라, diff 알고리즘에서 속성을 업데이트 하는 로직 중에 없어진 props를 attribute에서 제거하는 부분인

if (newNode.getAttribute(name) !== undefined) continue;

코드에 대해 여쭤보고 싶은게 있습니다. MDN에서 살펴보니 어떤 노드의 속성이 존재하지 않을 때 getAttribute()의 리턴값이 null 혹은 '' 라고 하길래 저는 위 코드를 다음과 같이 바꿔서 사용해왔습니다:

const getAttrRes = newNode.getAttribute(name);
if (getAttrRes !== null && getAttrRes !== '') continue;

이렇게 하니, 없어진 props를 attribute에서 제거하는 작업은 잘 되는것 같은데, <input> 요소에서 사용하던 multiple 속성이 제거되는 버그가 발생했습니다.

좀 더 살펴보니 위의 multiple 속성도 그렇고 <button> 등에서 사용하는 disabled 속성과 같은 boolean attribute를 사용하는 케이스에 대해선 제대로 동작하지 않는것 같았습니다.

물론 여기에서 말하는 것처럼 disabled="disabled"와 같이 사용하는 경우엔 제대로 동작하겠으나, 그냥 disabled와 같이 사용한다거나, 혹은 disabled=""와 같이 사용하는 경우엔 제대로 동작하지 않는 것 같습니다. (그냥 disabled 와 같이 사용하니 getAttribute()의 결과가 ''로 나와 if문을 통과하지 못했습니다..)

따라서 이 문제를 해결하기 위해 getAttribute() 대신 hasAttribute()를 사용하니 모든 경우에 대해 정상적으로 동작하는 것 같았습니다.

이에 대해 준일님은 어떻게 생각하시는지 궁금합니다! 혹시 제가 놓친 부분이나 잘못 알고있는 부분이 있을 수 있으니 그 점 양해 부탁드립니다... 감사합니다! 🙏🙏

JunilHwang commented 2 years ago

@jaehyeon48 안녕하세요 재현님! 일단 disabled 같은 부분은 사실 고려해지 못했네요 ㅎㅎ 그래서 본문의 코드를 보완해야 하는게 맞습니다. 이에 대한 방안으로 hasAtrribute를 사용하는 것 까지 제시해주셨네요! 재현님이 작성한 방식 대로 만들면 될 것 같습니다.

그리고 변화에 대한 검사를 할 때, hasAttribute와 getAttribute를 같이 사용하면 될 것 같아요! 좋은 내용 코멘트 달아주셔서 감사합니다 🙇‍♂️

sanghogu commented 2 years ago

읽을수록 정리도 엄청 잘된걸 느끼네요! ㄷ ㄷ

cerulean85 commented 2 years ago

회사 프로젝트가 React를 반드시 적용해야 할 만큼 규모가 그리 크지 않은 탓에, Vanilla만으로 어떻게 하면 컴포넌트 및 가상돔 기반으로 소스코드를 작성할 수 있을까 고민하던 찰나에 이 글을 읽게 되었네요. 북마크에 등록해두고 수시로 와서 복습하도록 하겠습니다 :)

bohaesoju commented 2 years ago

예제마다 소스코드가 있어서 이해하기 너무 좋네요 !! 한가지 궁금한점이 있는데 virtualDOM 대신, 메모리에 올리고 변경된점이 있을때 다시 렌더링을 하는 예제를 보여주셨는데요. 그렇다면 리액트 팀에서는 왜 메모리를 이용하지 않고, virtualDOM 을 이용하여 최적화를 진행하였을까요?

keinn51 commented 1 year ago

찢었다

JunilHwang commented 1 year ago

@bohaesoju 가상돔을 사용하면 확장하기가 더 용이하기 때문이라고 생각합니다!

macjjuni commented 1 year ago

유익한 글 감사드립니다. 공부하는데 도움이 많이 됐어요. 그리고 "생선되면" 오타 발견해서 말씀드립니다!

JunilHwang commented 1 year ago

@macjjuni 제보 감사합니다 😁 수정해놨습니다!

n0eyes commented 1 year ago

유익한 글 매번 감사드립니다! 한 가지 궁금한 점이 있는데, 컨텐츠 목록들에 대해 개별적인 스켈레톤 UI를 적용하고 싶은 경우 각 이미지마다 로딩되는 속도가 달라 렌더 함수의 디바운싱 범위를 넘어가는 경우가 발생하고 있는데.. 이런 부분을 해결할 수 있는 아이디어가 있을까요? 뾰족한 수가 떠오르지 않네요 ㅜㅜ

const img = new Image().src = 'path'
img.addEventListener('load', () => setIsLoading(false))

많은 리렌더링이 일어나는 현상을 해결하고자 고민하다가 가상 돔 게시글까지 오게되었네요 항상 감사합니다!

dhdbtkd commented 6 months ago

글들이 참 심도 깊네요. 인상적이에요