<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>DR_Developer</title>
    <link>https://dr-dev.tistory.com/</link>
    <description>도움이 되는 글들을 전하고 싶습니다.</description>
    <language>ko</language>
    <pubDate>Thu, 16 Jul 2026 11:17:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>drk_4</managingEditor>
    <image>
      <title>DR_Developer</title>
      <url>https://tistory1.daumcdn.net/tistory/5752005/attach/1fab23eb27574589a3916fa0e83853c8</url>
      <link>https://dr-dev.tistory.com</link>
    </image>
    <item>
      <title>[자료구조] 자바스크립트로 우선순위 큐(Priority Queue) 구현하기</title>
      <link>https://dr-dev.tistory.com/26</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;우선순위 큐란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 일반적인 큐는 선입선출 (FIFO)원칙에 따라 데이터가 처리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 우선순위 큐는 각 데이터들이 &lt;b&gt;우선순위&lt;/b&gt;가 있어서, 큐에 들어온 순서는 차순위가 되고 &lt;u&gt;정해진 우선순위에 따라 데이터가 큐에서 나가게 된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Heap 자료구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Heap 자료구조는 완전 이진트리의 일종이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 완전이진트리란 루트 노드부터 시작하여 왼쪽 자식, 오른쪽 자식 순서대로 데이터가 삽입되는 트리를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Heap은 항상 루트 노드를 제거하는 식으로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자바스크립트로 우선순위 큐를 구현하는데 있어서 이 Min Heap (최소 힙) 자료구조를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 최소 힙은 부모 노드가 항상 자식 노드보다 값이 작다는 특징을 갖고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOFVtP/btsFGMzVANU/OwG2pFkRIKeEgqUnf4M8g0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOFVtP/btsFGMzVANU/OwG2pFkRIKeEgqUnf4M8g0/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://www.geeksforgeeks.org/difference-between-min-heap-and-max-heap/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOFVtP/btsFGMzVANU/OwG2pFkRIKeEgqUnf4M8g0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOFVtP%2FbtsFGMzVANU%2FOwG2pFkRIKeEgqUnf4M8g0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;788&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://www.geeksforgeeks.org/difference-between-min-heap-and-max-heap/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일반 배열을 사용하지 않는 이유는 무엇일까?&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터를 조회하기 위해 배열을 순회하게 되면 O(n)의 시간 복잡도가 걸린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 힙을 사용하게 되면 O(1)의 시간복잡도까지 낮출 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자료를 추가로 삽입하거나 삭제하는 경우에도 O(logn)의 시간복잡도로, 굉장히 높은 효율성을 가진다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;최소 힙 기반의 우선순위 큐를 직접 구현해보자.&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2차원 트리를 선형적인 배열로 구현할 수 있다.&lt;/h4&gt;
