[Javascript] 요소 추가 방법 - innerHTML vs createElement

박기영·2023년 5월 2일
1

Javascript

목록 보기
41/45
post-custom-banner

이번 팀 프로젝트에서 동적으로 생성되는 HTML 태그를 createElement로 관리했다.
React에 익숙해서 어색하기는 했지만, 태그를 세부적으로 나눠서 볼 수 있다는 점은 좋았다.
그런데, 문득 그런 생각이 들었다.
이렇게 하나하나 관리해주는게 맞는건가? 왜 React가 나왔지? 이거 편하게 하려고 하는거 아닌가?
이런 질문들은 createElement 대신 다른 방법이 없는지 찾아보게 만들었고,
innerHTML에 직접 넣는 방식이 자주 비교되는 방법인 것을 알게 되었다.
어떤 것이 맞는걸까? 조사를 해보았다.

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

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가 안 좋은걸까? 뭐가 더 나은 방법이지?
결론은, "정답은 없다"이다.

다만, 여러 글들의 의견을 정리해보고자 한다.

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 than creating 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 the innerHTML.
- 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 게시글 -

따라서 성능적인 부분에서 반복 작업으로 인한 문제점을 해결할 수 있다!

innerHTML가 좋은 이유

여러 번의 변경 사항을 한번에 반영할 수 있다.

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 using innerHTML 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나 다른 프로젝트에서도 사용될지는 미지수이다.

참고 자료

javascripttutorial 게시글
kevinchi118님 블로그

profile
나를 믿는 사람들을, 실망시키지 않도록
post-custom-banner

0개의 댓글