이번 팀 프로젝트에서 동적으로 생성되는 HTML 태그를
createElement
로 관리했다.
React에 익숙해서 어색하기는 했지만, 태그를 세부적으로 나눠서 볼 수 있다는 점은 좋았다.
그런데, 문득 그런 생각이 들었다.
이렇게 하나하나 관리해주는게 맞는건가? 왜 React가 나왔지? 이거 편하게 하려고 하는거 아닌가?
이런 질문들은createElement
대신 다른 방법이 없는지 찾아보게 만들었고,
innerHTML
에 직접 넣는 방식이 자주 비교되는 방법인 것을 알게 되었다.
어떤 것이 맞는걸까? 조사를 해보았다.
보통 innerHTML
로 요소를 추가하게 되면 다음과 같은 방법을 사용한다.
Template Literal
을 사용하는 방법이 보통인 것 같다.
node.innerHTML += `
<h1>Hello Vanilla!</h1>
<div>
We use the same configuration as Parcel to bundle this sandbox, you can find more
info about Parcel
<a href="https://parceljs.org" target="_blank" rel="noopener noreferrer">here</a>.
</div>
`;
해당 코드가 실행될 때마다, 요소가 계속해서 추가되는 식이다.
물론, +=
이 아니라 =
이라면 통째로 요소가 변하게 될 것이다. 이런 디테일은 pass
createElement
의 경우, 요소의 생성, 수정, 추가를 일일이 해줘야한다.
const h1 = document.createElement("h1");
h1.innerText = "Hello Vanilla!";
node.appendChild(h1);
const div = document.createElement("div");
div.innerText = `We use the same configuration as Parcel to bundle this sandbox, you can find more
info about Parcel `;
node.appendChild(div);
const a = document.createElement("a");
a.href = "https://parceljs.org";
a.target = "_blank";
a.rel = "noopener noreferrer";
a.innerText = "here";
div.appendChild(a);
위에서 innerHTML
에 추가했던 것과 완벽하게 동일한 화면을 보여주는 코드이다.
간단한 코드라도 상당히 길어지는 것을 느낄 수 있다.
코드가 길어지니까 createElement
가 안 좋은걸까? 뭐가 더 나은 방법이지?
결론은, "정답은 없다"이다.
다만, 여러 글들의 의견을 정리해보고자 한다.
However, using the
innerHTML
causes the web browsers to reparse and recreate all DOM nodes inside the div element. Therefore, it is less efficient thancreating a new element and appending
to the div. In other words,creating a new element and appending
it to the DOM tree provides better performance than theinnerHTML
.
- JavaScript Tutorial 게시글 -
innerHTML
은 모든 노드를 재분석하고 재생성하기 때문에 비효율적이다.
As mentioned in the
innerHTML
tutorial, you should use it only when the data comes from a trusted source like a database.
If you set the contents that you have no control over to the innerHTML, the malicious code may be injected and executed.
- JavaScript Tutorial 게시글 -
innerHTML
은 신뢰할 수 있는 데이터를 가지고 사용해야하며,
그렇지않으면 악의적인 코드가 삽입되고 실행될 수 있다.
// 반복문을 통해 여러번 변경하는 방법
let div = document.querySelector('.container');
for (let i = 0; i < 1000; i++) {
let p = document.createElement('p');
p.textContent = `Paragraph ${i}`;
div.appendChild(p);
}
// createDocumentFragment를 사용하여 한번에 변경하는 방법
let div = document.querySelector('.container');
let fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
let p = document.createElement('p');
p.textContent = `Paragraph ${i}`;
fragment.appendChild(p);
}
div.appendChild(fragment);
createDocumentFragment
를 사용하여 반복 생성되는 노드를 관리하면,
이를 DOM에 추가하기 전까지는 어떠한 변경도 없다.
A document fragment does not link to the active DOM tree, therefore, it doesn’t incur any performance.
- JavaScript Tutorial 게시글 -
따라서 성능적인 부분에서 반복 작업으로 인한 문제점을 해결할 수 있다!
However,
innerHTML
does have an advantage when we want to do multiple things to an element.
- kevinchi118님의 medium -
여러 개의 작업을 해야하는 경우에 innerHTML
이 유리하다.
예를들면, li
의 반복 생성 등이 있겠다.
필자가 발췌한 블로그 작성자 분께서는 예시를 함께 제시하셨다.
// createElement를 사용하는 경우
for (i = 0; i < 100; i++) {
let newElement = document.createElement('p');
newElement.textContent = 'New Element Number: ' + i;
div.appendChild(newElement);
}
If we use
createElement
, we must append on each iteration, resulting in a recalculation of styles, painting and layout every single time. This is hardly efficient, and usinginnerHTML
within the loop the same way is even worse — but what if we add the paragraph htmls to a variable instead, and then only need to set the innerHTML one time at the end?
- kevinchi118님의 medium -
createElement
를 사용하여 여러 번 같은 작업을 수행해야한다면, 이는 비효율적이다.
물론, innerHTML
을 사용해서 그런 작업을 해도 마찬가지이다.
그렇다면..HTML 문장을 변수로 만들어서 추가한다면?
반복되는 작업을 마지막에 한번에 innerHTML
에 설정해줄 수 있다면?
// innerHTML을 사용하는 경우
let newElements = '';
for (i = 0; i < 100; i++) {
newElements += `<p>New Element Number: ${i}</p>`
}
div.innerHTML =+ newElements;
As we can see, in simple one-time cases, createElement/appendChild is more efficient, but in cases where many changes are made, innerHTML can be the more efficient choice.
- kevinchi118님의 medium -
하나의 요소를 다루는 경우 createElement
가 더 효율적이지만,
여러 번의 변경을 만들어내는 경우 innerHTML
이 더 효율적이다.
원본 블로그 글에 접속하시면, 실제로 성능을 비교하는 것도 체험하실 수 있습니다.
따라서, 결론은..본인이 중요하다고 생각하는 부분에 강점이 있는 방법을 사용하자!
필자는 본래 createElement
를 사용해왔고,
createDocumentFragment
를 사용하면 반복 작업도 DOM에 무리를 주지 않고 처리할 수 있기 때문에
아무래도..createElement
방법을 사용하지 않을까싶다.
물론, 이는 거의 Vanilla JS를 쓰는 프로젝트에서 사용할 것 같지만..?
React나 다른 프로젝트에서도 사용될지는 미지수이다.