&lt;pre id=&quot;code_1709912130014&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;class PriorityQueue {
  constructor() {
    this.heap = [];
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;생성자 함수로는 우선 빈 배열을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709912122164&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt; size() {
  	return this.heap.length
  }
  
  isEmpty() {
  	return this.heap.length === 0
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;우선순위 큐의 사이즈와 비어있는지 여부를 확인하는 메서드들을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;데이터 삽입 기능을 구현해보자&lt;/h4&gt;
&lt;pre id=&quot;code_1709912536272&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; enqueue(value) {
  	this.heap.push(value);
    this.heapifyUp();
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;enqueue라는 메서드를 추가하여 힙 배열에 추가하려는 값을 push하였다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이후 최소 힙 원칙에 따라 정렬하는 heapifyUp메서드를 실행한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;heapifyUp 메서드에 대한 상세 구현은 아래에서 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709914255619&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt; heapifyUp() {
  	let i = this.size() - 1;
    const lastNode = this.heap[i];
    
    while (i &amp;gt; 0) {
      const parentIndex = Math.floor((i - 1) / 2);
      
      if (this.heap[parentIndex] &amp;gt; lastNode) {
        this.heap[i] = this.heap[parentIndex];
        i = parentIndex;
      } else {
        break;
      }
    }
    
    this.heap[i] = lastNode;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;부모노드의 인덱스를 계산하여 크기 비교를 하고, 더 작다면 위치를 바꿔주는 반복문을 통해 맨끝에 새로 삽입된 노드를 정렬해주는 코드이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;삽입을 구현했으니, 노드를 삭제하는 것도 구현해보자.&lt;/h4&gt;
&lt;pre id=&quot;code_1709915964488&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dequeue() {
    if (this.isEmpty()) return null;
    
    const rootNode = this.heap[0];
    const lastNode = this.heap.pop();
    this.heap[0] = lastNode;
    this.heapifyDown();
    
    return rootNode;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 말했다시피 힙에서의 삭제는 항상 루트노드에서만 일어난다. 루트 노드 자리를 제일 마지막 노드로 가져오고 heapifyDown 메서드로 정렬해주면 자연스레 기존의 루트 노드는 참조를 잃고 큐에서 사라지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709916479479&quot; class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;  heapifyDown() {
  	let i = 0;
    const rootNode = this.heap[i];
 	const heapSize = this.size();
    let swapIndex;
    
    while (true){
    	let leftChildIndex = i * 2 + 1;
    	let rightChildIndex = (i * 2) + 2;
        
        if (leftChildIndex &amp;lt; heapSize) {
            if (this.heap[leftChildIndex] &amp;lt; this.heap[i]) {
                swapIndex = leftChildIndex
        	}
        }
        
        if (rightChildIndex &amp;lt; heapSize) {
        	f (
                (swapIndex === null &amp;amp;&amp;amp; this.heap[rightChildIndex] &amp;lt; this.heap[i]) ||
                (swapIndex !== null &amp;amp;&amp;amp; this.heap[rightChildIndex] &amp;lt; this.heap[leftChildIndex])
            ) {
                swapIndex = rightChildIndex;
            }
        }
        if (swapIndex === null) break;
        
        [this.heap[i], this.heap[swapIndex]] = [this.heap[swapIndex], this.heap[i]];
        i = swapIndex;
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;heapifyDown은 상위 루트노드를 좌우의 자식노드와 비교하여 트리의 하위로 점점 내리면서 정렬시키는 메서드이다. 왼쪽 자식과 오른쪽 자식 중 바꾸어야할 인덱스를 swapIndex로 지정하여 노드 위치를 교환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;전체 코드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1709921420768&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class PriorityQueue {
  constructor() {
  	this.heap = [];
  }
  
  size() {
    return this.heap.length
  }
  
  isEmpty() {
  	return this.heap.length === 0
  }
 
  heapifyUp() {
  	let i = this.size() - 1;
    const lastNode = this.heap[i];
    
    while(i &amp;gt; 0) {
      const parentIndex = Math.floor((i - 1) / 2);
      
      if (this.heap[parentIndex] &amp;gt; lastNode) {
        this.heap[i] = this.heap[parentIndex];
        i = parentIndex;
      } else {
        break;
      }
    }
    
    this.heap[i] = lastNode
  }
 
  enqueue(value) {
   	this.heap.push(value);
    this.heapifyUp();
  }
  
  dequeue() {
    if (this.isEmpty()) return null;
    
    const rootNode = this.heap[0];
    const lastNode = this.heap.pop();
    this.heap[0] = lastNode;
    this.heapifyDown();
    
    return rootNode;
  }
  
  heapifyDown() {
  	let i = 0;
    const rootNode = this.heap[i];
 	const heapSize = this.size();
    let swapIndex;
    
    while(i &amp;gt; 0) {
    	let leftChildIndex = i * 2 + 1;
    	let rightChildIndex = (i * 2) + 2;
        
        // 왼쪽 자식 인덱스가 범위 안에 있고,
        if (leftChildIndex &amp;lt; heapSize) {
        	// 대상이 왼쪽 자식보다 크다면, 왼쪽 자식 인덱스를 바꿔야할 인덱스로 지정
            if (this.heap[leftChildIndex] &amp;lt; this.heap[i]) {
                swapIndex = leftChildIndex
        	}
        }
        // 오른쪽 자식 인덱스가 범위 안에 있고, 
        if (rightChildIndex &amp;lt; heapSize) {
        	if (
            // 바꿔야할 인덱스가 지정된 값이 없고, 대상이 오른쪽 자식보다 크거나
                (swapIndex === null &amp;amp;&amp;amp; this.heap[rightChildIndex] &amp;lt; this.heap[i]) ||
            // 바꿔야할 인덱스가 왼쪽으로 지정되어 있지만, 왼쪽 자식이 오른쪽 자식보다 크다면
                (swapIndex !== null &amp;amp;&amp;amp; this.heap[rightChildIndex] &amp;lt; this.heap[leftChildIndex])
            ) {
            // 바꿔야할 인덱스로 오른쪽 자식 인덱스를 지정한다.
                swapIndex = rightChildIndex;
            }
        }
        // 바꿔야할 인덱스가 없다면 반복문 종료
        if (swapIndex === null) break;
        
        // 바꿔야할 인덱스와 대상의 위치를 바꿔준다.
        [this.heap[i], this.heap[swapIndex]] = [this.heap[swapIndex], this.heap[i]];
        i = swapIndex;
    }
    
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;글을 쓰는데 도움이 된 자료들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709911625402&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JavaScript로 Heap | Priority Queue 구현하기&quot; data-og-description=&quot;그래프 자료구조에서 엣지 간에 최단거리를 구하는 다익스트라 알고리즘(Dijkstra Algorithm)을 사용해서 문제 해결을 하려고 했더니, 우선순위 큐에 대한 이해가 부족해서 이 글을 쓰게 되었다.&quot; data-og-host=&quot;jun-choi-4928.medium.com&quot; data-og-source-url=&quot;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&quot; data-og-url=&quot;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdPPxm/hyVud4BX36/xIDmuNirGPQsrbFy3cKFFK/img.png?width=496&amp;amp;height=432&amp;amp;face=0_0_496_432,https://scrap.kakaocdn.net/dn/bB8bkM/hyVunTGxgb/hytDU7ELwN5emRrYg8g1k1/img.jpg?width=1358&amp;amp;height=2315&amp;amp;face=0_0_1358_2315,https://scrap.kakaocdn.net/dn/IjN51/hyVufuzifB/AzH222khWib531ZsY2jp70/img.jpg?width=1358&amp;amp;height=1358&amp;amp;face=0_0_1358_1358&quot;&gt;&lt;a href=&quot;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-choi-4928.medium.com/javascript%EB%A1%9C-heap-priority-queue-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-8bc13bf095d9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdPPxm/hyVud4BX36/xIDmuNirGPQsrbFy3cKFFK/img.png?width=496&amp;amp;height=432&amp;amp;face=0_0_496_432,https://scrap.kakaocdn.net/dn/bB8bkM/hyVunTGxgb/hytDU7ELwN5emRrYg8g1k1/img.jpg?width=1358&amp;amp;height=2315&amp;amp;face=0_0_1358_2315,https://scrap.kakaocdn.net/dn/IjN51/hyVufuzifB/AzH222khWib531ZsY2jp70/img.jpg?width=1358&amp;amp;height=1358&amp;amp;face=0_0_1358_1358');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JavaScript로 Heap | Priority Queue 구현하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;그래프 자료구조에서 엣지 간에 최단거리를 구하는 다익스트라 알고리즘(Dijkstra Algorithm)을 사용해서 문제 해결을 하려고 했더니, 우선순위 큐에 대한 이해가 부족해서 이 글을 쓰게 되었다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-choi-4928.medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709911631238&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Efficient way to implement Priority Queue in Javascript?&quot; data-og-description=&quot;Priority Queues have a priority value and data, for every entry. Thus, when adding a new element to the queue, it bubbles up to the surface if it has a higher priority value than elements already ...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&quot; data-og-url=&quot;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbuoG8/hyVxwBshFD/wb2EoMJtoNU4Fz9GPUChx1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/42919469/efficient-way-to-implement-priority-queue-in-javascript&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbuoG8/hyVxwBshFD/wb2EoMJtoNU4Fz9GPUChx1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Efficient way to implement Priority Queue in Javascript?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Priority Queues have a priority value and data, for every entry. Thus, when adding a new element to the queue, it bubbles up to the surface if it has a higher priority value than elements already ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>javascript</category>
      <category>Priority Queue</category>
      <category>디스크 컨트롤러</category>
      <category>백준</category>
      <category>우선순위큐</category>
      <category>자료구조</category>
      <category>자바스크립트</category>
      <category>코딩테스트</category>
      <category>프로그래머스</category>
      <category>힙</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/26</guid>
      <comments>https://dr-dev.tistory.com/26#entry26comment</comments>
      <pubDate>Sat, 9 Mar 2024 03:14:12 +0900</pubDate>
    </item>
    <item>
      <title>리액트 생명주기와 useEffect</title>
      <link>https://dr-dev.tistory.com/25</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;React 컴포넌트의 생명주기&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사람이 태어나고, 성장하고, 죽는 것처럼 React 컴포넌트는 생명주기를 갖는다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;react-lifecycle-methods-diagram.png&quot; data-origin-width=&quot;2280&quot; data-origin-height=&quot;1276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BC909/btsFt4nd5JJ/GTzYF6fOKkn1zc1ja4GaGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BC909/btsFt4nd5JJ/GTzYF6fOKkn1zc1ja4GaGk/img.png&quot; data-alt=&quot;REACT 컴포넌트의 생명주기와 각 시기별 사용할 수 있는 생명주기 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BC909/btsFt4nd5JJ/GTzYF6fOKkn1zc1ja4GaGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBC909%2FbtsFt4nd5JJ%2FGTzYF6fOKkn1zc1ja4GaGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2280&quot; height=&quot;1276&quot; data-filename=&quot;react-lifecycle-methods-diagram.png&quot; data-origin-width=&quot;2280&quot; data-origin-height=&quot;1276&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;REACT 컴포넌트의 생명주기와 각 시기별 사용할 수 있는 생명주기 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;바로, &quot; 생성 - 업데이트 - 제거&quot;의 과정이 그것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;생성될 때 (Mount)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;constructor로 정의해놓은 것들이 실행되고 render되면서 mount(생성)된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;업데이트될 때 (Update)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트는 props나 state가 변경되었을 때 발생한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제거될 때 (Unmount)&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 컴포넌트가 하위 컴포넌트를 더이상 그리지 않을 때, unmount(제거) 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(클래스 컴포넌트 기준으로) 모든 컴포넌트는 render 메서드를 갖는다. render 메서드는 웹 컴포넌트를 실제 DOM 요소에 그려주는 역할을 한다. render 메서드는 제거될 때를 말고는 모두 실행되는데, 그 전후에 필요한 사이드 이펙트들을 생명주기 메서드들을 통해 실행시킬 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자주 사용하는 생명주기 메서드들&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 생명주기 그림에도 나와있듯이, 각 생명주기 시점에 따라 실행할 수 있는 생명주기 메서드들이 다양하다. 이중에서도 자주 사용하는 3개 생명주기 메서드만 자세히 알아보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;componentDidMount&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 모두 구성된 직후에 componentDidMount가 호출된다. 이 메서드는 컴포넌트가 렌더링된 직후에 호출된다. 이 시점에서는 DOM 노드에 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;이벤트 리스너를 추가하거나 API 호출을 수행하는 등의 작업을 수행하면 효과적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;componentDidUpdate&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 업데이트된 직후에 componentDidUpdate가 호출된다. 이 메서드는 컴포넌트가 업데이트된 직후에 호출된다. 이 시점에서는 이전의 props와 state를 접근할 수 있으며, 이를 통해 컴포넌트가 업데이트되기 전과 후를 비교하여 필요한 작업을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;화면에 출력되는 화면 구성을 변경하고자 할 때 많이 사용한다. 그러나 데이터 변경과 관련한 함수를 클라이언트가 직접 처리하는 경우는 많지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;componentWillUnmount&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 제거되기 직전에 componentWillUnmount가 호출된다. 이 메서드는 컴포넌트가 제거되기 직전에 호출된다. 이 시점에서는 컴포넌트가 제거되기 전에 필요한 작업을 수행할 수 있다. 이 메서드는 컴포넌트가 제거되기 직전에 호출되기 때문에, 이벤트 리스너를 제거하거나 네트워크 요청을 취소하는 등의 작업을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;컴포넌트의 동작을 위해 사용되었던 메소드들의 리소스를 제거해줄 때 사용한다. 어플리케이션 성능 향상을 위해 사용되는 경우가 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;함수형 컴포넌트에서의 Effect 훅, &lt;b&gt;useEffect&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급한 생명주기 메서드들은 클래스형 컴포넌트에서만 사용할 수 있었다. 훅의 등장으로 useEffect를 사용할 수 있게 되면서 함수형 컴포넌트에서도 생명주기 시점에 따른 사이드 이펙트를 실행할 수 있게 되었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. useEffect(callBack); (&lt;b&gt;≒&lt;/b&gt; componentDidMount + componentDidUpdate + componentWillUnmount)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오로지 콜백만 파라미터로 넘겨주는 경우다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, 컴포넌트가 생성되고, 업데이트되고 제거되기전에 모두 콜백이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급한 자주 쓰이는 생명주기 메서드 3개가 모두 실행된다고 이해하면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. useEffect(callBack, []);(&lt;b&gt;≒&lt;/b&gt; componentDidMount)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 파라미터로 빈 array를 넘겨주는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째에 오는 array는 dependency array라고 하는데, 여기에 오는 요소들이 변경이 생길때마다 callback을 다시 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 array이므로 업데이트가 생기지 않으므로, 생성되고 나서 1번만 콜백이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생명주기 메서드의 componentDidMount와 동일하다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. useEffect(callBack, [state, props]);(&lt;b&gt;≒&lt;/b&gt; componentDidMount + componentDidUpdate)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dependency array에 요소를 넘겨준 경우이다. state나 props를 넘겨주는데, 처음 컴포넌트가 생성됐을 때 뿐만 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state나 props가 변경되어 컴포넌트가 업데이트 되어야할때도 콜백이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;componentDidMount와 componentDidUpdate 메서드를 합쳤다고 생각하면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. cleanup function (&lt;b&gt;≒&lt;/b&gt; componentWillUnmount)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우는 예시코드를 통해 확인해보자.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;useEffect(()=&amp;gt;{
    exampleAPI.subscribe();
    return(() =&amp;gt; exampleAPI.unsubscribe()); // componentWillUnmount
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사이드 이펙트로 어떤 모델을 참조하는 구독 메서드를 실행했다고 가정하자. 이것은 사이드 이펙트이기 때문에 컴포넌트가 제거되어도 구독 자체는 유지가 될 것이다. 사이드 이펙트로 실행한 구독을 다시 해제하지 않으면, 더이상 사용하지 않아 제거된 컴포넌트에서 일어난 구독일지라도 계속해서 외부를 참조하고 있어 불필요한 메모리 누수가 발생할 수 있다. 이때 구독을 해제하는 함수를 return과 함께 useEffect 내에서 처리해주면, 컴포넌트가 제거되기 전에 구독을 해제하고 컴포넌트가 제거될 수 있다. 이렇게 이펙트에서 실행된 함수를 return문과 함께 정리하는 함수를 'cleanup function'이라고 한다. 이 cleanup function이 useEffect 내에서 이뤄지면, 컴포넌트가 제거되기전에 실행되므로 componentWillUnmount와 동일한 시점에 실행된다고 볼 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고한 자료들&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html&quot;&gt;리액트 레거시 공식문서 - State and Lifecycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/&quot;&gt;react-lifecycle-methods-diagram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/mhBfAibYwHQ?si=eIQ2F3utVQlCZ-JE&quot;&gt;동빈나 유튜브&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.react.dev/learn/lifecycle-of-reactive-effects&quot;&gt;리액트 한글 번역 공식문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@sukong/REACT-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80-useEffect-Hook#-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%9B%85%EC%9D%84-%EB%8F%84%EC%9E%85%ED%95%9C-%EB%AA%A9%EC%A0%81&quot;&gt;[React] 리액트의 생명주기와 Hook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[[React] 리액트의 생명주기와 Hook&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 기반 라이브러리인 react에서, 컴포넌트가 가지는 생명주기와, 함수형 컴포넌트에서 활용하는 Hook 중 useEffect에 대해서 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;velog.io](&lt;a href=&quot;https://velog.io/@sukong/REACT-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80-useEffect-Hook#-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%9B%85%EC%9D%84-%EB%8F%84%EC%9E%85%ED%95%9C-%EB%AA%A9%EC%A0%81&quot;&gt;https://velog.io/@sukong/REACT-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0%EC%99%80-useEffect-Hook#-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%9B%85%EC%9D%84-%EB%8F%84%EC%9E%85%ED%95%9C-%EB%AA%A9%EC%A0%81&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[State and Lifecycle &amp;ndash; React&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org](&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html&quot;&gt;https://ko.legacy.reactjs.org/docs/state-and-lifecycle.html&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[React Lifecycle Methods diagram&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fully interactive and accessible React Lifecycle Methods diagram.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;projects.wojtekmaj.pl](&lt;a href=&quot;https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/&quot;&gt;https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/mhBfAibYwHQ&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[반응형 effects의 생명주기 &amp;ndash; React&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The library for web and native user interfaces&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ko.react.dev](&lt;a href=&quot;https://ko.react.dev/learn/lifecycle-of-reactive-effects&quot;&gt;https://ko.react.dev/learn/lifecycle-of-reactive-effects&lt;/a&gt;)&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>frontend</category>
      <category>react</category>
      <category>react lifecycle</category>
      <category>useEffect</category>
      <category>리액트</category>
      <category>리액트 생명주기</category>
      <category>리액트 훅</category>
      <category>클래스 컴포넌트</category>
      <category>프론트엔드</category>
      <category>함수형 컴포넌트</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/25</guid>
      <comments>https://dr-dev.tistory.com/25#entry25comment</comments>
      <pubDate>Sat, 2 Mar 2024 00:41:34 +0900</pubDate>
    </item>
    <item>
      <title>[React] Virtual DOM과 동작원리</title>
      <link>https://dr-dev.tistory.com/24</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #1f2328; text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;1. Virtual DOM이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;virtual DOM은 실제 DOM을 추상화한 자바스크립트 객체이다. &lt;/b&gt;&lt;/u&gt;실제 DOM이 갖고있는 속성들&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;(id, class, style, innerHTML 등)&lt;/span&gt;을 virtual DOM도 갖고 있다. 하지만 DOM API&lt;span style=&quot;background-color: #ffffff; color: #1f2328; text-align: left;&quot;&gt;(getElementById, querySelector 등)&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;는 갖고 있지 않기 때문에 실제 DOM보다는 가볍다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #1f2328; text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-virtual-dom의-예시&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/hyunwlee-dev/interview-study/blob/main/dongryul/virtualDOM.md#virtual-dom%EC%9D%98-%EC%98%88%EC%8B%9C&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;2. Virtual DOM의 예시&lt;/h3&gt;
&lt;div style=&quot;background-color: #000000; color: #1f2328; text-align: start;&quot;&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;background-color: #000000; color: #000000;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let domNode = {
  tagName: 'div',
  attributes: {
    id: 'container',
    class: 'container',
    style: 'background-color: red;'
  },
  children: [
    {
      tagName: 'h1',
      attributes: {},
      children: ['Hello, Virtual DOM!']
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;virtual DOM은 자바스크립트 객체라고 하였다. 위 코드는 virtual DOM을 약식으로 구현한 코드이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;virtual DOM은 메모리 상에서 동작하기 때문에 빠르게 연산 가능하고 실제 렌더링되지 않기 때문에 연산 비용이 적다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;3. Virtual DOM을 통해 Real DOM을 변경하는 방식&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a id=&quot;user-content-데이터가-변경되면-가상-dom의-ui가-변경되고-실제-dom과-비교하여-바뀐-부분만-적용한다&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/hyunwlee-dev/interview-study/blob/main/dongryul/virtualDOM.md#%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EB%B3%80%EA%B2%BD%EB%90%98%EB%A9%B4-%EA%B0%80%EC%83%81-dom%EC%9D%98-ui%EA%B0%80-%EB%B3%80%EA%B2%BD%EB%90%98%EA%B3%A0-%EC%8B%A4%EC%A0%9C-dom%EA%B3%BC-%EB%B9%84%EA%B5%90%ED%95%98%EC%97%AC-%EB%B0%94%EB%80%90-%EB%B6%80%EB%B6%84%EB%A7%8C-%EC%A0%81%EC%9A%A9%ED%95%9C%EB%8B%A4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;데이터가 변경되면, 가상 DOM의 UI가 변경되고, 실제 DOM과 비교하여 바뀐 부분만 적용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J3bUB/btsFer5ODEd/QVqlXbL2ewdNIAJk3Dxt40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J3bUB/btsFer5ODEd/QVqlXbL2ewdNIAJk3Dxt40/img.png&quot; data-alt=&quot;왼쪽상단이 바뀌기 전의 가상돔, 왼쪽 하단이 바뀌고 난뒤의 가상돔이며, 이 둘을 비교하여 바뀐부분만 오른쪽의 실제 DOM에 반영한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J3bUB/btsFer5ODEd/QVqlXbL2ewdNIAJk3Dxt40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ3bUB%2FbtsFer5ODEd%2FQVqlXbL2ewdNIAJk3Dxt40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;463&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;왼쪽상단이 바뀌기 전의 가상돔, 왼쪽 하단이 바뀌고 난뒤의 가상돔이며, 이 둘을 비교하여 바뀐부분만 오른쪽의 실제 DOM에 반영한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;비교 (Diffing&lt;/b&gt;&lt;/u&gt;) : virtual DOM이 업데이트 되면 업데이트 이전의 virtual DOM과 비교하여 정확히 어떤 virtual DOM Element가 변경되었는지 확인한다. 효율적인 알고리즘을 통해 변경된 지점을 빠르게 파악할 수 있다.&lt;/li&gt;
&lt;li&gt;만일, 가상 DOM의 속성 값만 변했다면 그것만 업데이트한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;하지만 element 태그나 컴포넌트가 변경되었다면 해당 element를 삭제하고(unmount), 새로운 Virtual DOM element를 추가한다.&lt;/li&gt;
&lt;li&gt;새로운 virtual DOM을 만들어 실제 DOM과 비교하여 바뀐 부분만 적용한다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;Batch update&lt;/b&gt;&lt;/u&gt;: 10곳이 바뀌었다면 10번 렌더링하는 것이 아니라, 바뀐 부분을 한꺼번에 업데이트 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;4. Diffing (비교) 다음 단계가&amp;nbsp; Reconciliation (재조정) 단계일까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 자료를 확인하면서 비교 단계와 재조정 개념을 살펴봤지만, 비교단계가 끝나고 재조정이 이뤄진다는 별개의 개념은 아니라는 결론을 내렷다. 그보다는 재조정이라는 용어는&lt;u&gt;&lt;b&gt;&amp;nbsp;비교를 통해 실제 DOM에 바뀐 부분을 적용하는, virtual DOM이 실제 DOM에 적용되는 전반적인 과정을 포괄하는 개념&lt;/b&gt;&lt;/u&gt;이라 보여진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #1f2328; text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-key-prop을-사용하는-이유&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/hyunwlee-dev/interview-study/blob/main/dongryul/virtualDOM.md#key-prop%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;5. key Prop을 사용하는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;virtual DOM을 공부하다보면 자연스레 key Prop을 사용했을 때의 이점도 알게 된다. 요지는, 자식 엘리먼츠들을 &lt;u&gt;&lt;b&gt;key prop을 통해 구분해줌&lt;/b&gt;&lt;/u&gt;으로써, 자식 엘리먼츠 전체를 unmount하여 교체하는 것이 아니라, &lt;u&gt;&lt;b&gt;변경이 생긴 자식 엘리먼츠만 변경사항을 반영하여 렌더링&lt;/b&gt;&lt;/u&gt;할 수 있다는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;key prop을 통해, 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할지 표시해줌으로서 렌더링 효율성을 높일 수 있다.&lt;/li&gt;
&lt;li&gt;해당 key는 오로지 형제 사이에서만 유일하면 되고, 전역에서 유일할 필요는 없다.&lt;/li&gt;
&lt;li&gt;배열의 인덱스를 key로 사용하면, 배열의 요소가 변경되어 인덱스도 변경될 경우 의도치 않은 방식으로 렌더링될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-참고자료&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/hyunwlee-dev/interview-study/blob/main/dongryul/virtualDOM.md#%EC%B0%B8%EA%B3%A0%EC%9E%90%EB%A3%8C&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;참고자료&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://youtu.be/PN_WmsgbQCo?si=C-cYsH-rtqaX3cLE&quot;&gt;[10분 테코톡]   지그의 Virtual DOM&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://youtu.be/gc-kXt0tjTM?si=R-SWPo-JhccOnI2a&quot;&gt;별코딩 - React의 가상돔 (Virtual DOM)이 뭔가요? (짱 쉬움)&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://programming119.tistory.com/240&quot;&gt;[React] 리액트 reconciliation(재조정) 이란? / 리액트 key [개발자 아저씨들 힘을모아:티스토리]&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://ko.legacy.reactjs.org/docs/reconciliation.html&quot;&gt;리액트 레거시 공식문서 '재조정'&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://medium.com/crossplatformkorea/react-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%B2%98%EC%9D%8C%EB%B6%80%ED%84%B0-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90-03-react-%EC%9D%98-reconciliation-%EA%B3%BC%EC%A0%95-2e6fb59c0c2d&quot;&gt;[React] 리액트를 처음부터 배워보자. &amp;mdash; 03. React 의 Update 스케줄링 과정&lt;/a&gt;&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>react</category>
      <category>Reconciliation</category>
      <category>VirtualDom</category>
      <category>가상DOM</category>
      <category>가상돔</category>
      <category>리액트</category>
      <category>재조정</category>
      <category>프론트엔드 면접질문</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/24</guid>
      <comments>https://dr-dev.tistory.com/24#entry24comment</comments>
      <pubDate>Fri, 23 Feb 2024 23:39:02 +0900</pubDate>
    </item>
    <item>
      <title>[React] ref와 useRef 훅</title>
      <link>https://dr-dev.tistory.com/23</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;react-logo.png&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;1042&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4dSfY/btsEWhuRBmJ/tUzCLwCntUXQGOEP7i2qT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4dSfY/btsEWhuRBmJ/tUzCLwCntUXQGOEP7i2qT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4dSfY/btsEWhuRBmJ/tUzCLwCntUXQGOEP7i2qT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4dSfY%2FbtsEWhuRBmJ%2FtUzCLwCntUXQGOEP7i2qT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1834&quot; height=&quot;1042&quot; data-filename=&quot;react-logo.png&quot; data-origin-width=&quot;1834&quot; data-origin-height=&quot;1042&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Ref란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ref는 &lt;b&gt;DOM을 직접적으로 건드려야하는 때&lt;/b&gt; 사용합니다. 순수 js로 컴포넌트를 제어하는 방식으로, ref는 current 프로퍼티를 가진 객체입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. id가 아니라 ref를 사용하는 이유는?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id는 DOM에서 유일해야하는데, React 컴포넌트는 여러번 사용될 수 있기 때문에 id를 사용하는것이 적절하지 않습니다.&lt;br /&gt;반면에, ref는 전역적으로 작동하지 않고 컴포넌트 내부에서만 작동하기 때문입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. ref를 사용하는 방법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. 클래스형 컴포넌트에서 사용하는 방법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React.createRef 메소드를 사용합니다.&lt;/li&gt;
&lt;li&gt;변수명.current로 접근할 수 있습니다.&lt;/li&gt;
&lt;li&gt;React 16.3 버전부터 사용 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class RefSample extends Component {
  input = React.createRef();

  handleFocus = () =&amp;gt; {
    this.input.current.focus();
  }

  render() {
    return (
      &amp;lt;div&amp;gt;
        &amp;lt;input ref={this.input} /&amp;gt;
        &amp;lt;button onClick={() =&amp;gt; this.handleFocus}&amp;gt;
          포커스
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. 함수형 컴포넌트에서 ref를 사용하는 방법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useRef 훅을 사용해야합니다. createRef를 사용할 수는 있지만, 함수 호출에 따라 createRef로 재호출되는 문제가 있습니다. 그렇기에 useRef를 권장합니다.&lt;/li&gt;
&lt;li&gt;마찬가지로, 변수명.current로 접근할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시코드&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useRef } from &quot;react&quot;;

function RefSample() {
  const input = useRef();
  const handleFocus = () =&amp;gt; {
    input.current.focus();
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input ref={input} /&amp;gt;
      &amp;lt;button onClick={handleFocus}&amp;gt;
        포커스
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-3. 콜백함수를 통해 사용하는 방법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;jsx 내 DOM 요소에 ref 프로퍼티 내 콜백 함수를 통해 ref를 전달합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시코드&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;&amp;lt;input 
  ref={(ref) =&amp;gt; this.input = ref}
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 실제 어플리케이션에서 사용하는 예시 (from. legacy 공식 문서)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.&lt;/li&gt;
&lt;li&gt;애니메이션을 직접적으로 실행시킬 때.&lt;/li&gt;
&lt;li&gt;서드 파티 DOM 라이브러리를 React와 같이 사용할 때.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. ref와 state의 차이 비교&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ref&lt;/th&gt;
&lt;th&gt;state&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;useRef(initialValue) =&amp;gt; &lt;code&gt;{ current : initialValue}&lt;/code&gt; 반환&lt;/td&gt;
&lt;td&gt;useState(initialValue) =&amp;gt; &lt;code&gt;[state = initialValue, setState]&lt;/code&gt; 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;변화 시 리렌더링이 일어나지 않는다&lt;/td&gt;
&lt;td&gt;변화할 때마다 리렌더링이 일어난다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mutable - 렌더링 프로세스 외부에서 current 값을 수정하고 업데이트할 수 있음&lt;/td&gt;
&lt;td&gt;Immutable - setState를 통해서 수정해 리렌더링을 대기열에 추가해야함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You shouldn&amp;rsquo;t read (or write) the current value during rendering. 렌더링 중에는 current 값을 읽거나 쓰지 말아야한다.&lt;/td&gt;
&lt;td&gt;You can read state at any time. However, each render has its own snapshot of state which does not change. state를 언제든 읽어올 수 있다. 그러나, 각 렌더링은 변화되지 않은 state을 스냅샷으로 갖고 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비제어컴포넌트&lt;/td&gt;
&lt;td&gt;제어 컴포넌트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. forwardRef&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트에서 부모 컴포넌트가 자식 컴포넌트의 DOM 요소에 접근하고자 할 때 사용하는 메서드이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;forwardRef를 통해 ref를 prop으로 받아서 원하는 element에 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;forwardRef로 자식 컴포넌트를 감싸고 전달하고자 하는 ref를 props 다음 두번째 인자로 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시코드&lt;/p&gt;
&lt;pre class=&quot;verilog&quot;&gt;&lt;code&gt;function App() {
  const ref = useRef(null);

  useEffect(() =&amp;gt; {
    console.log(ref);
  }, [ref]);

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;StyledInput ref={ref} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

const StyledInput = forwardRef((props, ref) =&amp;gt; {
  return &amp;lt;input ref={ref} /&amp;gt;;
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고자료 출처&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://react-ko.dev/learn/referencing-values-with-refs&quot;&gt;리액트 공식문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-05-15-react-ref/&quot;&gt;React ref 톺아보기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1708060395918&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ref로 값 참조하기 &amp;ndash; React&quot; data-og-description=&quot;The library for web and native user interfaces&quot; data-og-host=&quot;react-ko.dev&quot; data-og-source-url=&quot;https://react-ko.dev/learn/referencing-values-with-refs&quot; data-og-url=&quot;https://react-ko.dev/learn/referencing-values-with-refs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cEuyoo/hyVi9AYqZs/JqFUgKCenSGvifvuxcPKH0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/PfRuq/hyVjlBoUpW/uTiBflcGLga7mMtKbJkgh0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567&quot;&gt;&lt;a href=&quot;https://react-ko.dev/learn/referencing-values-with-refs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://react-ko.dev/learn/referencing-values-with-refs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cEuyoo/hyVi9AYqZs/JqFUgKCenSGvifvuxcPKH0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/PfRuq/hyVjlBoUpW/uTiBflcGLga7mMtKbJkgh0/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ref로 값 참조하기 &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The library for web and native user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;react-ko.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1708060392608&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;React ref 톺아보기&quot; data-og-description=&quot;0. Intro React로 웹프론트엔드 개발을 하다보면 React만으로는 DOM을 조작하기 어려울 때가 있습니다. 가장 흔하게는 어떤 엘리먼트를 focus 해야 할 때 말이죠. React의 ref는 무엇이고, ref&amp;hellip;&quot; data-og-host=&quot;tecoble.techcourse.co.kr&quot; data-og-source-url=&quot;https://tecoble.techcourse.co.kr/post/2021-05-15-react-ref/&quot; data-og-url=&quot;https://tecoble.techcourse.co.kr/post/2021-05-15-react-ref/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nBLt6/hyVmQ7BkIJ/SDzKr0RZcg8viAtD1HFX71/img.png?width=1200&amp;amp;height=1015&amp;amp;face=0_0_1200_1015,https://scrap.kakaocdn.net/dn/TZXXv/hyVjfnClO9/F6yhzLdAQ0QKfnF2RHXUb0/img.png?width=1200&amp;amp;height=1015&amp;amp;face=0_0_1200_1015,https://scrap.kakaocdn.net/dn/bJh44z/hyVjiSbNxy/Thrk6w2k1smLFfwx6fzKGK/img.png?width=750&amp;amp;height=480&amp;amp;face=0_0_750_480&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-05-15-react-ref/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tecoble.techcourse.co.kr/post/2021-05-15-react-ref/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nBLt6/hyVmQ7BkIJ/SDzKr0RZcg8viAtD1HFX71/img.png?width=1200&amp;amp;height=1015&amp;amp;face=0_0_1200_1015,https://scrap.kakaocdn.net/dn/TZXXv/hyVjfnClO9/F6yhzLdAQ0QKfnF2RHXUb0/img.png?width=1200&amp;amp;height=1015&amp;amp;face=0_0_1200_1015,https://scrap.kakaocdn.net/dn/bJh44z/hyVjiSbNxy/Thrk6w2k1smLFfwx6fzKGK/img.png?width=750&amp;amp;height=480&amp;amp;face=0_0_750_480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;React ref 톺아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;0. Intro React로 웹프론트엔드 개발을 하다보면 React만으로는 DOM을 조작하기 어려울 때가 있습니다. 가장 흔하게는 어떤 엘리먼트를 focus 해야 할 때 말이죠. React의 ref는 무엇이고, ref&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tecoble.techcourse.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>createRef</category>
      <category>react</category>
      <category>ReactHooks</category>
      <category>Ref</category>
      <category>useref</category>
      <category>리액트</category>
      <category>리액트훅</category>
      <category>클래스형컴포넌트</category>
      <category>프론트엔드</category>
      <category>함수형컴포넌트</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/23</guid>
      <comments>https://dr-dev.tistory.com/23#entry23comment</comments>
      <pubDate>Fri, 16 Feb 2024 14:13:30 +0900</pubDate>
    </item>
    <item>
      <title>[@tanstack/react-query] Query Status와 Fetch Status</title>
      <link>https://dr-dev.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React Query에는 2가지의 Status가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 2가지 Status의 상태와 그것이 가지는 의미를 구분하여 파악해보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Query Status&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 실제로 받아온 data 값이 있는지 없는지를 나타내는 상태값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;확인 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- useQuery의 결과값에서 status 값을 통해 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3가지 종류의 상태 값을 갖는다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1. pending : 데이터를 아직 받아오지 못한 상태일때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2. success : 데이터를 성공적으로 받아왔을 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3. error : 데이터를 받아오는 중에 에러가 발생했을 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Fetch Status&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- queryFn() 함수가 현재 실행되는중인지 아닌지를 나타내는 상태값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3가지 종류의 상태 값을 갖는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 1. fetching : 쿼리 함수가 (재)실행될 때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 2. paused : 쿼리 함수의 실행이 중단되었을때.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3. idle : 데이터를 성공적으로 가져온것과 별개로, 쿼리 함수의 실행이 끝났을때의 상태.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 두 상태의 조합&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Query Status와 Fetch Status는 서로 독립적인 상태이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 'error'이면서 'idle' 상태일 수도 있고, 'pending'이면서 'fetching' 상태 일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 이 두 상태가 가지는 의미를 잘 파악하고 그에 맞는 상황에 필요한 구현을 개발자는 그릴 수 있어야한다.&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>Fetch Status</category>
      <category>Query Status</category>
      <category>react</category>
      <category>react-query</category>
      <category>tanstack-query</category>
      <category>리액트</category>
      <category>리액트쿼리</category>
      <category>서버상태관리</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/22</guid>
      <comments>https://dr-dev.tistory.com/22#entry22comment</comments>
      <pubDate>Mon, 29 Jan 2024 00:09:02 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 이터러블과 이터레이터 프로토콜</title>
      <link>https://dr-dev.tistory.com/21</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GVNhY/btsDKP1LZZY/X13jvj2KysNz65cviRKWMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GVNhY/btsDKP1LZZY/X13jvj2KysNz65cviRKWMK/img.png&quot; data-alt=&quot;출처 : https://poiemaweb.com/es6-iteration-for-of&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GVNhY/btsDKP1LZZY/X13jvj2KysNz65cviRKWMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGVNhY%2FbtsDKP1LZZY%2FX13jvj2KysNz65cviRKWMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;430&quot; height=&quot;192&quot; data-origin-width=&quot;1017&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://poiemaweb.com/es6-iteration-for-of&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;0. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;iteration protocol의 등장 배경&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6 이전에는 순회 가능한 데이터 컬렉션(자료구조)가 명확한 통일된 규약 없이 각자의 구조를 갖고 나름의 방식(for...in문으로 순회한다던지...forEach문으로 순회한다던지...)으로 순회할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 ES6부터는 이 순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하였다. 그리고 이 이터러블이 for...of문, 스프레드 문법, 배열 구조분해할당(destructuring)을 사용할 수 있게 된다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 순회가능한 자료구조(Array, String, Map/Set 등)를 데이터 공급자 라고 하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것을 순회하여 사용하는 방식(스프레드문법, for..of문, 배열 디스트럭처링 할당 등)을 데이터 소비자라고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일 각각의 순회가능한 자료구조가 개별의 순회방식을 가지고 있다면, 데이터 소비자는 각 자료구조에 맞게 일일이 순회구조에 맞게 사용방식을 구현해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 이터레이션 프로토콜로 통일된 데이터 공급방식이 제공된다면 데이터 소비자는 이터레이션 프로토콜에 맞게만 구현해놓으면 어떤 순회가능한 자료구조가 오던지 사용할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 이터레이션 프로토콜은 데이터 소비자가 효율적으로 데이터 공급자를 사용할 수 있도록 &lt;u&gt;&lt;b&gt;그 사이를 연결하는 인터페이스 역할&lt;/b&gt;&lt;/u&gt;을 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;iterable&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-1. iterable의 정의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iterable protocol을 준수한 객체를 iterable 이라고 한다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-2. iterable protocol 이란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Well-Known Symbol*인&lt;u&gt;&lt;b&gt; Symbol.iterator&lt;/b&gt;&lt;/u&gt;를 프로퍼티 키로 사용한 메서드를 직접 구현하거나, 프로토타입 체인을 통해 상속받아 갖고 있으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp; Symbol.iterator 메서드를 호출하면, iterator protocol을 준수한&lt;u&gt;&lt;b&gt; iterator를 반환&lt;/b&gt;&lt;/u&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-3. iterator란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iterator protocol을 준수한 객체를 iterator 이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-4. iterator protocol이란?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;u&gt;&lt;b&gt;next&lt;/b&gt;&lt;/u&gt; 메서드를 소유하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. next 메서드를 호출하면 value와 done property를 갖는 &lt;u&gt;&lt;b&gt;iterator result 객체를 반환&lt;/b&gt;&lt;/u&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 : { value : 2, done: false }&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next메서드를 호출할 때마다 value를 통해 값을 가져오고, 가져올 값이 없으면 done: true를 return한다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Built-In Iterable&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 iteration protocol을 준수하는 기본 이터러블을 제공한다. 이를 빌트인 이터러블이라고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 이터러블은, 당연하게도 Symbol.iterator 메서드를 소유하고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1. Array&lt;br /&gt;2. String&lt;br /&gt;3. Map&lt;br /&gt;4. Set&lt;br /&gt;5. TypedArray*&lt;br /&gt;6. arguments&lt;br /&gt;7. DOM Collection (NodeList, HTMLCollection)*&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;이터러블과 유사배열객체와는 다른 것인가?&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. 유사배열객체란 : 1) 인덱스로 프로퍼티 값에 접근할 수 있고, 2) length 프로퍼티를 갖는 객체 이다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유사배열객체는 for문으로 순회할 수 있으나, 어쨌거나 일반적인 객체이다. 이터러블처럼 Symbol.iterator 메서드를 갖고 있지 않기 때문에 for...of문으로 순회할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. 이터러블이면서 유사배열 객체인 것들&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- arguments, NodeList, HTMLCollection&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6가 되면서 위 객체들이 이터러블이 되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 모든 유사배열객체가 이터러블인 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로, 모든 이터러블이 유사배열객체인것도 아니다. (ex. 배열)&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;각주&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Well-Known Symbol&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;- 자바스크립트가 기본 제공하는 빌트인 심벌값이다. 자바스크립트 엔진의 내부 알고리즘 구현을 위해 사용되는 값이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;TypedArray&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 원시이진데이터를 다루기 위한, 배열처럼 생긴 객체&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NodeList, HTMLCollection&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- DOM API가 결과값을 반환하기 위해 반환하는 유사배열 객체. HTMLCollection은 live 객체이지만 NodeList는 childNodes프로퍼티를 제외하고 Non-live라는 차이가 있다.&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>arraylike</category>
      <category>iterable</category>
      <category>iteration</category>
      <category>Iterator</category>
      <category>javascript</category>
      <category>유사배열객체</category>
      <category>이터러블</category>
      <category>이터레이션</category>
      <category>이터레이터</category>
      <category>자바스크립트</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/21</guid>
      <comments>https://dr-dev.tistory.com/21#entry21comment</comments>
      <pubDate>Thu, 25 Jan 2024 11:28:32 +0900</pubDate>
    </item>
    <item>
      <title>[Monorepo] yarn workspace 모노레포 내의 컴포넌트가 import 되지 않을 때 해결법 (@babel/runtime, yarn berry와 npm의 차이)</title>
      <link>https://dr-dev.tistory.com/20</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[Monorepo] yarn workspace 모노레포 환경 내의 컴포넌트가 다른 패키지에서 import 되지 않을 때 해결법 (@babel/runtime)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 문제 상황&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pIGAT/btsDJUmxZ3Q/5lrcs4LHYfmNK4MGxRvlB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pIGAT/btsDJUmxZ3Q/5lrcs4LHYfmNK4MGxRvlB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pIGAT/btsDJUmxZ3Q/5lrcs4LHYfmNK4MGxRvlB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpIGAT%2FbtsDJUmxZ3Q%2F5lrcs4LHYfmNK4MGxRvlB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;430&quot; height=&quot;353&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 시작하면서 yarn berry workspace를 통해 모노레포 환경을 구축하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림과 같이 프로젝트의 주요 목표가 될 '서비스 어플리케이션'들끼리 공통적으로 사용할 컴포넌트들을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package 폴더 안에 '공통 컴포넌트 패키지'로 만들어 컴포넌트 재사용성을 높이고자 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705568627367&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Cannot find module babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 다음과 같은 메시지를 뱉으며 불러오지 못하는 문제를 겪었다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 원인 진단&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 레포지토리의 컴포넌트를 import 한 것이 아니라 모노레포 였음에도 불구하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트를 불러오지 못한 이유가 무엇일지 궁금했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 문제가 될만한 요소들을 확인하였다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. 컴포넌트 패키지에서 export를 누락한 것이 없는지 확인한다.&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 컴포넌트 패키지에서 export되길 원하는 컴포넌트들을 잘 export 했는지 확인하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컴포넌트들을 index.tsx로 묶어서 전체 컴포넌트들을 default로 내보냈다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705572429527&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export { default as Avatar } from './Avatar';
export { default as Button } from './Button';
export { default as Form} from './Form';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈 export 상의 누락 문제는 없는 것으로 확인되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. 필요한 의존성 항목이 없는 것인지 확인한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'@babel/runtime' 의존성 항목이 서비스 어플리케이션에서 필요한 것으로 판단되었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그렇다면 @babel/runtime은 무엇인가?&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@babel/runtime은 바벨의 런타임 라이브러리로서, 프로그램이 실행되는 동안에 필요한 함수들을 지원한다. 이를테면 es6에서 도입된 클래스를 es5이전 환경에서 구동할 수 있게끔 변환해주는 함수 등이 @babel/runtime에 포함되어있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플러그인으로서 추가하여 사용하게 되면 @babel/plugin-transform-runtime과 동일하다고 볼 수 있다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;그렇다면 왜 컴포넌트 패키지에서는 잘 트랜스파일링 되는데, 서비스 어플리케이션 환경에서는 트랜스파일링되지 않는 것인가?&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것은 바로 yarn berry의 특성 때문이다. yarn berry는 필요한 의존성 패키지를 탐색할 때 node_modules와는 다른 방식으로 탐색한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xoQGN/btsDGp2t3Zj/MU8M890YkQnkZcudtYK4q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xoQGN/btsDGp2t3Zj/MU8M890YkQnkZcudtYK4q0/img.png&quot; data-alt=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xoQGN/btsDGp2t3Zj/MU8M890YkQnkZcudtYK4q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxoQGN%2FbtsDGp2t3Zj%2FMU8M890YkQnkZcudtYK4q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;458&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm은 하위 패키지와 상위 패키지가 의존성이 겹치게 될 때 오른쪽과 같이 의존성 트리를 변경하고 하위 패키지가 상위 패키지로 거슬러올라와 해당 의존성을 참조하게끔 한다. 하위의 의존성이 끌어올려지는 듯하여 이를 호이스팅된다고도 한다. (자바스크립트의 호이스팅과는 다름)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식은 중복되는 의존성을 제거하고 메모리 용량을 save할 수 있다는 장점이 있다.&amp;nbsp;그렇지만 의존성 관리를 햇갈리게 하고 의존성 사양에 변경이 발생하면 에러 가능성이 있다. (유령 의존성 문제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx4aqG/btsDFVgzuuZ/XbEzuUSN1Oj93ushqaFXS0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx4aqG/btsDFVgzuuZ/XbEzuUSN1Oj93ushqaFXS0/img.jpg&quot; data-alt=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx4aqG/btsDFVgzuuZ/XbEzuUSN1Oj93ushqaFXS0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx4aqG%2FbtsDFVgzuuZ%2FXbEzuUSN1Oj93ushqaFXS0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1087&quot; height=&quot;533&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yarn berry도 중복된 의존성 설치를 하진 않지만 symlink를 통해 의존성 package를 개별적으로 관리하는 덕에 각각의 패키지가 독립적인 의존성을 유지할 수 있게 해준다. 한마디로 호이스트되어 찾는 방식이 아니게 된거다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 본론으로 돌아가자면, nohoist가 활성화된 yarn berry의 특성으로 인해 추가하지 않은 종속성에 대해 임의로 탐색하지 않아 런타임 환경에서 실행 시 서비스 어플리케이션에서 공통 컴포넌트 패키지의 컴포넌트를 불러오지 못한 것이라는 원인 진단을 내릴 수 있었다. 공식문서(하단 참조 링크 참고)에서도 Module not found 에러가 발생할 수 있으며 이것이 (구조적으로) 고쳐질 수 없는 것임을 설명하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-5971732715732610&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 해결방법&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. 루트 디렉토리에 @babel/runtime을 설치한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모노레포 루트에 있는 package.json에 '@babel/runtime'을 의존성 항목에 추가하였다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1705572621611&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add @babel/runtime&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과, 컴포넌트가 서비스 어플리케이션에서 정상적으로 import 될 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 향후 개발단계에서 비슷한 이유로 트랜스파일링 과정에서의 문제 발생이 우려된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이를 선제적으로 대비하기 위해서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;개별 패키지/어플리케이션 내부로 들어가서 빠진 종속성 항목이 있는지, .babelrc에서 추가할 속성이 있는지 살펴보고 좀 더 넓은 커버리지를 갖고 있는 @babel/preset을 추가하는거나 필요할 것으로 예상되는 플러그인을 설치하는 것이 더 좋을 것 같다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고한 글&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://babeljs.io/docs/babel-runtime&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://babeljs.io/docs/babel-runtime&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705574884884&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;@babel/runtime &amp;middot; Babel&quot; data-og-description=&quot;@babel/runtime is a library that contains Babel modular runtime helpers.&quot; data-og-host=&quot;babeljs.io&quot; data-og-source-url=&quot;https://babeljs.io/docs/babel-runtime&quot; data-og-url=&quot;https://babeljs.io/docs/babel-runtime&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://babeljs.io/docs/babel-runtime&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://babeljs.io/docs/babel-runtime&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;@babel/runtime &amp;middot; Babel&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;@babel/runtime is a library that contains Babel modular runtime helpers.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;babeljs.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/7976/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://techblog.woowahan.com/7976/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705568715140&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Yarn berry workspace를 활용한 프론트엔드 모노레포 구축기 | 우아한형제들 기술블로그&quot; data-og-description=&quot;{{item.name}} 안녕하세요 우아한형제들 딜리버리프로덕트실 DH로컬라이징스쿼드 입니다. 저희 조직에서는 백오피스 애플리케이션, 크로스플랫폼 모바일 애플리케이션 등 다양한 프론트엔드 프로&quot; data-og-host=&quot;techblog.woowahan.com&quot; data-og-source-url=&quot;https://techblog.woowahan.com/7976/&quot; data-og-url=&quot;https://techblog.woowahan.com/7976/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RdNwO/hyU819iTlu/8uJ3XGliESTHAIscbXkveK/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/bDkwJf/hyU5LUBfQz/zrp4Bj2G1FRF6kTooBZxkk/img.png?width=351&amp;amp;height=600&amp;amp;face=0_0_351_600&quot;&gt;&lt;a href=&quot;https://techblog.woowahan.com/7976/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://techblog.woowahan.com/7976/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RdNwO/hyU819iTlu/8uJ3XGliESTHAIscbXkveK/img.jpg?width=1640&amp;amp;height=856&amp;amp;face=0_0_1640_856,https://scrap.kakaocdn.net/dn/bDkwJf/hyU5LUBfQz/zrp4Bj2G1FRF6kTooBZxkk/img.png?width=351&amp;amp;height=600&amp;amp;face=0_0_351_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Yarn berry workspace를 활용한 프론트엔드 모노레포 구축기 | 우아한형제들 기술블로그&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;{{item.name}} 안녕하세요 우아한형제들 딜리버리프로덕트실 DH로컬라이징스쿼드 입니다. 저희 조직에서는 백오피스 애플리케이션, 크로스플랫폼 모바일 애플리케이션 등 다양한 프론트엔드 프로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;techblog.woowahan.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/facebook/create-react-app/issues/7183&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/facebook/create-react-app/issues/7183&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1705568729553&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Cannot find module babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray &amp;middot; Issue #7183 &amp;middot; facebook/create-re&quot; data-og-description=&quot;Error Message on the terminal: Cannot find module '/Users/pehhuishi/code/react/practice/react-practice/node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray Not sure...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/facebook/create-react-app/issues/7183&quot; data-og-url=&quot;https://github.com/facebook/create-react-app/issues/7183&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAZXCB/hyU5UqtwlM/1tnO07mlf8eKdKhzvE5srk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/facebook/create-react-app/issues/7183&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/facebook/create-react-app/issues/7183&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAZXCB/hyU5UqtwlM/1tnO07mlf8eKdKhzvE5srk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cannot find module babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray &amp;middot; Issue #7183 &amp;middot; facebook/create-re&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Error Message on the terminal: Cannot find module '/Users/pehhuishi/code/react/practice/react-practice/node_modules/babel-preset-react-app/node_modules/@babel/runtime/helpers/slicedToArray Not sure...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot;&gt;https://toss.tech/article/node-modules-and-yarn-berry&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705580431313&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;node_modules로부터 우리를 구원해 줄 Yarn Berry&quot; data-og-description=&quot;토스 프론트엔드 레포지토리 대부분에서 사용하고 있는 패키지 매니저 Yarn Berry. 채택하게 된 배경과 사용하면서 좋았던 점을 공유합니다.&quot; data-og-host=&quot;toss.tech&quot; data-og-source-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; data-og-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UXwe4/hyU8W7XZru/kK1VHoz4TznnIqQdqTkvvk/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/DNQL1/hyU8ZXUXex/nkoRjVJxUInTFXbx47o9kK/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/dZNXE8/hyU83zfhti/InvYVphKHiVAuHcIkuD3lk/img.png?width=1500&amp;amp;height=1500&amp;amp;face=0_0_1500_1500&quot;&gt;&lt;a href=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://toss.tech/article/node-modules-and-yarn-berry&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UXwe4/hyU8W7XZru/kK1VHoz4TznnIqQdqTkvvk/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/DNQL1/hyU8ZXUXex/nkoRjVJxUInTFXbx47o9kK/img.png?width=4802&amp;amp;height=2514&amp;amp;face=0_0_4802_2514,https://scrap.kakaocdn.net/dn/dZNXE8/hyU83zfhti/InvYVphKHiVAuHcIkuD3lk/img.png?width=1500&amp;amp;height=1500&amp;amp;face=0_0_1500_1500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;node_modules로부터 우리를 구원해 줄 Yarn Berry&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;토스 프론트엔드 레포지토리 대부분에서 사용하고 있는 패키지 매니저 Yarn Berry. 채택하게 된 배경과 사용하면서 좋았던 점을 공유합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;toss.tech&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1705653722421&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;nohoist in Workspaces&quot; data-og-description=&quot;As wonderful as yarn workspaces are, the rest of the community hasn&amp;rsquo;t yet fully caught up with the monorepo hoisting scheme. The introducing of the nohoist i...&quot; data-og-host=&quot;classic.yarnpkg.com&quot; data-og-source-url=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot; data-og-url=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://classic.yarnpkg.com/blog/2018/02/15/nohoist/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;nohoist in Workspaces&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;As wonderful as yarn workspaces are, the rest of the community hasn&amp;rsquo;t yet fully caught up with the monorepo hoisting scheme. The introducing of the nohoist i...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;classic.yarnpkg.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend</category>
      <category>@babel/runtime</category>
      <category>Cannot find module</category>
      <category>node_modules</category>
      <category>nohoist</category>
      <category>react</category>
      <category>yarn</category>
      <category>yarn berry</category>
      <category>yarn berry workspace</category>
      <category>모노레포</category>
      <category>컴포넌트 import</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/20</guid>
      <comments>https://dr-dev.tistory.com/20#entry20comment</comments>
      <pubDate>Fri, 19 Jan 2024 18:06:00 +0900</pubDate>
    </item>
    <item>
      <title>[CS] REST API의 Code On Demand 원칙이 필수가 아닌 이유는 무엇일까?</title>
      <link>https://dr-dev.tistory.com/19</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3334&quot; data-origin-height=&quot;1311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgFdMd/btsDmpB5h65/NxJov2ZwaNbx9XULAqcixK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgFdMd/btsDmpB5h65/NxJov2ZwaNbx9XULAqcixK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgFdMd/btsDmpB5h65/NxJov2ZwaNbx9XULAqcixK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgFdMd%2FbtsDmpB5h65%2FNxJov2ZwaNbx9XULAqcixK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3334&quot; height=&quot;1311&quot; data-origin-width=&quot;3334&quot; data-origin-height=&quot;1311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&quot;rest-api-6원칙-중-유일한-optional-code-on-demand&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;REST API 6원칙 중 유일한 Optional, Code on Demand&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;REST API에는 6가지 원칙이 있다.&lt;br /&gt;그중에서 유일하게 optional 한 원칙이며, 현재는 잘 사용되지 않는 녀석이 있는데, 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;code on demand&lt;span&gt;&amp;nbsp;&lt;/span&gt;원칙이다.&lt;/p&gt;
&lt;h2 id=&quot;code-on-demand-원칙이란&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Code on Demand 원칙이란&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Code-on-demand 원칙이란 RESTful 웹 서비스에서 서버가 클라이언트에게 실행 가능한 코드를 다운로드하여 실행할 수 있는 기능을 제공하는 것을 의미한다. 이 기능은 시스템에 유연성과 확장성을 제공할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;흔히들 자바애플릿으로 코드를 그대로 받아 실행하는 경우를 예시로 많이 든다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트로 따지면 코드를 문자열로 받아 실행하는 eval의 경우가 Code on Demand로 설계된 API를 활용할 때 사용될 수 있을 것이다.&lt;/p&gt;
&lt;h2 id=&quot;code-on-demand가-잘-지켜지지-않는-이유&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Code on Demand가 잘 지켜지지 않는 이유&lt;/h2&gt;
&lt;h3 id=&quot;1-보안-문제&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 보안 문제&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 큰 이유로써, 서버에서 실행 가능한 코드를 클라이언트로 전송하는 것은 보안 문제를 야기할 수 있다는 점이다. 클라이언트 측에서 실행되는 코드는 서버 측의 컨트롤을 벗어나기 때문에 악용될 수 있는 위험이 존재한다. 따라서, 상당수의 서비스가 보안을 위해 code-on-demand 기능을 비활성화한다.&lt;/p&gt;
&lt;h3 id=&quot;2-호환성의-문제&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 호환성의 문제&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에서 생성된 코드가 클라이언트 플랫폼에 따라 호환되지 않을 수 있다는 문제가 있다. RESTful 웹 서비스는 다양한 클라이언트와 상호 작용해야 하는데, 서버 측에서 실행 가능한 코드가 만일 특정 플랫폼에 종속되게 된다면 해당 API의 활용도가 떨어지게 될 것이다. 그래서 요즘 Code-on-demand 원칙으로 직접 실행가능한 코드를 클라이언트 측에서 실행하는 대신, 서버로부터 반환되는 데이터를 기반으로 클라이언트 애플리케이션에서 필요한 로직을 직접 구현하는 방식을 선호한다.&lt;/p&gt;
&lt;h3 id=&quot;3-성능-이슈&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 성능 이슈&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RESTful 웹 서비스는 캐싱을 활용하여 성능을 향상시키는 것이 중요하다. 하지만 코드 on demand를 지원하면 서버에서 반환되는 코드는 동적이므로 클라이언트에서 캐싱이 어렵다. 클라이언트 측에서 실행 가능한 코드가 자주 변경된다면 캐싱을 적용하기 어렵고, 매번 코드를 다운로드해야 하므로 성능에도 영향을 미칠 수 있다. 점점 하나의 서비스에서 다루는 데이터의 크기가 커지면서 캐싱의 중요성이 더욱 부각되는 최근의 트렌드와 견주어보면, code-on-demand의 편의성은 아무래도 후순위가 될 수 밖에 없다.&lt;/p&gt;
&lt;h3 id=&quot;4-코드-유지보수의-복잡성-증가&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 코드 유지보수의 복잡성 증가&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;code-on-demand를 사용하면 클라이언트 애플리케이션의 복잡성이 증가할 수 있다는 어려움이 있다. 클라이언트에게 서버에서 실행 가능한 코드를 다운로드하고 관리하는 추가적인 작업이 필요하기 때문이다. 특히, 다양한 플랫폼에서 동작하는 클라이언트 애플리케이션을 개발해야 하는 경우 code-on-demand를 구현하고 유지 보수하는데 있어서 어려움을 초래할 수 있고, 점점 복잡해지고 있는 클라이언트 단의 개발환경을 고려한다면 code-on-demand 사용은 '굳이?' 라는 생각이 들게 한다.&lt;/p&gt;
&lt;h2 id=&quot;번외-code-on-demand-원칙의-등장에-대한-이해&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;번외) Code-on-demand 원칙의 등장에 대한 이해&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 살펴본 이유로, 사실상 code-on-demand 원칙은 REST API를 만들 때 요즘 거의 사용되고 있지 않다. 그렇다면 어쩌다 이러한 원칙이 끼어들게 된거지? 하는 궁금증이 든다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 궁금증에 대한 해답을 찾기 위해서는 로이 필딩이 REST 원칙에 대해 논문을 내던 시절을 살펴보면 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;당시에는 웹이란 대부분 정적 document들이었고,&amp;nbsp; 클라이언트 라는 것도 브라우저 그 자체였던 시절이다. 과거에는 클라이언트 단에서 필요한 로직을 구현하기에 충분하지 않았던 환경이었기 때문에 그랬던 건가 싶다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현재는 자바스크립트가 동적으로 데이터를 받아오는 영역이 더 커졌기 때문에 지금은 필요성을 많이 떨어졌다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;gt; 위 글은 Velog에서 작성했던 글을 이관 해오면서 일부 수정 및 개정한 글입니다.&lt;/p&gt;</description>
      <category>Computer Science</category>
      <category>codeondemand</category>
      <category>ComputerScience</category>
      <category>CS지식</category>
      <category>restapi</category>
      <category>restfulapi</category>
      <category>REST원칙</category>
      <category>RoyFielding</category>
      <category>코드온디맨드</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/19</guid>
      <comments>https://dr-dev.tistory.com/19#entry19comment</comments>
      <pubDate>Fri, 12 Jan 2024 16:22:53 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] '타입스크립트가 정적 트랜스파일링 언어이다' 라는 것의 의미</title>
      <link>https://dr-dev.tistory.com/18</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 프론트엔드 개발자 공고에서 빠지지 않는 것 중 하나는 바로 Typescript 활용 능력이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;'Typescript가 타입을 지정하고 큰 프로젝트에서는 안정성이 좋다' 이런 얘기들은 많이 들어봤지만 구체적으로 어떤 특징을 갖고, 왜 협업과 큰 프로젝트에서 좋은지 javascript와 비교해보면서 구체적으로 살펴보고자 한다.&lt;/p&gt;
&lt;h2 id=&quot;정적-타입-언어-vs-동적-타입-언어&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;정적 타입 언어 vs 동적 타입 언어&lt;/h2&gt;
&lt;h3 id=&quot;typescript는-정적-타입-언어이다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Typescript는 정적 타입 언어이다.&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Typescript는 정적 타입 언어이다. 정적이다는 영어로, static이며 동적(dynamic) 이라는 단어와 반대되는 뜻이다. 한마디로 움직이지 않고 정해져있다는 뜻인데, 그렇다면 타입이 정적이다는 무슨 뜻이고 동적이다는 무슨 뜻인걸까?&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;function sum ( a: number, b: number) {
	const total = a + b
    return total
}

sum (3, 5); // 8
sum ('Hello', ' World'); // 'error!' &lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 코드에서처럼 타입스크립트는 함수의 각 인자를 딱 '지정'하여 number, 숫자타입으로 정해져있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;숫자타입인 a, b 두 인자를 더 했으니 자연스레 return 되는 total 이라는 변수도 숫자 타입으로 정해지게 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아래 호출 단계에서와 같이 인자를 숫자로 잘 넣은 첫 번째 함수는 실행이 잘 되지만,&lt;br /&gt;문자열 타입을 넣은 두 번째 경우는 에러를 표시하게 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍이란, 데이터를 다루는 것이다.&lt;br /&gt;위와 같은 예시를 통해 알 수 있는 것은, 타입스크립트는 함수나 변수 등에 명확하게 타입을 지정함으로써 예기치 못한 데이터의 변형을 막을 수 있다. (한마디로, 통제 가능하게끔 한 것이다. )&lt;/p&gt;
&lt;h2 id=&quot;javascript는-동적-타입-언어이다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Javascript는 동적 타입 언어이다.&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Javascript는 반대로 동적언어인데, 실행하는 단계에서 타입 분석을 진행한다.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;function sum ( a, b ) {
	const total = a + b
    return total
}

sum (3, 5); // 8
sum ('Hello', ' World'); // 'Hello World' &lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞의 sum 함수 예시를 그대로 가져왔다.&lt;br /&gt;자바스크립트는 a, b 인자의 타입을 호출할 때마다 동적으로 분석한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 호출에서는 인자로 숫자를 넣었고,&lt;br /&gt;두 번째 호출에서는 문자열 두 개를 인자에 넣었다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두 호출 모두 문제없이 각 인자의 타입을 동적으로 분석하여 결과를 반환한다.&lt;br /&gt;이처럼, 동적으로 타입을 분석할 수 있는 유연성이 자바스크립트의 단점이자 장점이기도 하다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;컴파일-언어-vs-인터프리터-언어&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;컴파일 언어 vs 인터프리터 언어&lt;/h2&gt;
&lt;h3 id=&quot;컴파일-언어란&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;컴파일 언어란?&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컴파일 언어란, 컴파일러를 통해 (1) 기계어로 번역하고, (2) 번역한 전체를 한번에 실행하는 2단계로 나눠 실행되는 언어이다.&lt;br /&gt;컴파일 언어는 (1) 기계어로 번역되는 단계에선 시간이 소요되지만, (1)의 단계가 끝났다면 (2)의 단계인 실행은 상대적으로 빠르게 된다.&lt;br /&gt;컴파일러는 (1)의 단계를 수행해주는 프로그램이라고 할 수 있다. Typescript는&lt;span&gt;&amp;nbsp;&lt;/span&gt;tsc&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 타입스크립트 전용 컴파일러를 통해 분석하고 자바스크립트 코드로 변환하여 실행한다는 점에서 컴파일 언어의 컨셉을 차용하고 있다고 보면 된다.&lt;/p&gt;
&lt;h4 id=&quot;다만-타입스크립트는-일반적인-다른-컴파일-언어와는-다르다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;다만, 타입스크립트는 일반적인 다른 컴파일 언어와는 다르다.&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반적인 컴파일 언어가 컴파일러를 통해 기계어로 작성된 프로그램 파일로 변환되지만, 타입스크립트는 결과적으로 실행가능한 자바스크립트 파일로 변환된다. (자바스크립트의 슈퍼셋이며, 자바스크립트와 100% 호환되는 것도 이 이유다.)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게, 소스코드를 비슷한 추상화 수준의 다른 언어로 변환하는 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;Transpiling&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라고 한다. 그렇기 때문에 타입스크립트는 특수한 컴파일 언어라고 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;혹자는 컴파일과 트랜스파일이 완전히 다른 것이며 구분되어야한다고들 하는데, 엄밀히 말하면 컴파일은 A라는 언어를 B언어로 변환시켜준다는 대개념이며, 그 안에 비슷한 수준의 추상화 언어로 변환한다는 트랜스파일이라는 소개념이 있다고 이해하면 좋겠다. (&lt;s&gt;트랜스파일이 컴파일과 완전히 다른 것이라면, tsc라는 이름은 애시당초 말이 안되는 이름이다.&lt;/s&gt;)&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컴파일, 트랜스파일, 컴파일 언어, 컴파일러 라는 각 개념들의 차이를 잘 이해해야 안 햇갈릴 듯 하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Y51M/btsDfMclWt4/ErncbKSUCzvWd1vKw2ct61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Y51M/btsDfMclWt4/ErncbKSUCzvWd1vKw2ct61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Y51M/btsDfMclWt4/ErncbKSUCzvWd1vKw2ct61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Y51M%2FbtsDfMclWt4%2FErncbKSUCzvWd1vKw2ct61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;373&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 이미지는 타입스크립트가 컴파일 하는 과정이다. 크게 타입 체크와 js 파일로의 변환하는 두 가지 단계의 과정이 있다. 자세한 컴파일 과정은 기회가 되면 따로 소개하도록 하겠다.&lt;/p&gt;
&lt;h3 id=&quot;javascript는-인터프리터-언어이다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Javascript는 인터프리터 언어이다.&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인터프리터 언어는 한 줄씩 기계어로의 번역과 실행을 동시에 진행하는 언어이다.&lt;br /&gt;컴파일 언어와 다르게 소스코드 해석(기계어로의 번역)과 실행이 동시에 이뤄지기 때문에&lt;br /&gt;실행단계에 들어가는 것은 당연히 컴파일 언어보다 빠르지만, 실행을 마치는 데에는 컴파일 언어보다 속도가 느리다. 오류가 발생하면 실행단계에서 중지된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 또한 인터프리터 언어이기 때문에 타입 에러 등을 미리 포착하지 못하고 실행단계에서나 알 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;장점과-단점&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;장점과 단점&lt;/h2&gt;
&lt;h3 id=&quot;typescript를-쓰면-좋은-경우&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Typescript를 쓰면 좋은 경우&lt;/h3&gt;
&lt;h4 id=&quot;1-안정적인-프로그램-구동이-필요하다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1. 안정적인 프로그램 구동이 필요하다.&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실행단계에서 오류가 발생하는 자바스크립트와 달리, 타입스크립트는 어쨌든 실행 전에 타입 검사를 통해 에러를 미리 포착해낼 수 있다. JSDoc은 주석을 통해 타입을 명시할 수는 있지만 타입스크립트처럼 컴파일 단계에서 검사하는 것이 아니기 때문에 한계가 있다.&lt;/p&gt;
&lt;h4 id=&quot;2-많은-사람들과-협업을-해야한다&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2. 많은 사람들과 협업을 해야한다.&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;interface와 type alias는 비단 객체와 변수에 타입을 지정하여 안정성을 확보하는 것 뿐만 아니라, 전체적인 구조를 보여준다는 점에서 코드를 추상화할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코드 작성자의 의도를 빠르게 파악하고 리뷰할 수 있다는 점에서 이러한 장점은 많은 사람들과 협업을 할 때 더욱 효과적이다.&lt;/p&gt;
&lt;h3 id=&quot;javascript를-쓰면-좋은-경우&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Javascript를 쓰면 좋은 경우&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최근에는 Typescript의 사용자가 늘고 장점이 부각되면서 자바스크립트 사용이 아마추어들의 전유물인 양 죄악처럼 여겨지는 듯하다.&lt;br /&gt;그렇지만 분명, 자바스크립트를 사용하는 경우가 더 좋은 상황이 있을 수 있다.&lt;/p&gt;
&lt;h4 id=&quot;빠르게-시작하기&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;빠르게 시작하기&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;당장 빠르게 mvp/프로토타입 어플리케이션을 구현해야하는가?&lt;br /&gt;그런데 tsconfig 설정과 fetch 데이터에 대한 타입 지정에 골머리를 앓고 있는가?&lt;br /&gt;그렇다면 자바스크립트로 빠르게 구현하는 것에 초점을 맞추는 것이 더&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이것은 프로그래밍적 관점을 너머, 비즈니스적 관점에서까지 고려한 이야기이다.&lt;br /&gt;개발에 들이는 시간 하루하루도 다 리소스고 기회비용이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;완벽한 타입과 안정성보다는 때로는 빠르게 유저 반응을 확인하고, 기능을 추가하는 것이 그 어플리케이션의 비즈니스적 가치를 높이는 데 기여하는 것일 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;마치며&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개인적인 생각으로, 타입스크립트를 사용하는 방법 자체는 마음 잡고 정리하면 하루면 충분히 익힐 수 있다고 생각한다. 그렇지만 타입스크립트의 특징과 작동방식, 등장 배경을 알지 못한다면 진정으로 타입스크립트 사용 시의 장점과 편의를 온전히 누리기엔 어렵다고 본다. 타입스크립트라는 언어 자체가 자바스크립트 언어를 사용하면서 생긴 문제를 해결하기 위해 등장하였기 때문이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어떤 문제를 해결한 결과물을 온전히 감사하며 잘 쓰는 것도 중요하지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;그 해결책이 나오기까지의 과정과 문제 의식을 잘 이해해야한다&lt;/b&gt;.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래야만 우리 자신도 또다른 문제를 풀어낼 수 있는 힘을 기르고, 실제로 문제를 해결하며, 그 문제를 겪고 있는 다른 누군가에게 선물과 같은 해결책을 선사할 수 있을 것이다.&lt;/p&gt;
&lt;h3 id=&quot;참고자료&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;참고자료&lt;/h3&gt;
&lt;blockquote style=&quot;color: #212529; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://www.huy.rocks/everyday/04-01-2022-typescript-how-the-compiler-compiles&quot;&gt;TypeScript / How the compiler compiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://youtu.be/X8k_4tZ16qU?feature=shared&quot;&gt;How the TypeScript Compiler Compiles - understanding the compiler internal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://inpa.tistory.com/entry/CS-%F0%9F%96%A5%EF%B8%8F-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%ED%8A%B8%EB%9E%9C%EC%8A%A4%ED%8C%8C%EC%9D%BC-%EC%9D%B8%ED%84%B0%ED%94%84%EB%A6%AC%ED%84%B0-%EB%B9%84%EA%B5%90-%EC%89%BD%EA%B2%8C-%EC%84%A4%EB%AA%85&quot;&gt;컴파일 / 트랜스파일 / 인터프리터 비교 쉽게 설명&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;</description>
      <category>Frontend</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>superset</category>
      <category>typescript</category>
      <category>자바스크립트</category>
      <category>정적트랜스파일링언어</category>
      <category>타입스크립트</category>
      <category>프론트엔드면접질문</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/18</guid>
      <comments>https://dr-dev.tistory.com/18#entry18comment</comments>
      <pubDate>Wed, 10 Jan 2024 11:42:37 +0900</pubDate>
    </item>
    <item>
      <title>[javascript] 배열에서 특정 인덱스를 삭제하고 새로운 배열을 만드는법</title>
      <link>https://dr-dev.tistory.com/17</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;방법 1&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702558787917&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;]
const i = 2;
const ileft = arr.slice(0, i)
const iright = arr.slice(i+1);
const newArr = ileft.concat(iright);
console.log(ileft)
console.log(iright)
console.log(newArr)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 2&lt;/p&gt;
&lt;pre id=&quot;code_1702558864831&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;]
const i = 2;

const newArr = [...arr]
newArr.splice(i, 1);

console.log(newArr);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Frontend</category>
      <author>drk_4</author>
      <guid isPermaLink="true">https://dr-dev.tistory.com/17</guid>
      <comments>https://dr-dev.tistory.com/17#entry17comment</comments>
      <pubDate>Thu, 14 Dec 2023 22:01:13 +0900</pubDate>
    </item>
  </channel>
</rss>