<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Song's DLog</title>
        <link>https://velog.io/</link>
        <description>하이 이것은 나의 깨지고 부서지는 기록들입니다</description>
        <lastBuildDate>Tue, 11 Feb 2025 15:03:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Song's DLog</title>
            <url>https://velog.velcdn.com/images/falling_star3/profile/99b286bc-39fc-4bbe-a8d3-b4cc3a51fecc/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Song's DLog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/falling_star3" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Data Structure]이진트리(Binary Tree)란? (이해와 활용)]]></title>
            <link>https://velog.io/@falling_star3/Data-Structure%EC%9D%B4%EC%A7%84%ED%8A%B8%EB%A6%ACBinary-Tree%EB%9E%80-%EC%9D%B4%ED%95%B4%EC%99%80-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@falling_star3/Data-Structure%EC%9D%B4%EC%A7%84%ED%8A%B8%EB%A6%ACBinary-Tree%EB%9E%80-%EC%9D%B4%ED%95%B4%EC%99%80-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Tue, 11 Feb 2025 15:03:29 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-이진트리binary-tree의-개념과-이해">📌 이진트리(Binary Tree)의 개념과 이해</h2>
<br>

<h3 id="1-이진트리binary-tree란">1. 이진트리(Binary Tree)란?</h3>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/2fee1b5f-b9c4-438b-9ecb-d04edfcde6a4/image.png" alt=""></p>
<blockquote>
<p><strong>트리의 종류 중 하나로 모든 노드의 자식 노드가 최대 2개인 트리를 의미한다.
포화 이진 트리 (Full Binary Tree), 완전 이진 트리 (Complete Binary Tree) 등의 종류가 있다.</strong></p>
</blockquote>
<br>
<br>

<h3 id="2-이진트리의-목적">2. 이진트리의 목적</h3>
<blockquote>
<p><strong>이진 트리는 탐색 및 효율적인 검색, 삽입, 삭제가 필요할 때 유용하다.
이진 트리 탐색의 시간 복잡도는 평균적으로 O(log n)이기 때문이다.
(트리가 한쪽으로 치우치면 시간 복잡도는 O(n)이 될 수 있다.)</strong></p>
</blockquote>
<p>✅ <strong>효율적인 탐색과 정렬</strong>
이진 탐색 트리(BST)를 활용하면 평균적인 탐색, 삽입, 삭제 연산이 O(logn)으로 매우 빠름. 이진 힙(Binary Heap)을 활용하면 정렬 및 우선순위 관리가 쉬움.</p>
<br>

<p>✅ <strong>메모리 효율적인 구조</strong>
배열이나 리스트보다 메모리를 절약하면서 동적 크기 조정이 가능.
트리 구조는 연결 리스트처럼 필요할 때만 메모리를 사용함.</p>
<br>

<p>✅ <strong>재귀적 구조로 문제 해결 가능</strong>
트리는 자연스럽게 재귀를 활용할 수 있어 많은 알고리즘 설계에 유리함.</p>
<br>
<br>

<h3 id="3-이진트리의-이해-✨">3. 이진트리의 이해 ✨</h3>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/f5b3d717-9914-4421-8423-60ce5305f396/image.png" alt=""></p>
<p>이진트리가 왜 검색에 빠르다는 걸까?
이진트리를 이해하지 못하면 이진트리의 목적과 활용을 이해할 수 없다.</p>
<br>

<p>간단한 예시를 들어보겠다.</p>
<p>누군가 당신에게 물어본다.</p>
<pre><code>???: 1~100사이에서 내가 생각한 숫자 한가지를 맞춰봐라. 
     숫자를 말하면 나는 Up 또는 Down을 알려주겠다.
나: 50
???: 다운
나: 25
???: 다운
나: 12</code></pre><p>당신은 첫번째로 무슨 숫자를 부를 것인가?
나는 딱 절반인 50을 부르겠다.
그 이후에도 절반을 부르겠다.
이렇게 범위를 좁혀나가는 것이다.</p>
<p>이것이 바로 이진탐색 트리를 이해하는 첫번째이다.</p>
<p>이제 이진트리를 이해하기 위해 배열을 이진탐색트리로 구현하는 예시를 살펴보자.</p>
<br>

<h4 id="▶-배열을-이진탐색-트리로-만드는-예제-🐭">▶ 배열을 이진탐색 트리로 만드는 예제 🐭</h4>
<p>① 배열 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 가 있다.
② &#39;2&#39;는 어디(인덱스)있는가?
③ 이진 검색 트리로 찾아보자.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/9db71f3b-db4d-41cf-aba6-04b7ba0b1825/image.png" alt=""></p>
<p>중앙값이 &#39;4&#39;, &#39;5&#39;인데 이 중 작은수를 뽑는 규칙을 설정하겠다.
&#39;4&#39;를 뽑았다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/042b7ce8-dfc2-4223-a078-673e71195bc5/image.png" alt=""></p>
<p>우리가 찾으려는 &#39;2&#39;는 &#39;4&#39;보다 작으므로 &#39;4&#39;의 왼쪽만 보겠다.
(오른쪽은 이제 볼 필요가 없다.)
&#39;0&#39;, &#39;1&#39;, &#39;2&#39;, &#39;3&#39; 이 있다. 여기서 또 중앙값을 찾는다.
&#39;1&#39;과 &#39;2&#39;중 작은수를 뽑는 규칙을 정했으므로 &#39;1&#39;이다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/4b467b37-c786-4d3d-abb5-f8374ec3a387/image.png" alt=""></p>
<p>&#39;2&#39;는 &#39;1&#39;보다 크므로 &#39;1&#39;의 오른쪽만 남는다.
&#39;2&#39;, &#39;3&#39;이 남았다.</p>
<p>&#39;2&#39;를 찾았다.</p>
<br>


<p>이제 위의 탐색법(경로)을 이진트리로 구현해보겠다.
<img src="https://velog.velcdn.com/images/falling_star3/post/e99b9214-8c57-431e-bc59-fb8438531cdf/image.png" alt=""></p>
<p>처음 찾은 중앙값인 &#39;4&#39;가 루트노드가 된다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/1ba94782-77d7-40e3-ac2b-6c046aec4274/image.png" alt=""></p>
<p>&#39;4&#39;보다 작은 값들을 탐색한다.
&#39;4&#39;보다 작은 값들이므로 왼쪽 자식 노드로 들어간다.(왼쪽 오른쪽은 다른 노드로 취급한다.)
자식노드는 중앙값인 &#39;1&#39;이 들어간다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/783a6657-da4e-4c98-afac-7d1872dfa324/image.png" alt=""></p>
<p>&#39;1&#39;보다 작은 값들을 탐색한다.
&#39;1&#39;보다 작은 값들이므로 왼쪽 자식 노드로 들어간다.
자식노드는 중앙값인 &#39;0&#39;이 들어간다.
&#39;0&#39;보다 작은 값이 없으므로 왼쪽자식 노드 탐색은 끝이난다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/6bb942a3-84b3-4cde-8bbe-f7c7db706c8b/image.png" alt=""></p>
<p>이제 &#39;1&#39;보다 큰 &#39;1&#39;의 오른쪽 자식노드를 탐색한다.
&#39;1&#39;보다 큰 값들이므로 오른쪽 자식 노드로 들어간다.
자식노드는 중앙값인 &#39;2&#39;가 들어간다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/1193959f-4d02-48fa-b474-1833dd13b3ce/image.png" alt=""></p>
<p>&#39;2&#39;보다 큰 값들을 탐색한다.
&#39;2&#39;보다 큰 값들이므로 오른쪽 자식 노드로 들어간다.
자식노드는 중앙값인 &#39;3&#39;이 들어간다.
&#39;3&#39;보다 큰 값이 없으므로 오른쪽자식 노드 탐색은 끝이난다.
(&#39;4&#39;보다 작은 &#39;0&#39;, &#39;1&#39;, &#39;2&#39;, &#39;3&#39;만 탐색했으므로)</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/c2f58226-29ff-4a93-b770-97663da7ee77/image.png" alt=""></p>
<p>이와같이 &#39;4&#39;의 오른쪽도 탐색하면 위와같은 트리가 완성된다.</p>
<p>👉 <a href="https://youtu.be/9ZZbA2iPjtM?si=rBFNZxO3lL6Pdkdf">유튜브 참고</a> </p>
<p>★ 위의 유튜브에서 영상 자료를 참고하였으며, 강추하는 영상입니다. ★</p>
<br>



<p>저렇게 구현된 트리를 노드별로 순회하며 탐색하는 방법을 이진 탐색 트리라한다.
위 예제의 탐색 방법 외에도 여러 탐색 방법이 있고, 여러 트리구조가 있다.</p>
<p>위의 탐색 방법은 &#39;전위 순회&#39;이다. (루트 노드인 &#39;4&#39;부터 자식노드 순회)
탐색 방법을 더 알아보자.</p>
<br>
<br>

<hr>
<h2 id="📌-2-이진트리-탐색-방법전위·중위·후위·레벨순회">📌 2. 이진트리 탐색 방법(전위·중위·후위·레벨순회)</h2>
<blockquote>
<p><strong>① 전위 순회 (Preorder Traversal): 루트 → 왼쪽 → 오른쪽
② 중위 순회 (Inorder Traversal): 왼쪽 → 루트 → 오른쪽
③ 후위 순회 (Postorder Traversal): 왼쪽 → 오른쪽 → 루트 (LRV) ✨
④ 레벨 순회 (Levelorder Traversal): 루트부터 레벨별로 왼쪽에서 오른쪽으로 (BFS, 너비 우선 탐색)</strong></p>
</blockquote>
<p>탐색 경로에 따라 전위, 중위, 후위, 레벨 순회가 있다.
일반적으로, 후위 순회가 많이 사용된다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/0ce3f5c9-9fb3-4243-b796-4508b11222ba/image.png" alt=""></p>
<p><strong>① 전위 순회 (Preorder Traversal): 루트 → 왼쪽 → 오른쪽 (VLR)</strong>
👉 <strong>A → B → D → E → C → F → G</strong></p>
<p>(1) 자기 자신을 처리
(2) 왼쪽 자식을 방문
(3) 오른쪽 자식을 방문</p>
<p>루트 노드를 가장 먼저 방문하기 때문에 트리 구조를 표현하는 데 적합 
→ 디렉터리 탐색, 데이터 직렬화</p>
<br>

<p><strong>② 중위 순회 (Inorder Traversal): 왼쪽 → 루트 → 오른쪽 (LVR)</strong>
👉 <strong>D → B → E → A → F → C → G</strong></p>
<p>(1) 왼쪽 자식을 방문
(2) 자기 자신을 처리
(3) 오른쪽 자식을 방문</p>
<p>이진 탐색 트리(BST)의 정렬된 순서로 탐색 
→ 검색, 데이터 정렬, 수식 계산 및 파싱 (수학적 표현식 변환)</p>
<br>


<p><strong>③ 후위 순회 (Postorder Traversal): 왼쪽 → 오른쪽 → 루트 (LRV)</strong>
👉 <strong>D → E  → B → F → G → C → A</strong>  </p>
<p>(1) 왼쪽 자식을 방문
(2) 오른쪽 자식을 방문
(3) 자기 자신을 처리</p>
<p>자식 노드를 모두 처리한 후에 부모 노드를 방문하는 방식
→ 파일 삭제(하위부터), 컴파일러</p>
<br>

<p><strong>④ 레벨 순회 (Levelorder Traversal): 루트부터 레벨별로 왼쪽에서 오른쪽으로 (BFS, 너비 우선 탐색)</strong>
👉 <strong>A → B → C → D → E → F → G</strong></p>
<p>(1) 현재 레벨의 모든 노드를 처리
(2) 왼쪽 자식을 방문
(3) 오른쪽 자식을 방문</p>
<p>너비 우선 탐색(BFS) 방식(트리를 위에서 아래로, 왼쪽에서 오른쪽으로 탐색)
→ 최단 경로 탐색, AI 탐색 알고리즘(예: 체스, 길찾기), 네트워크</p>
<br>
<br>

<hr>
<h2 id="📌-3-이진트리의-종류">📌 3. 이진트리의 종류</h2>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/c960c46a-7537-4f7f-adfb-37dfd6335db6/image.png" alt=""></p>
<p><strong>① 포화 이진 트리 (Full Binary Tree)</strong>
모든 노드가 자식 2개 또는 0개를 가짐.
모든 레벨이 꽉 차 있지는 않아도 됨.</p>
<p><strong>② 완전 이진 트리 (Complete Binary Tree)</strong>
마지막 레벨을 제외한 모든 노드가 가득 차 있으며, 마지막 레벨의 노드는 왼쪽부터 순서대로 채워짐.
힙(Heap) 자료구조에서 많이 사용됨.</p>
<p><strong>③ 퇴화 이진 트리 (Degenerate Binary Tree)</strong>
모든 노드가 자식 노드를 하나만 가짐.
연결 리스트(Linked List)와 유사한 구조로, 탐색, 삽입, 삭제 연산이 O(n) 으로 증가.</p>
<p><strong>④ 정 이진 트리 (Perfect Binary Tree)</strong>
모든 내부 노드는 자식 2개, 모든 리프 노드는 같은 깊이에 위치.
노드 개수는 항상 2^ℎ−1 형태.</p>
<p><strong>⑤ 이진 탐색 트리 (Binary Search Tree, BST)</strong>
왼쪽 서브트리는 부모보다 작은 값, 오른쪽 서브트리는 부모보다 큰 값을 가짐.
평균적인 탐색, 삽입, 삭제 연산의 시간 복잡도는 O(log n), 최악의 경우 O(n).</p>
<br>
<br>

<hr>
<h2 id="4-이진트리-구현java">4. 이진트리 구현(Java)</h2>
<p>이진트리를 직접 구현해보자.
&#39;50, 30, 70, 20, 40, 60, 80&#39;의 값들을 이진 탐색 트리(BST)로 구현할 것이다.</p>
<p>결론적으로, 트리는 아래와 같이 만들어질 것이다.</p>
<pre><code>        50
       /  \
     30    70
    /  \   /  \
  20   40 60  80
</code></pre><br>

<pre><code class="language-java">// 이진 트리의 노드 클래스 (각 노드가 값을 가지며 왼쪽/오른쪽 자식을 가짐)
class Node {
    int value;      // 노드의 값
    Node left, right; // 왼쪽 자식 노드, 오른쪽 자식 노드

    // 생성자 (새로운 노드를 만들 때 값만 설정하고, 자식 노드는 없음)
    public Node(int value) {
        this.value = value;
        left = right = null;
    }
}

// 이진 트리 클래스 (삽입 및 탐색 기능 포함)
class BinaryTree {
    Node root; // 트리의 루트 노드 (초기에는 null)

    // 이진 탐색 트리(BST) 방식으로 노드를 삽입하는 메서드
    Node insert(Node root, int value) {
        if (root == null) return new Node(value); // 루트가 없으면 새 노드를 생성하여 반환

        // 삽입할 값이 현재 노드보다 작으면 왼쪽 서브트리에 삽입
        if (value &lt; root.value) {
            root.left = insert(root.left, value);
        }
        // 삽입할 값이 현재 노드보다 크면 오른쪽 서브트리에 삽입
        else {
            root.right = insert(root.right, value);
        }
        return root; // 변경된 루트 반환
    }

    // 특정 값이 트리에 존재하는지 탐색하는 메서드
    boolean search(Node root, int key) {
        if (root == null) return false; // 루트가 null이면 존재하지 않음
        if (root.value == key) return true; // 현재 노드의 값이 찾는 값과 같으면 true 반환

        // 찾는 값이 현재 노드보다 작으면 왼쪽 서브트리에서 검색
        if (key &lt; root.value) {
            return search(root.left, key);
        }
        // 찾는 값이 현재 노드보다 크면 오른쪽 서브트리에서 검색
        else {
            return search(root.right, key);
        }
    }
}

// 실행 클래스 (메인 메서드 포함)
public class BinaryTreeDemo {
    public static void main(String[] args) {
        BinaryTree tree = new BinaryTree(); // 이진 트리 객체 생성

        // 노드 삽입 (이진 탐색 트리 구조 유지)
        int[] values = {50, 30, 70, 20, 40, 60, 80};
        for (int value : values) {
            tree.root = tree.insert(tree.root, value);
        }

        // 값 탐색 테스트
        int searchValue = 40;
        if (tree.search(tree.root, searchValue)) {
            System.out.println(searchValue + &quot;을(를) 찾았습니다.&quot;);
        } else {
            System.out.println(searchValue + &quot;이(가) 존재하지 않습니다.&quot;);
        }
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[불변객체(Immutable Object)란? (+불변객체를 사용해야하는 상황 및 예제)]]></title>
            <link>https://velog.io/@falling_star3/%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4Immutable-Object%EB%9E%80-%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC%ED%95%98%EB%8A%94-%EC%83%81%ED%99%A9-%EB%B0%8F-%EC%98%88%EC%A0%9C</link>
            <guid>https://velog.io/@falling_star3/%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4Immutable-Object%EB%9E%80-%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC%ED%95%98%EB%8A%94-%EC%83%81%ED%99%A9-%EB%B0%8F-%EC%98%88%EC%A0%9C</guid>
            <pubDate>Sun, 12 Jan 2025 08:08:52 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-불변객체immutable-object란">📌 1. 불변객체(Immutable Object)란?</h2>
<blockquote>
<p><strong>객체의 상태(객체 내부의 값, 필드, 멤버 변수)가 변하지 않는 객체를 불변 객체(Immutable Object)라 한다.</strong></p>
</blockquote>
<p>한마디로, 위의 그림과 같이 객체의 내부를 변경 못하도록 막는 것이다.</p>
<pre><code class="language-java"> public class RefMain2 {
 public static void main(String[] args) {
 ImmutableAddress a = new ImmutableAddress(&quot;서울&quot;);
 ImmutableAddress b = a; //참조값 대입을 막고 싶은데 방법이 없다!
 //b.setValue(&quot;부산&quot;); //컴파일 오류 발생
 //b에 a를 대입하는 것을 막을 수 있는 방법이 없으니, 
 //b에 a를 대입하되 값이 변경될 수 없도록 불변객체로 만드는 것이다.
 }</code></pre>
<p>이게 무슨말인지 왜 필요한지 차근차근 알아보자.</p>
<br>
<br>

<hr>
<h2 id="📌-2-공유-참조와-사이드-이펙트기본형과-참조형의-공유">📌 2. 공유 참조와 사이드 이펙트(기본형과 참조형의 공유)</h2>
<br>

<p><strong>자바의 데이터 타입을 가장 크게 보면 기본형(Primitive Type)과 참조형(Reference Type)으로 나눌 수 있다.</strong></p>
<blockquote>
<p>** - 기본형: 하나의 값을 여러 변수에서 절대로 공유하지 않는다.**
 ** - 참조형: 하나의 객체를 참조값을 통해 여러 변수에서 공유할 수 있다.**</p>
</blockquote>
<br>

<p>여기서 &#39;공유&#39;란 무엇인가?
a에서 변경을 하면 b도 함께 변경되고 b에서 변경하면 a도 변경되는 것을 말한다.
이때 a와 b는 서로 값을 &#39;공유&#39;하고 있다고 한다.</p>
<p>기본형 타입과 참조형 타입의 &#39;공유&#39;에 대해 알아보자.</p>
<br>

<h4 id="▶-기본형-타입">▶ 기본형 타입</h4>
<p><strong>기본형 타입 변수는 값을 복사할 뿐 공유하지 않는다.</strong></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/a967a2f2-18f1-4d64-b21a-b444fe52fc53/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/63f11179-a2ce-419a-ad15-5d06ca051fa6/image.png" alt=""></p>
<pre><code class="language-java"> public class PrimitiveMain {
   public static void main(String[] args) {
     int a = 10;
     int b = a; 
     // a -&gt; b, 값 복사 후 대입(기본형은 절대로 같은 값을 공유하지 않는다.)
     System.out.println(a); //10
     System.out.println(b); //10

     b = 20;
     System.out.println(a); //10 
     System.out.println(b); //20 
   }
}</code></pre>
<br>

<p>b를 20으로 변경해도, a는 여전히 10이 출력되는 것을 볼 수 있다.
a와 b가 같은 값을 공유하는 것이 아닌, a의 값을 b에 복사하여 대입했기 때문이다.</p>
<br>
<br>

<h4 id="▶-참조형-타입">▶ 참조형 타입</h4>
<p><strong>참조형 변수는 하나의 객체를 참조값을 통해 여러 변수에서 공유할 수 있다.</strong></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/b92b0d67-5713-4248-acbe-361c52040754/image.png" alt=""></p>
<pre><code class="language-java"> public class RefMain1 {
   public static void main(String[] args) {
   //참조형 변수는 하나의 인스턴스를 공유할 수 있다.
   Address a = new Address(&quot;서울&quot;);
   Address b = a;
   b.setValue(&quot;부산&quot;); //b의 값을 부산으로 변경
   System.out.println(a); //출력: 부산 (사이드 이펙트 발생)
   System.out.println(b); //출력: 부산
      }
 }</code></pre>
<p>1) 처음에는 a, b 둘다 서울이라는 주소를 가져야 한다고 가정하자.
2) 이후 b를 부산으로 변경한다.
3) 실행결과를 보면 b뿐만 아니라 a의 주소도 함께 부산으로 변경되어 버린다.</p>
<p>같은 주소값(인스턴스)을 참조하기 때문이다.</p>
<p>b=a라고 하면 a에 있는 참조값 x001을 복사해서 b에 전달한다.
참조값을 복사해서 전달하므로 결과적으로 a, b는 같은 x001 인스턴스를 참조한다.
<strong>참조형 변수는 참조값을 통해 같은 객체(인스턴스)를 공유할 수 있다.</strong></p>
<p>여기서 b의 주소만 부산으로 변경했는데, a의 주소도 함께 변경되는 것을 <strong>사이드 이펙트</strong>라 한다.</p>
<br>

<h5 id="💡-사이드이펙트side-effect란">💡 사이드이펙트(Side Effect)란?</h5>
<h6 id="프로그래밍에서-어떤-계산이-주된-작업-외에-추가적인-부수-효과를-일으키는-것을-말한다-프로그래밍에서-사이드-이펙트는-보통-부정적인-의미로-사용되는데-사이드-이펙트는-프로그램의-특정-부분에서-발생한-변경이-의도치-않게-다른-부분에-영향을-미치는-경우에-발생한다-이로-인해-디버깅이-어려워지고-코드의-안정성이-저하될-수-있다">프로그래밍에서 어떤 계산이 주된 작업 외에 추가적인 부수 효과를 일으키는 것을 말한다. 프로그래밍에서 사이드 이펙트는 보통 부정적인 의미로 사용되는데, 사이드 이펙트는 프로그램의 특정 부분에서 발생한 변경이 의도치 않게 다른 부분에 영향을 미치는 경우에 발생한다. 이로 인해 디버깅이 어려워지고 코드의 안정성이 저하될 수 있다.</h6>
<br>

<p><img src="https://velog.velcdn.com/images/falling_star3/post/33cac88c-5e2b-4b43-8e3f-0fc461a5761d/image.png" alt=""></p>
<p><strong>개발자에게 내가 의도하지 않은 무언가가 나도 모르게 뒤에서 돌아가고 있는것만큼 무서운 것은 없다..</strong></p>
<p>사이드 이펙트를 해결하려면 어떻게 해야할까?
위와 같은 경우에서는 a와 b가 서로 다른 인스턴스를 참조하도록 하면 된다.</p>
<pre><code class="language-java"> Address a = new Address(&quot;서울&quot;);
 Address b = new Address(&quot;서울&quot;)</code></pre>
<p>위와 같이 여러 변수가 하나의 참조값을 공유하지 않으면 문제가 해결될 것 같다.</p>
<p>하지만, 개발자가 실수로 하나의 참조값을 공유하도록 코드를 작성한다면 문제가 발생할 것이다.</p>
<p><strong>애초부터 b=a를 막는 방법은 없을까?
공유하면 안되는 인스턴스는 공유를 못하도록 막는 방법말이다.
슬프게도 그런 방법은 없다.</strong></p>
<p>b=a로 하나의 인스턴스를 공유하게 코드를 작성해도 자바 문법상 아무런 오류가 나지 않는다. 막는 특별한 문법 또한 없다.
참조형 변수의 대입은 그 자체로 아무런 문제가 없기 때문이다.</p>
<p>실제로는 훨씬 더 복잡한 상황에서 이런 문제가 발생한다.
구조와 코드가 복잡할수록 사이드 이펙트는 원인을 찾기도 디버깅 하기도 어려워진다.</p>
<br>

<h3 id="⭐-그래서-등장한-것이-바로-불변객체이다">⭐ 그래서 등장한 것이 바로 불변객체이다!</h3>
<br>
<br>

<hr>
<h2 id="📌-3-불변객체---도입">📌 3. 불변객체 - 도입</h2>
<blockquote>
<p><strong>객체의 상태(객체 내부의 값, 필드, 멤버 변수)가 변하지 않는 객체를 불변 객체(Immutable Object)라 한다.</strong></p>
</blockquote>
<p>지금까지 발생한 문제를 잘 생각해보면 공유하면 안되는 객체를 여러 변수에서 공유했기 때문에 발생한 문제이다.</p>
<p>하지만 앞서 살펴보았듯이 객체의 공유를 막을 수 있는 방법은 없다.
그런데 사이드 이펙트의 더 근본적인 원인을 고려해보면, 객체를 공유하는 것 자체는 문제가 아니다. 객체를 공유한다고 바로 사이드 이펙트가 발생하지는 않는다.</p>
<p>문제는 바로 <strong>공유된 객체의 값을 변경</strong>한 것에 있다.</p>
<p><strong>객체의 값을 변경하지 못하게 설계했다면 이런 사이드 이펙트 자체가 발생하지 않을 것이다.</strong></p>
<p>이때 필요한 것이 바로 <strong>불변객체</strong>이다.
불변객체로 만드는 예시를 살펴보자.</p>
<br>

<p>▶ <strong>기존 코드</strong></p>
<pre><code class="language-java"> public class Address {
   private String value;
   public Address(String value) {
           this.value = value;
   }
   public void setValue(String value) {
           this.value = value;
   }
   public String getValue() {
           return value;
   }

   @Override
   public String toString() {
           return value;
   }
}</code></pre>
<br>

<p>▶ <strong>불변객체 코드</strong></p>
<blockquote>
<p><strong>1. 내부 값이 변경되면 안되기 때문에 value의 필드를 final로 선언.
2. 값을 변경할 수 있는 setValue() 제거.
3. 이 클래스는 생성자를 통해서만 값을 설정할 수 있고, 이후 값을 변경하는 것이 불가능.</strong></p>
</blockquote>
<pre><code class="language-java">public class ImmutableAddress {
     private final String value;
     public ImmutableAddress(String value) {
         this.value = value;
    }
    public String getValue() {
         return value;
    }
    @Override
    public String toString() {
         return value;
    }
 }</code></pre>
<p><strong>코드의 목적</strong>
: ImmutableAddress를 사용하는 개발자가 값을 변경하려고 시도하다가, 값을 변경하는 것이 불가능하다는 것을 알고(b.setValue(&quot;부산&quot;)불가능) 이 객체가 불변객체인 것을 깨닫는 것.
따라서, 어쩔 수 없이 새로운 인스턴스를 생성하는 것!</p>
<br>
<br>

<h3 id="정리">정리</h3>
<p>객체의 공유 참조는 막을 수 없다. 그래서 객체의 값을 변경하면 다른 곳에서 참조하는 변수의 값도 함께 변경되는 사이드 이펙트가 발생한다. 사이드 이펙트가 발생하면 안되는 상황이라면 불변 객체를 만들어서 사용하면 된다. 불변 객체는 값을 변경할 수 없기 때문에 사이드 이펙트가 원천 차단된다.</p>
<p>불변 객체는 값을 변경할 수 없다. 따라서 불변 객체의 값을 변경하고 싶다면 변경하고 싶은 값으로 새로운 불변 객체를 생성해야 한다. 이렇게 하면 기존 변수들이 참조하는 값에는 영향을 주지 않는다.</p>
<br>
<br>

<hr>
<h4 id="마지막-한-줄">마지막 한 줄</h4>
<p>정말 개발하면서 제일 무서운 것은.. 내가 수정한 코드에 사이드 이펙트가 발생해서 나도 모르게! 뒤에서 의도하지 않은 무언가가 변경되는 것이다..</p>
<p>그리고 개발하면서 제일 중요한 것은 인간을 믿지 말고 시스템을 믿자는 것이다^^! 실수하지 않기를 바라지말고 시스템에서 막아야 한다.
이는 개발자든 사용자든 모두에게 해당되는 말이다★</p>
<br>


<h4 id="참고">참고</h4>
<p>김영한의 java 중급1 - 불변객체</p>
]]></description>
        </item>
        <item>
            <title><![CDATA['=='연산자와 equals() 메서드의 차이(동일성 vs 동등성)]]></title>
            <link>https://velog.io/@falling_star3/%EC%97%B0%EC%82%B0%EC%9E%90%EC%99%80-equals-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%8F%99%EC%9D%BC%EC%84%B1-vs-%EB%8F%99%EB%93%B1%EC%84%B1</link>
            <guid>https://velog.io/@falling_star3/%EC%97%B0%EC%82%B0%EC%9E%90%EC%99%80-equals-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%8F%99%EC%9D%BC%EC%84%B1-vs-%EB%8F%99%EB%93%B1%EC%84%B1</guid>
            <pubDate>Fri, 20 Dec 2024 03:29:38 GMT</pubDate>
            <description><![CDATA[<p>java에서 &#39;==&#39;과 equals()는 다르게 쓰인다.
문자열을 비교할 때 equals() 메서드를 사용하는 것은 알겠다.</p>
<p>그런데 이 둘은 내부적으로 무슨 차이를 가지길래 구별해서 쓰고 있는 것일까?</p>
<p><strong>자바는 두 객체가 같다라는 표현을 두 가지로 분리해서 제공한다.</strong></p>
<br>
<br>

<h2 id="📌-1-동일성-vs-동등성">📌 1. 동일성 vs 동등성</h2>
<blockquote>
<p><strong>동일성(Identity): == 연산자를 사용해서 두 객체의 참조가 동일한 객체를 가리키고 있는지 확인</strong>
<strong>동등성(Equality): equals() 메서드를 사용하여 두 객체가 논리적으로 동등한지 확인</strong></p>
</blockquote>
<p><strong>&#39;==&#39;연산자와 equals() 메서드의 차이는 바로, &#39;동일&#39;과 &#39;동등&#39;의 차이이다.</strong></p>
<p>&#39;동일&#39;은 완전히 같음을 의미한다. 반면 &quot;동등&quot;은 같은 가치나 수준을 의미하지만 그 형태나 외관 등이 완전히 같지는 않
을 수 있다. 영어로 보면 좀 더 쉽다. &#39;Identity&#39;와 &#39;Equality&#39;의 차이이다.</p>
<p>쉽게 이야기해서, <strong>동일성은 물리적으로 같은 메모리에 있는 객체 인스턴스인지 참조값을 확인</strong>하는 것이고, <strong>동등성은 논리적으로 같은지 확인</strong>하는 것이다.</p>
<p>동일성은 자바 머신 기준이고 메모리의 참조가 기준이므로 물리적이다. 반면 동등성은 보통 사람이 생각하는 논리적인 
기준에 맞추어 비교한다.</p>
<br>
<br>

<hr>
<h2 id="📌-2-동일성-vs-동등성-예제">📌 2. 동일성 vs 동등성 예제</h2>
<br>


<p>같은 회원 번호를 가진 회원 객체가 2개 있다고 가정해보자.</p>
<pre><code class="language-java"> User a = new User(&quot;id-100&quot;) //참조 x001
 User b = new User(&quot;id-100&quot;) //참조 x002</code></pre>
<p>이 경우 물리적으로 다른 메모리에 있는 다른 객체이지만, 회원 번호를 기준으로 생각해보면 논리적으로는 같은 회원으
로 볼 수 있다.</p>
<p>따라서 <strong>동일성은 다르지만, 동등성은 같다.</strong>
문자의 경우도 마찬가지이다.</p>
<pre><code class="language-java"> String s1 = &quot;hello&quot;;
 String s2 = &quot;hello&quot;;</code></pre>
<p>이 경우 물리적으로는 각각의 &quot;hello&quot; 문자열이 다른 메모리에 존재할 수 있지만, 논리적으로는 같은 문자열이다.</p>
<br>

<p>이제 실제로 코드를 출력해보자.</p>
<br>
<br>

<h4 id="▶-동일성-동등성-예제">▶ 동일성 동등성 예제</h4>
<p><strong>Q. 다음과 같이 찍어보면 어떻게 될까?</strong></p>
<pre><code class="language-java">System.out.println(&quot;identity = &quot; + (user1 == user2));
System.out.println(&quot;equality = &quot; + user1.equals(user2))</code></pre>
<p>** 실행 결과는 다음과 같다.**</p>
<pre><code class="language-java"> identity = false
 equality = false</code></pre>
<p>이상하다. 물리적으로는 다른 메모리이니 동일하지 않다는 것은 알겠다. 그런데 <strong>왜 동등하지도 않은가?</strong> (아깐 동등하다며!)</p>
<p>** 🚫Object가 기본으로 제공하는 equals()는 ==으로 동일성 비교를 제공한다.**</p>
<p>위와 같은 이유로 인해 false가 나오는 것이다.
ID가 같을 경우, 논리적으로 동등한 결과라고 할 것이라면 equals()메서드를 재정의 해주어야 한다.</p>
<br>

<h4 id="▶-문자열-예제1">▶ 문자열 예제1</h4>
<p><strong>Q. 그럼 문자열은 어떨까?</strong></p>
<pre><code class="language-java">System.out.println(&quot;identity = &quot; + (s1 == s2)); 
System.out.println(&quot;equality = &quot; + s1.equals(s2))</code></pre>
<p>** 실행 결과는 다음과 같다.**</p>
<pre><code class="language-java"> identity = true
 equality = true</code></pre>
<p> 둘 다 true가 나오는 이유는 <strong>문자열이 같은 경우 자바가 같은 메모리를 사용하도록 최적화(String Constant Pool )</strong> 하기 때문이다.
 그러므로 동일하고, Object가 기본 제공하는 equals()는 동일성을 체크하므로 둘 다 true가 나오는 것이다.</p>
<br>
<br>

<h4 id="▶-문자열-예제2">▶ 문자열 예제2</h4>
<p>여기서 또 의문이 들 것이다.
아까 문자열은 equals()로 비교한다면서 위의 예제는 왜 true로 나오는가?</p>
<p>다음 예제를 보자.</p>
<pre><code class="language-java">String s1 = &quot;hello&quot;;
String s2 = new String(&quot;hello&quot;);

System.out.println(s1 == s2);       // false: 다른 객체
System.out.println(s1.equals(s2)); // true: 값은 같음</code></pre>
<p>문자열이 리터럴이 아닌 <strong>new String()</strong>을 통해 생성된 경우, 서로 다른 객체를 참조하므로 &#39;==&#39;는 false를 반환한다. </p>
<p>사용자 입력값이나 데이터 조작으로 생성된 문자열은 동일한 값을 가지더라도 다른 메모리 주소를 참조할 가능성이 높다.
(&#39;==&#39;는 리터럴처럼 메모리 최적화가 명확한 경우에만 올바르게 작동)</p>
<p>equals()는 문자열의 값(내용)을 비교하기 때문에 상황에 상관없이 올바른 결과를 보장한다.
위와 같은 이유로 코드의 안정성과 가독성을 위해 문자열 비교에는 항상 equals()를 사용하는 것이 권장된다.</p>
<br>
<br>

<hr>
<h4 id="출처">출처</h4>
<p>Java SE Documentation - Object.equals()
Java SE Documentation - Java Language Specification (Equality Operators)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[java구현]Parant parent = new Child();의 경우, 오버라이딩 된 메서드를 메모리에서 어떻게 찾아갈 것인가?(동적 디스패치)]]></title>
            <link>https://velog.io/@falling_star3/%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8F%84-%EC%B0%B8%EC%A1%B0-%EB%B3%80%EC%88%98-%ED%83%80%EC%9E%85%EC%9D%84-%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C-%ED%98%B8%EC%B6%9C%ED%95%98%EB%8A%94%EA%B0%80%EB%A9%94%EC%84%9C%EB%93%9C-%EB%94%94%EC%8A%A4%ED%8C%A8%EC%B9%98%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8</link>
            <guid>https://velog.io/@falling_star3/%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8F%84-%EC%B0%B8%EC%A1%B0-%EB%B3%80%EC%88%98-%ED%83%80%EC%9E%85%EC%9D%84-%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C-%ED%98%B8%EC%B6%9C%ED%95%98%EB%8A%94%EA%B0%80%EB%A9%94%EC%84%9C%EB%93%9C-%EB%94%94%EC%8A%A4%ED%8C%A8%EC%B9%98%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8</guid>
            <pubDate>Tue, 22 Oct 2024 10:31:48 GMT</pubDate>
            <description><![CDATA[<p>상속의 중요한 두 가지 개념은 다음과 같다.</p>
<blockquote>
<p><strong>1. 메서드 호출 시 호출하는 변수의 타입(클래스)을 기준으로 호출
2. 메서드 상속은 일방통행 (자식 → 부모)</strong></p>
</blockquote>
<br>

<p>이제 질문이 생긴다. 오버라이딩의 경우 말이다. </p>
<p><strong>Q. <code>Parant parent = new Child();</code>의 경우, 오버라이딩 된 메서드는 메모리에서 어떻게 찾아갈 것인가?</strong></p>
<p>오버라이딩 된 메서드도 참조 변수 타입을 기준으로 호출할 것인가?
그럼 Parent로 가는데 Child에서 오버라이딩 된 것을 어떻게 찾을 것인가?
Parent -&gt; Child는 부모-&gt;자식이므로 안되지 않나?</p>
<p>이 물음표 때문에 이 포스팅을 작성한다.</p>
<p>상속의 개념과 오버라이딩 메서드 호출 개념 사이의 혼란을 해결해가보자.</p>
<br>

<p>** 🚫 !! 해당 포스팅은 각종 자료로 제가 결론을 도출한 포스팅이기 때문에 틀린 내용이 있을 수 있습니다.**
<del>인프런의 특정 java 강의에서 저의 결론과 다른 내용이 있어 문의한 상태입니다.</del>
=&gt; 동작 구현은 제 포스팅의 내용이 맞으며, 강의에서는 다형성을 쉽게 이해시키기 위해 한 표현이라고 답변받았습니다.</p>
<p>관련 내용 포스팅이 많지 않아, 공부한 자료를 근거로 논리적 결론을 도출했으므로 틀린내용이 있으면 댓글 환영입니다..★</p>
<br>

<hr>
<p><strong>알고가면 좋을 사전 지식</strong></p>
<p> <a href="https://velog.io/@falling_star3/Java-Ch071.-%EC%83%81%EC%86%8Dinheritance">상속 자세히</a>
 <a href="https://velog.io/@falling_star3/%EC%83%81%EC%86%8D%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0">상속과 메모리 구조 자세히</a>
<a href="https://velog.io/@falling_star3/Java-Ch072.-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9overriding">오버라이딩 자세히</a></p>
<br>
<br>




<hr>
<h2 id="📌-1-오버라이딩-된-메서드-호출">📌 1. 오버라이딩 된 메서드 호출</h2>
<br>



<pre><code class="language-java">
public class Test {
    public static void main(String[] args) {
        Parant parent = new Child();
        parent.getTest(); 
    }
}

class Parent {
    public void getTest() {
        System.out.println(&quot;부모&quot;);
    }
}

class Child extends Parent {
    public void getTest() {
        System.out.println(&quot;자식&quot;);
    } 
}
</code></pre>
<p><strong>오버라이딩 된 경우, 부모(Parent)클래스의 getTest()가 호출될까? 자식의 getTest()가 호출될까?</strong>
👉 *<em>정답은 &quot;자식&quot;이다. *</em></p>
<br>

<p>어떻게 보면 당연하다.
그런데 좀 찝찝하다.</p>
<p>참조 변수의 타입이 Parent인데 어떻게 된걸까?
<del>참조 변수 타입으로 호출 기준 정한다면서요!!</del> </p>
<p>오버라이딩 됐기때문에 <code>일단 Parent 먼저 찾고 오버라이딩 체크해서 오버라이딩 된 메서드이면 → Child 클래스로 가서 getTest() 호출</code>한 것인가?</p>
<br>

<p>그런데 첫 단락에서 정리한 내용을 보면 <strong>메소드 상속은 일방통행(자식 → 부모)이다.</strong></p>
<hr>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/019dd06c-5a2d-4aca-a644-a67c234add8b/image.png" alt=""></p>
<hr>
<p>Parent클래스에 가서 getTest()를 찾고, 오버라이딩 된 함수라고 자식으로 가서 호출할 수가 없다는 말이다!
자식 → 부모로는 갈 수 있지만, 부모 → 자식으로 갈 수는 없으니까 말이다.</p>
<br>

<p>정리해보자면,</p>
<p><strong>1) 참조 변수 타입이 Parent이니까 Parent로 먼저 감.
2) 자식 → 부모 일방통행이니까 Parent에서 오버라이딩 된 자식 메서드로 갈 수 없음.</strong></p>
<p>흐름이 어떻게 되는거지 ????????????
여기서 내 논리가 붕괴됐다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/b93ac441-0b60-4900-ac51-79482a265ff5/image.png" alt=""></p>
<h6 id="예쁘다-아이유♥">예쁘다 아이유...♥</h6>
<p>*<em>&#39;자식&#39;이라는 출력 결과가 나오려면 &#39;참조 변수 타입 기준 호출&#39;과 &#39;메소드 상속은 일방통행&#39;은 양립할 수 없다. *</em></p>
<p>그렇다면</p>
<p>(1) 참조 변수 타입을 기준으로 호출하는 것이 틀리거나,
(2) 메소드 상속이 일방통행인 것이 틀리거나,
(3) 뭔가 다른 작동이 있거나</p>
<br>

<p><strong>정답은 (3)이다.</strong>
정확히 말하면, (1)에 예외가 생긴다.
<em>(&#39;예외&#39;라는 표현은 틀렸을 수 있지만, 일단 위에서 &#39;참조변수 타입 기준 호출&#39;을 말했으니 이 내용은 &#39;예외&#39;라고 표현하겠다.)</em></p>
<br>

<p>예외의 기준은 <strong>getTest()가 오버라이딩 되었는가?</strong>이다.</p>
<blockquote>
<p><strong>getTest()가 오버라이딩 되지 않았으면, 변수의 타입이 기준이고,
getTest()가 오버라이딩 되었으면, 실제 객체가 기준이 된다.</strong></p>
</blockquote>
<pre><code class="language-java">public class Test {

    public static void main(String[] args) {
        Parant parent = new Child();

        parent.getTest(); //&quot;자식&quot; 출력
    }
}

class Parent {
    public void getTest() {
        System.out.println(&quot;부모&quot;);
    }

}

class Child extends Parent {
    public void getTest() {
        System.out.println(&quot;자식&quot;);
    } 
}</code></pre>
<p>위에서 getTest()가 오버라이딩 되지 않았으면 Parent에서 호출하고, 오버라이딩 되었으면 Child에서 호출할 것이다.</p>
<br>


<p><strong>내가 궁금했고, 중요하게 생각하는 부분은 &#39;흐름&#39;과 &#39;시점&#39;이다.</strong>
그래서 &#39;오버라이딩 체크를 어디서 하는지&#39;, &#39;Parent에서 먼저 찾는지 Child에서 먼저 찾는지&#39; 말이다.</p>
<p>결론부터 말하자면 다음과 같다.</p>
<blockquote>
<p><strong>메서드 호출 시점에 오버라이딩을 체크해서, 오버라이딩이면 동적 디스패치가 수행된다. 
동적 디스패치를 수행하면, 참조변수타입이 아닌 실제 객체를 기준으로 메서드가 호출된다. (오버라이딩이 아니면 동적 디스패치는 수행되지 않는다.)</strong></p>
</blockquote>
<ol>
<li>parent.getTest()실행</li>
<li>호출된 메서드가 오버라이딩이면 동적 디스패치 수행(호출 시점에 실행)</li>
<li>동적 디스패치를 수행하면 참조변수타입이 아닌 실제 객체를 기준으로(new Child) 메서드가 호출됨. (오버라이딩이 안된 메서드면 동적 디스패치 수행x)</li>
<li>객체 주소 x001로 이동(부모, 자식 다 있음.) → 실제 객체 오버라이딩 된 메서드로 바로 이동.</li>
</ol>
<br>
<br>

<hr>
<h2 id="📌-2-정적-메서드-디스패치static-dispach와-동적-메서드-디스패치dynamic-method-dispatch">📌 2. 정적 메서드 디스패치(Static Dispach)와 동적 메서드 디스패치(Dynamic Method Dispatch)</h2>
<br>


<blockquote>
<p><strong>Static Method Dispatch : 컴파일 시점에 호출되는 메서드가 결정.
Dynamic Method Dispatch : 실행 시점에 호출되는 메서드가 결정.</strong></p>
</blockquote>
<p><strong>어떤 메소드를 호출할 것인가를 결정하고 실행하는 과정을 Method Dispatch라 한다.</strong></p>
<p>메서드 디스패치에 대한 개념에 대한 포스팅은 많지만, 이게 어떻게 쓰이는지 어떤 의미를 가지는지 와닿는 예시는 많이 없다.</p>
<p>그저 개념만 대충 알고 있었을 뿐인데 여기서 만날 줄이야!
상속에서 오버라이딩 된 메서드 호출 과정을 메모리 중점으로 바라보면 메서드 디스패치를 이해할 수 있다.</p>
<br>
<br>

<h3 id="2-1-정적-메서드-디스패치static-dispach">2-1. 정적 메서드 디스패치(Static Dispach)</h3>
<blockquote>
<p><strong>정적 메서드 디스패치는 컴파일 타임에 메서드가 호출될 대상을 결정하는 방식이다. 정적 메서드는 클래스에 속한 메서드이기 때문에, 객체의 실제 타입이 아닌 참조 변수의 타입에 따라 호출된다.</strong></p>
</blockquote>
<ul>
<li><p>** 컴파일 타임에 결정** 
메서드 호출은 참조 타입에 기반하여 컴파일 타임에 결정된다.</p>
</li>
<li><p><strong>오버로딩만 가능</strong> 
정적 메서드는 오버로딩(메서드 이름이 같지만 파라미터가 다른 경우)은 가능하지만, 오버라이딩(상속받아 메서드를 재정의하는 것)은 불가능하다.
<a href="https://velog.io/@falling_star3/Java-Ch064.-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9overloading">오버로딩 자세히 </a></p>
</li>
<li><p><strong>객체의 인스턴스와는 무관</strong> 
객체의 실제 타입과는 상관없이 호출되는 메서드이다.</p>
</li>
</ul>
<br>

<p>정적 메서드 디스패치는 정적 메서드, 오버라이딩 되지 않은 메서드에서 실행된다.
즉, 이런 메서드들은 참조 변수의 타입에 따라 호출된다.</p>
<p>static 메서드는 당연히 컴파일 타임에 결정되고,
오버라이딩 되지 않은 메서드도 부모 클래스의 메서드를 호출하므로 정적 메서드 디스패치가 실행된다.</p>
<br>

<p>*<em>여기서 재밌는 질문, static 메서드를 오버라이딩 한다면 어떻게 될까? *</em>
포스팅 : <a href="https://velog.io/@falling_star3/Java-%EC%A0%95%EC%A0%81-%EB%A9%94%EC%84%9C%EB%93%9Cstatic%EB%8A%94-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9%EC%9D%B4-%EB%90%A0%EA%B9%8C">정적 메서드(static)는 오버라이딩이 될까? (메서드 은닉)</a></p>
<pre><code class="language-java">
class Parent {
    public static void show() {
        System.out.print(&quot;부모 메서드&quot;);
    }
}

class Child extends Parent {
    public static void show() {
        System.out.print(&quot;자식 메서드&quot;);
    }
}

public class Test {
    public static void main(String[] args) {
        Parent p = new Child();  // 실제 객체는 Child, 참조 변수는 Parent
        p.show();  // Parent의 static 메서드 호출
    }
}
</code></pre>
<br>
<br>

<h3 id="2-2-동적-메서드-디스패치dynamic-method-dispatch">2-2. 동적 메서드 디스패치(Dynamic Method Dispatch)</h3>
<blockquote>
<p><strong>동적 메서드 디스패치는 런타임에 메서드 호출 대상을 결정하는 방식이다. 
객체가 실제로 어떤 클래스의 인스턴스인지에 따라 메서드가 호출된다. 주로 오버라이딩된 인스턴스 메서드에서 발생하며, 다형성을 구현하는 데 사용된다.</strong></p>
</blockquote>
<p><strong>런타임에 결정</strong>
메서드 호출은 객체의 실제 타입에 따라 런타임에 결정된다.</p>
<p><strong>오버라이딩</strong> 
부모 클래스에서 메서드를 정의하고 자식 클래스에서 재정의(오버라이딩)한 메서드가 호출된다.</p>
<p><strong>다형성 구현</strong> 
동일한 메서드 호출이 객체의 타입에 따라 다르게 동작할 수 있게 한다.</p>
<br>
<br>

<h3 id="💡-결론">💡 결론</h3>
<blockquote>
<p><strong>오버라이딩 된 메서드는 런타임에 메서드 호출 대상을 결정한다.
그러므로 실제 객체를 기준으로 호출한다. (동적 메서드 디스패치)</strong></p>
</blockquote>
<blockquote>
<p><strong>오버라이딩 되지 않은 메서드는 컴파일 타임에 메서드 호출 대상을 결정한다.
그러므로 참조 변수 타입을 기준으로 호출한다. (정적 메서드 디스패치)</strong></p>
</blockquote>
<blockquote>
<p><strong>오버라이딩 된 정적 메서드는 컴파일 타임에 메서드 호출 대상을 결정한다.
그러므로 참조 변수 타입을 기준으로 호출한다. (정적 메서드 디스패치)</strong></p>
</blockquote>
<br>
<br>

<hr>
<h4 id="ref">Ref.</h4>
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html">https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[상속과 메모리 구조]]></title>
            <link>https://velog.io/@falling_star3/%EC%83%81%EC%86%8D%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@falling_star3/%EC%83%81%EC%86%8D%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 19 Oct 2024 12:53:16 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-상속과-메모리-구조">📌 1. 상속과 메모리 구조</h2>
<blockquote>
<p><strong>상속 관계의 객체를 생성하면 그 내부에는 부모와 자식이 모두 생성된다.</strong></p>
</blockquote>
<pre><code class="language-java">public class Child extends Parent</code></pre>
<p>자식 클래스인 Child가 부모 클래스 Parent를 상속받은 경우를 생각해보자.
상속받는다고 해서 부모와 자식이 합쳐진 하나가 생성될 것 같지만(=내 생각), 그렇지 않다.</p>
<p>단순히 부모의 필드와 메서드만 물려 받는게 아니다. 상속 관계를 사용하면 부모 클래스도 함께 포함해서 생성된다. 외부에서 볼때는 하나의 인스턴스를 생성하는 것 같지만 <strong>내부에서는 부모와 자식이 모두 생성되고 공간도 구분된다.</strong></p>
<p>new Child()를 호출하면 Child뿐만 아니라 상속 관계에 있는 Parent까지 함께 포함해서 인스턴스를 생성한다. 참조값은 x001 로 하나이지만 실제로 그 안에서는 Parent, Child 라는 두가지 클래스 정보가 공존하는 것이다.</p>
<br>

<blockquote>
<p>💡 ** 내부에 부모와 자식이 모두 존재한다면, child.test()를 호출했을때 부모와 자식 중 어디에서 찾을 것인가?**
 ** ▶ 호출하는 변수의 타입(클래스)을 기준으로 선택한다.**</p>
</blockquote>
<br>

<pre><code class="language-java">Parent parent = new Child();
Child child = new Child();
parent.test(); //부모에서 test()호출
child.test(); //자식에서 상속받은 test()호출</code></pre>
<p>출력값이 같더라도, 어느 것을 호출했느냐는 다르다는 것이다.
위의 예제에서 child는 자식타입이 기준이니 자식에 먼저 가서 Test()를 찾고, 자식에 없으면 상속관계인 부모에게 가서 Test()를 찾을 것이다.
만약 부모에서도 해당 기능을 찾지 못하면 더 상위 부모에서 필요한 기능을 찾아본다. 부모에 부모로 계속 올라가면서 필드나 메서드를 찾는 것이다(자식 → 부모 일방통행).
물론 계속 찾아도 없으면 컴파일 오류가 발생한다.</p>
<p>** &#39;먼저&#39; 어디서 찾냐가 중요한 이유는 사용할 수 있는 메서드에 차이가 있기 때문이다.**</p>
<pre><code class="language-java">Parent parent = new Child();</code></pre>
<p>이 경우, Child에는 있고 Parent에는 없는 메서드들은 사용할 수 없다.</p>
<br>

<p>내용을 정리하면 상속의 중요한 두 가지 개념은 다음과 같다.</p>
<blockquote>
<p><strong>1. 메서드 호출 시 호출하는 변수의 타입(클래스)을 기준으로 호출
2. 메서드 상속은 일방통행 (자식 → 부모)</strong></p>
</blockquote>
<br>
<br>



<p>위의 메모리 구조는 &#39;다형성&#39;을 이해하는데도 큰 도움이 된다.</p>
<br>
<br>

<hr>
<h4 id="출처">출처</h4>
<p><a href="https://www.scaler.com/topics/runtime-polymorphism-in-java/">https://www.scaler.com/topics/runtime-polymorphism-in-java/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 정적 메서드(static)는 오버라이딩이 될까? (메서드 은닉)]]></title>
            <link>https://velog.io/@falling_star3/Java-%EC%A0%95%EC%A0%81-%EB%A9%94%EC%84%9C%EB%93%9Cstatic%EB%8A%94-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9%EC%9D%B4-%EB%90%A0%EA%B9%8C</link>
            <guid>https://velog.io/@falling_star3/Java-%EC%A0%95%EC%A0%81-%EB%A9%94%EC%84%9C%EB%93%9Cstatic%EB%8A%94-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9%EC%9D%B4-%EB%90%A0%EA%B9%8C</guid>
            <pubDate>Fri, 11 Oct 2024 20:03:11 GMT</pubDate>
            <description><![CDATA[<p>static 변수의 메모리 구조를 다시 보던 중 궁금증이 생겼다.</p>
<p>static 변수를 클래스가 아닌 인스턴스를 통해 접근하면 힙 영역에서 메서드 영역으로 리턴되어 접근한다.(지양하는 방법)
즉, 여러개의 인스턴스를 만들어도 static변수는 결국 정적 변수(프로그램 실행 시점에 딱 만들어지고, 프로그램 종료 시점에 제거되는 변수)이므로 한 곳을 바라본다.
여러개의 인스턴스를 만들어 인스턴스를 통해 접근해도, 결국 클래스를 통해 접근하는 것과 같다.
하나의 인스턴스에서 값을 변경하면, 다른 인스턴스에서의 접근도 변경된 값을 갖는다.</p>
<pre><code class="language-java">//public static int cnt = 1 일 경우

Test t1 = new Test(); 
t1.cnt = 2; 
Test t2 = new Test(); 
t2.cnt = 3;
System.out.println(t1.count); //3
System.out.println(t2.count); //3
// t1과 t2는 서로 다른 인스턴스임에도 불구하고 같은 값이 출력된다.</code></pre>
<br>

<p>💡💡💡💡💡💡💡 여기서 생긴 궁금증!
** static 변수의 값을 변경하면 위와 같은데, static 메서드를 재정의하는 경우는 어떠한가?**
상속받은 static메서드를 오버라이딩 하는 경우 말이다.</p>
<blockquote>
<p><strong>오버라이딩이란?</strong>
부모 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다.
<a href="https://velog.io/@falling_star3/Java-Ch072.-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9overriding">👉 자세히 click</a></p>
</blockquote>
<br>

<h3 id="📌--그래서-정적-메서드static는-오버라이딩이-될까-안될까">📌 !!! 그래서 정적 메서드(static)는 오버라이딩이 될까? 안될까?</h3>
<h3 id="▶-결론부터-말하자면-불가하다-static-메서드는-method-overriding-재정의이-아닌-method-hiding-은닉을-수행한다">▶ 결론부터 말하자면, 불가하다! static 메서드는 method overriding (재정의)이 아닌 method hiding (은닉)을 수행한다!</h3>
<br>


<blockquote>
<p><strong>If a subclass defines a static method with the same signature as a static method in the superclass, then the method in the subclass hides the one in the superclass.</strong></p>
</blockquote>
<blockquote>
<p><strong>자식 클래스가 부모 클래스의 정적 메서드와 동일한 시그니처를 가진 정적 메서드를 정의하는 경우, 자식 클래스에서의 메서드는 부모 클래스의 메서드를 숨긴다.</strong></p>
</blockquote>
<p>&#39;재정의&#39;가 아닌 &#39;은닉&#39;이 이루어지는 것이다.
어떤 메서드가 은닉될지는 부모 클래스에서 호출되는지 혹은 자식 클래스에서 호출되는지에 따라 다르다.</p>
<pre><code class="language-java">public class Test {

    public static void main(String[] args) {
        Parant parent1 = new Parent();
        Parant parent2 = new Child();
        Child child = new Child();

        parent1.getTest1(); //부모1 hiding 자식 메서드 은닉
        parent1.getTest2(); //부모2

        parent2.getTest1(); //부모1 hiding 자식 메서드 은닉
        parent2.getTest2(); //자식2 

        child.getTest1(); //자식1 hiding 부모 메서드 은닉
        child.getTest2(); //자식2 
    }
}

class Parent {
    public static void getTest1() {
        System.out.println(&quot;부모1&quot;);
    }

    public void getTest2() {
        System.out.println(&quot;부모2&quot;);
    }
}

class Child extends Parent {
    public static void getTest1() {
        System.out.println(&quot;자식1&quot;);
    }

    public void getTest2() {
        System.out.println(&quot;자식2&quot;);
    } 
}
</code></pre>
<p>메서드 호출이 어느 객체로 전달될지 결정하는 과정을 Method Dispatch라 한다.</p>
<ul>
<li><strong>Static Method Dispatch : 컴파일 시점에 호출되는 메서드가 결정.</strong></li>
<li><strong>Dynamic Method Dispatch : 런타임 시점에 호출되는 메서드가 결정.</strong></li>
</ul>
<p>정적(static메서드)는 컴파일시 메모리에 올라간다. 
정적 메서드는 클래스에 속한 메서드이기 때문에, 객체의 실제 타입이 아닌 참조 변수의 타입에 따라 호출된다.</p>
<p>즉, 오버라이딩처럼 런타임 시 인스턴스가 실제로 참조하고 있는 클래스를 찾아가는 것이 아니라 컴파일 시 결정된 클래스를 찾아가기 때문에 위와 같은 상황이 발생하는 것이다.</p>
<br>

<hr>
<p>이쯤 왔으면 궁금증 이 생겼을 것이다.</p>
<blockquote>
<p><strong>왜 메서드 &#39;은닉(hiding)&#39;인가?</strong></p>
</blockquote>
<p>왜 &#39;은닉&#39;이라는 표현을 쓰는지 궁금졌다.
&#39;A와 B에서 B가 A를 재정의 한 것&#39;과
&#39;A와 B에서 B가 A를 은닉 한 것&#39;은 무슨 차이가 있는가?</p>
<p><strong>&#39;재정의(overriding)&#39;는 부모 메서드를 말 그대로 다시 &#39;재정의&#39;하는 것이지만,
&#39;은닉&#39;은 자식 메서드가 새로 &#39;추가&#39;되어 부모 메서드를 &#39;은닉(hide)&#39; 시켜버리는 것이다.</strong></p>
<p>부모의 정적메서드를 자식이 재정의하려고 하면, 자식 클래스는 재정의가 아닌 부모메서드를 &#39;은닉&#39;시키고(가려버리고) 새로 &#39;추가&#39;하게 된다. 이는 새롭게 추가된 것이며 서로 구별되어 진다.</p>
<br>


<p><a href="https://velog.io/@falling_star3/%EC%83%81%EC%86%8D%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0">상속과 메모리 구조</a> </p>
<p>(상속과 메모리 구조 포스팅 작성중입니다. 이후 링크와 함께 내용추가 예정입니다. 총총..)</p>
<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://docs.oracle.com/javase/tutorial/java/IandI/override.html">https://docs.oracle.com/javase/tutorial/java/IandI/override.html</a></p>
<br>

<hr>
<h4 id="오늘의-한-줄">오늘의 한 줄</h4>
<p>새로운 시리즈 &lt;물음표 살인일지&gt;를 만들었다.
나는 주변에서 물음표 살인마로 불리는데 호기심도 많고, 궁금한건 못참기 때문...
개발하면서 가졌던 (쓸데없을수도 있는)궁금증들을 적어보고자 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[getter, setter란?(+사용하는 이유, 지양하는 이유)]]></title>
            <link>https://velog.io/@falling_star3/getter-setter%EB%9E%80%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%EC%A7%80%EC%96%91%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@falling_star3/getter-setter%EB%9E%80%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%EC%A7%80%EC%96%91%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Sun, 16 Jun 2024 10:09:45 GMT</pubDate>
            <description><![CDATA[<p>이번 포스팅은 묵히고 묵혔던 getter setter에 대한 포스팅이다.</p>
<p>업무에서 getter setter 생성을 통해 VO, DTO를 사용한다.
<em>(getter setter 생성 단축키: 이클립스 alt+shift+s / 인텔리제이 alt+insert)</em></p>
<p><strong>&#39;왜 getter setter를 사용하는가?&#39;</strong>라는 질문이 생겼다.
대충 캡슐화, 보안적인 문제라는 것은 알고 있는데 좀 더 정확하게 알기위해 포스팅 해보고자 한다.</p>
<p>여기에선 &lt;자바의 제어자&gt; 개념을 알고 있어야 하므로,
접근제어자 개념을 모른다면 하단 포스팅을 미리 보고 오는 것을 추천한다.</p>
<p><a href="https://velog.io/@falling_star3/Java-Ch074.-%EC%A0%9C%EC%96%B4%EC%9E%90modifier">[Java] Ch07_4. 제어자</a></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/4568428e-5f7e-4568-8fa2-3530eda71861/image.png" alt=""></p>
<br>


<h2 id="📌-1-getter-setter란">📌 1. getter, setter란?</h2>
<blockquote>
<p>*<em>데이터의 직접적인 접근을 막고, getter와 setter 메서드를 사용하여 데이터의 값을 꺼내오거나 수정하는 일종의 기법. *</em></p>
</blockquote>
<ul>
<li>getter: 외부에서 객체의 데이터를 읽을 때 사용하는 메서드(return값 필요)</li>
<li>setter: 외부에서 객체의 데이터를 수정할 때 사용하는 메서드(매개변수 필요)</li>
</ul>
<p>먼저 생긴걸 보자.
<img src="https://velog.velcdn.com/images/falling_star3/post/8389f360-d947-4d33-9047-8ac9df65f63f/image.png" alt=""></p>
<p>1)** 필드(멤버변수)는 private 접근제어자**를 통해 객체 외부에서 객체의 필드에 직접적으로 접근하는 것을 막는다.</p>
<p>2) <strong>getter, setter 메서드는 public 접근제어자</strong>를 통해 외부에서 접근 가능하도록 하고, getter, setter 메서드를 통해 필드값을 사용하고 수정한다.</p>
<p>3) get/set+필드이름(대문자시작)으로 명명한다.</p>
<br>


<p>외부 객체에서 getter, setter를 사용해 데이터에 접근해보자.</p>
<pre><code class="language-java">Student student = new Student();
Int age = student.getAge(); //getter를 통해 age값 가져오기.
student.setAge(5); //setter를 통해 age값 수정.</code></pre>
<p>getter메서드는 데이터를 가져와야 하므로 return이 필요하다.
setter메서드는 값을 수정해야하므로 매개변수(위의 예시에서는 5)가 필요하다.</p>
<br>
<br>

<hr>
<h2 id="📌-2-getter-setter-사용하는-이유">📌 2. getter, setter 사용하는 이유</h2>
<blockquote>
<p><strong>1. 데이터의 무결성이 지켜진다.</strong>
: getter, setter를 통해 데이터에 접근 및 생성하므로 한 번 검증하고 처리할 수 있게 된다.
(무분별한 setter는 무결성을 해칠 수 있다. 이는 아래 3번 지양하는 이유에서 설명.)</p>
</blockquote>
<blockquote>
<p><strong>2. 정보은닉이 가능하다.</strong>
: 객체의 필드를 private 접근제어자로 두면서 객체지향의 목적인 정보은닉이 가능하다.</p>
</blockquote>
<h5 id="💡-데이터의-무결성은-데이터의-정확성-일관성-유효성이-유지되는-것을-말한다">💡 데이터의 무결성은 데이터의 정확성, 일관성, 유효성이 유지되는 것을 말한다</h5>
<br>

<p>쉽게 말해, 데이터는 소중하니 중간에 메서드로 중개자를 두겠다는 것이다. (like a 부동산 중개업자)</p>
<p>아까 위의 Student클래스의 멤버변수 age가 private이 아닌 public이라고 가정해보자.</p>
<pre><code class="language-java">student.age = -30;</code></pre>
<p>이렇게 학생의 나이가 &#39;-30&#39;이라는 말도 안되는 값을 데이터에 넣게 된다.
하지만, age가 private 접근제어자이고 setter를 통해 값을 변경한다면,</p>
<pre><code class="language-java">public void setAge(int age) {
        if(age &lt; 1){
            this.age = 1;
        }else{
            this.age = age;
        }
    } </code></pre>
<p>위와같이 사전 검증을 통해 데이터를 넣을 수 있게 된다.</p>
<br>
<br>

<hr>
<h2 id="📌-3-getter-setter를-지양하는-이유">📌 3. getter, setter를 지양하는 이유</h2>
<br>

<p>위의 2번의 내용을 보며 의문이 들 것이다.
private로 정보를 은닉했는데 결국, getter와 setter를 통해 외부에서 데이터에 쉽게 접근 할 수 있다.
기껏 숨긴 필드들을 메서드라는 수단을 통해 외부로 노출시키고 있는 것이다.
이는 캡슐화를 위반한다.</p>
<p>또한, setter로 데이터를 수정하면 어떤부분을 어디서 왜 수정하는지 알 수가 없다.
그러므로 setter 메서드는 도메인의 의미나 의도를 표현하지 못하고,
도메인 로직을 도메인 객체가 아닌 응용 영역이나 표현 영역으로 분산시킨다.</p>
<p><strong>아 그럼 어쩌라고?</strong>
=&gt; 요즘엔 setter대신 의도와 목적이 명확한 메서드를 사용하는 것을 지향하는 추세이다.</p>
<p>getter, setter가 지양되는 OOP 4대원칙, SOLID 개방폐쇄원칙
그리고 이를 해결하기 위한 방법은 더 긴긴 포스팅이 될 것이므로 다음에 추가적으로 자세히 포스팅하겠다.</p>
<br>
<br>

<hr>
<h4 id="포스팅-한마디">포스팅 한마디</h4>
<p>getter setter를 수없이 쓰면서 그 의도와 목적에 대해서는 &#39;어렴풋이&#39; 알 뿐, 제대로 설명하지 못했다.
우리가 습관적으로, 자연스럽게 쓰는 것들에 대해 &#39;왜?&#39;라는 의문을 가지고, 그것에 대한 답변을 찾아갈때 비로소 &#39;코드를 짠다.&#39;라고 할 수 있는 것 같다.
꼬리의 꼬리를 무는 묵은 포스팅들이 임시저장소에 엄청 많은데 하나씩 해결해가는 재미가 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 내가 while문보다 for문을 선호하는 이유(속도, 구조 비교)]]></title>
            <link>https://velog.io/@falling_star3/JAVA-%EB%82%B4%EA%B0%80-while%EB%AC%B8%EB%B3%B4%EB%8B%A4-for%EB%AC%B8%EC%9D%84-%EC%84%A0%ED%98%B8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%86%8D%EB%8F%84-%EA%B5%AC%EC%A1%B0-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@falling_star3/JAVA-%EB%82%B4%EA%B0%80-while%EB%AC%B8%EB%B3%B4%EB%8B%A4-for%EB%AC%B8%EC%9D%84-%EC%84%A0%ED%98%B8%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0%EC%86%8D%EB%8F%84-%EA%B5%AC%EC%A1%B0-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Sat, 01 Jun 2024 08:47:58 GMT</pubDate>
            <description><![CDATA[<p>오랜만에 쓰는 포스팅이다.
Java강의를 들으며 오랜만에 쓰고 싶은 주제가 생각나 포스팅을 시작해본다.</p>
<p>코테 좀 해봤다는 사람이면, 특정한 경우를 제외하고는 효율성 테스트를 통과하기 위해 while문보다 for문을 사용할 것이다. for문이 효율성면에서 훨씬 유리하기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/d22e3722-49ac-4bd8-8867-4b07a0c92185/image.png" alt=""></p>
<blockquote>
<p><strong>결론부터 말하자면, for문이 while문보다 속도, 구조적으로 유리하다.</strong></p>
</blockquote>
<br>

<h2 id="📌-1-for문과-while문의-구조적-차이스코프-관점">📌 1. for문과 while문의 구조적 차이(스코프 관점)</h2>
<br>

<p>지역변수는 변수가 선언된 코드블록내에서만 생존한다.
자신이 선언된 코드 블록을 벗어나면 제거되어 접근할 수 없다.</p>
<p>가독성이 좋은 코드를 짜기 위해서는 변수가 생존해야하는 코드블록을 잘 파악하고 선언해야한다.
코드가 복잡할수록 고려해야할 변수가 많아지므로 변수의 적절한 선언위치는 필수적이다.</p>
<p>이제 for문과 while문의 변수 선언 위치를 살펴보자.</p>
<pre><code class="language-java">//for문
public class For2 {
 public static void main(String[] args) {
     int sum = 0;
     int endNum = 3;
    for(int i=0; i&lt;2; i++){
        sum = sum + i;
    } //for문은 초기식에 직접 변수 선언
  }
}


//while문
public class While1 {
 public static void main(String[] args) {
    int sum = 0;
    int i = 1;
    int endNum = 3;

    while (i &lt;- endNum){
        sum = sum + i;
    }
  }
}
</code></pre>
<p><strong>- for문 : 초기식에 직접 변수 선언 (변수 i의 스코프 : for문 안으로 한정)</strong>
<strong>- while문 : while 코드블록 바깥에 선언 (변수 i의 스코프 : main() 메서드 전체)</strong></p>
<blockquote>
<p><strong>따라서, 변수 i와 같이 for문안에서만 사용되는 카운터 변수가 있다면 while문보다는 for문을 사용해 스코프의 범위를 제한하는 것이 메모리 사용과 유지보수 관점에서 더 좋다.</strong></p>
</blockquote>
<br>

<p>이에 대한 차이는 코드의 복잡성이 증가할수록 더 커진다.
이제는 이로인한 속도의 차이를 알아보자.</p>
<br>
<br>


<h2 id="📌-2-for문과-while문의-속도-차이">📌 2. for문과 while문의 속도 차이</h2>
<blockquote>
<p><strong>for문이 while문보다 미세하지만, 빠른 속도를 가지고 있다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/e269a7ca-a396-43d2-8774-2e4a1eee81dd/image.png" alt=""></p>
<p>출처: <a href="https://3colored.tistory.com/5">for문과 while문의 속도 비교 실험</a></p>
<br>

<p>사실, for문과 while문의 속도 차이는 유의미다고 볼만큼 크게 나지 않는다.
그럼에도 효율성 테스트를 하나라도 더 통과해야하는 코테러에게는 유의미하다.</p>
<p>이 미세한 속도차이는 (1)에서 설명한 구조적차이에 있다.</p>
<p>for문은 초기식에 직접 변수를 선언하여 사용하므로 반복문이 끝나면 바로 할당된 메모리를 해제하는 반면 while문은 반복문에 활용되는 변수를 계속 가지고 있기 때문이다.</p>
<br>
<br>

<hr>
<h4 id="한줄메모">한줄메모</h4>
<p>java가 메모리 할당 및 자원관리에 매우 엄격한 언어인만큼(javascript는 훨씬 유연),
개발자도 이를 활용하여 효율성 및 가독성이 좋은 코드를 짜야한다는 생각이 들었다.</p>
<p>별로 중요한 내용의 포스팅은 아니지만,
이런 사소한 차이가 더 좋은 코드를 만들고, 코드가 더 복잡해질수록 중요해지는 부분이라고 생각하기 때문에 포스팅을 작성해보았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Router 라우터의 개념 및 사용법 ]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Router-%EB%9D%BC%EC%9A%B0%ED%84%B0%EC%9D%98-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Router-%EB%9D%BC%EC%9A%B0%ED%84%B0%EC%9D%98-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Sat, 27 Jan 2024 10:07:13 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-vue-router-뷰-라우터란">📌 1. Vue Router 뷰 라우터란?</h2>
<blockquote>
<p><strong>뷰 라우터는 Vue.js를 이용하여 싱글 페이지 애플리케이션(SPA)을 구현할 때 사용하는 Vue.js의 공식 라우터이다.</strong></p>
</blockquote>
<h3 id="라우터란-router"><strong>라우터란? (Router)</strong></h3>
<p>라우터라고 하면 일반적으로 네트워크간에 데이터를 전송하는 장치를 말한다. 
뷰에서 말하는 라우터는 쉽게 말해서 URL에 따라 어떤 페이지를 보여줄지 매핑해주는 라이브러리라고 보면 된다.</p>
<p>예를 들자면, ‘/home’ 경로로 요청이 들어왔을때 ‘Home.vue’ 컴포넌트를 화면에 렌더링 해주는 역할을 수행하는 라이브러리이다. </p>
<br>

<h3 id="라우트란-route">라우트란? (Route)</h3>
<p>어떤 URL에 대해 어떤 페이지를 표시해야 하는지에 대한 정보.
위의 예시에서 ‘/home’ → ‘Home.vue’와 같은 맵핑정보를 라우트(Route)라고 한다.</p>
<br>
<br>

<hr>
<h2 id="📌-2-vue-router-라우터-설정-및-사용법">📌 2. Vue Router 라우터 설정 및 사용법</h2>
<br>

<p>라우터를 설정하고 사용해보자.
요구사항은 다음과 같다.</p>
<p>&#39;/&#39; 경로가 입력되면 HomeView.vue 를 렌더링 해 줄 것이고,
&#39;/about&#39; 경로가 입력되면 AboutView.vue를 렌더링 해 줄 것이다.</p>
<ul>
<li><code>‘/’</code> → <code>HomeView.vue</code></li>
<li><code>‘/about’</code> → <code>AboutView.vue</code></li>
</ul>
<br>

<h3 id="1-라우터-설치">1) 라우터 설치</h3>
<p>먼저 라우터 라이브러리를 사용하려면 설치가 필요하다.</p>
<pre><code class="language-javascript">npm install vue-router</code></pre>
<br>

<h3 id="2-라우터-설정">2) 라우터 설정</h3>
<p>설치된 라이브러리를 사용하기 위한 설정 작업들이다.</p>
<pre><code class="language-javascript">// src/router/index.js
import { createRouter, createWebHistory } from &#39;vue-router&#39;;
import HomeView from &#39;@/views/HomeView.vue&#39;;
import AboutView from &#39;@/views/AboutView.vue&#39;;

//라우트(routes) 정의 : URL 요청에 대해 어떤 페이지(컴포넌트)를 보여줄지에 대한 매핑정보를 정의
const routes = [
  {
    path: &#39;/&#39;,
    name: &#39;home&#39;,
    component: HomeView,
  },
  {
    path: &#39;/about&#39;,
    name: &#39;about&#39;,
    component: AboutView,
  },
];
const router = createRouter({
  history: createWebHistory(&#39;/&#39;),
  routes,
});

export default router;
</code></pre>
<br>

<h3 id="3-설정한-라우터-객체를-vue-인스턴스에-추가">3) 설정한 라우터 객체를 Vue 인스턴스에 추가</h3>
<pre><code class="language-javascript">//main.js
import { createApp } from &#39;vue&#39;;
import App from &#39;./App.vue&#39;;
import router from &#39;./router&#39;;

createApp(App).use(router).mount(&#39;#app&#39;);</code></pre>
<p>app.use(router)를 호출 함으로써 컴포넌트 내부에서 $router, $route 객체에 접근할 수 있다.</p>
<br>

<h3 id="4-라우터-사용">4) 라우터 사용</h3>
<p>vue화면이 헤더와 본문으로 구성되어 있다고 가정해보자.
그렇다면 새로운 경로 요청을 할때 본문 컴포넌트(ex.TheView.vue)에 렌더링을 해주어야 한다.</p>
<pre><code class="language-html">&lt;!--TheView.vue--&gt;
&lt;template&gt;
  &lt;main&gt;
    &lt;div&gt;
     &lt;!-- &lt;h2&gt;Hello Vue3&lt;/h2&gt; 렌더링 되어야할 위치--&gt;
      &lt;RouterView&gt;&lt;/RouterView&gt;
    &lt;/div&gt;
  &lt;/main&gt;
&lt;/template&gt;
</code></pre>
<br>
<br>

<hr>
<h2 id="📌-3-vue-라우터-사용법-예시">📌 3. Vue 라우터 사용법 예시</h2>
<br>

<p>위의 2번에서 다룬 라우터 사용법은 경로(ex.menuId..)에 따라서 본문의 화면을 렌더링해주는 것으로 초기에 설정해두고 해당 코드를 많이 다루지 않는다.</p>
<p>실제 업무에서는 이벤트(버튼 클릭 등)에 따른 화면전환 즉, 실제 컴포넌트의 html과 javascript부에서 라우터를 많이 다룬다.</p>
<p>이해에는 역시 실제로 써보는게 최고다.
html과 javascript에서 라우터를 어떻게 사용하는지 예시를 들어보자.</p>
<br>

<h3 id="1-html-예시--네비게이션-기능-만들기">1) HTML 예시 : 네비게이션 기능 만들기</h3>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/45daf91f-e849-4352-9a7a-f9239f1d948b/image.png" alt=""></p>
<p>네이버뉴스에서는 위와 같은 네비게이션 바를 제공한다.
연예를 클릭하면, 연예뉴스 페이지로 이동하는 것이다.</p>
<p>이처럼 App.vue의 네비게이션 html부분에서 라우터를 사용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/b41abbed-4f1e-4fac-8fa6-3a442f63de13/image.png" alt=""></p>
<pre><code class="language-html">&lt;!-- src/App.vue --&gt;
&lt;template&gt;
  &lt;nav&gt;
    &lt;Routerlink to=&quot;/&quot;&gt;Home&lt;/Routerlink&gt; &lt;!--to에 경로를 적는다.--&gt;
    &lt;span&gt; | &lt;/span&gt;
    &lt;RouterLink to=&quot;/about&quot;&gt;About&lt;/RouterLink&gt;
  &lt;/nav&gt;
  &lt;main&gt;
    &lt;RouterView&gt;&lt;/RouterView&gt;
  &lt;/main&gt;
&lt;/template&gt;</code></pre>
<p>이제 네비게이션바 부분의 Home을 클릭하면 Home.vue로 이동하고,
About을 클릭하면 About.vue로 이동할 것이다.</p>
<h4 id="--routerlink">- <strong><code>&lt;RouterLink&gt;</code></strong></h4>
<p>Vue Router 에서는 페이지를 이동할 때는 일반 a태그를 사용하는 대신 커스텀 컴포넌트인 <code>&lt;RouterLink&gt;</code>를 사용하여 다른 페이지 링크를 만들어야 한다.</p>
<p>이를 통해 Vue Router는 페이지를 리로딩 하지 않고 URL에 매핑된 페이지를 렌더링 할 수 있다. 
=&gt; SPA를 만들 수 있다. (href는 페이지를 리로딩함)</p>
<h4 id="--routerview">- <code>&lt;RouterView&gt;</code></h4>
<p><code>&lt;RouterView&gt;</code>는 URL에 매핑된 컴포넌트를 화면에 표시한다.</p>
<br>
<br>

<h3 id="2-javascript-예시--버튼-클릭으로-화면-이동">2) Javascript 예시 : 버튼 클릭으로 화면 이동</h3>
<br>

<p>업무에서 주로 쓰는 라우터의 사용은 버튼 클릭 등의 특정 이벤트로 화면을 전환시키는 것이다.
자바스크립트에서 이를 어떻게 쓰는지 알아보자.</p>
<p>먼저 위에서 router를 설정할 때 app.use(router)를 호출했다. 
이렇게 호출 함으로써 모든 자식 컴포넌트에 router, route 같은 객체를 사용할 수 있다. 
그리고 이러한 객체는 페이지 이동 또는 현재 활성 라우트(경로 매핑)정보 에 접근하는 데 사용할 수 있다.</p>
<pre><code class="language-javascript">&lt;!-- HomeView.vue --&gt;
&lt;template&gt;
  &lt;h1&gt;Home Page&lt;/h1&gt;
  &lt;button @click=&quot;goAboutPage&quot;&gt;About 페이지로 이동&lt;/button&gt;
&lt;/template&gt;

&lt;script setup&gt;
import { useRoute, useRouter } from &#39;vue-router&#39;;

const router = useRouter(); //기능
const route = useRoute(); //정보
console.log(&#39;route.name: &#39;, route.name); // home
console.log(&#39;route.path: &#39;, route.path); // /
const goAboutPage = () =&gt; router.push(&#39;/about&#39;);
&lt;/script&gt;
</code></pre>
<p>라우트는 읽기전용의 정보이고, 라우터는 실제 기능이다.
router.push(&#39;/about&#39;)을 통해 about경로의 컴포넌트를 호출한다.</p>
<p>라우터는 많은 옵션을 가지고 있으며, 아주 다양하게 활용할 수 있다.
vue공식홈페이지에서 속성들을 살펴볼 수 있다.</p>
<p>이 외에도 route에 params 등의 파라미터를 보낼 수 있으며 쿼리나 해시로도 호출할 수 있다.</p>
<br>
<br>


<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://router.vuejs.org/guide/">vue공식홈페이지</a>
짐코딩-vue3실전편</p>
<hr>
<h4 id="오늘의-한-줄">오늘의 한 줄</h4>
<p>나의 계획했던 vue포스팅이 끝났다.
원래는 작년에 라이프사이클로 vue시리즈를 마무리하고, 2023년 회고를 작성하며 새로운 주제를 작성하려 했는데 라우터는 꼭 포스팅하고 싶어서 1월까지 넘어와서 마지막 포스트를 작성했다.
라우터는 실제 업무에서도 정말 많이 쓰이는 라이브러리이기에 원리를 잘 알고, 사용법을 익혀두는 것이 좋다.</p>
<p>프로젝트 오픈시기라 업무가 바빠 포스팅이 조금 더뎌졌지만, 
이렇게 19편의 포스트로 vue시리즈를 마무리해본다.</p>
<br>


<p>업무를 하다보면 속도를 맞춰야해서 원리나 개념, 자세한 사용법을 알고 지나가기가 어렵다.
넥사크로에서 vue전환 프로젝트를 진행하면서도 그때그때 필요할때마다 검색해 해결하느라 vue에 대해 심도있게 알긴 어려웠다.
검색해서 알게된 지식은 휘발되기 쉽고, 복사 붙여넣기를 주로하게 되는 코드들은 깊게 고민하지 않기 때문이다.</p>
<p>단순히 할 줄 아는 것 말고, 왜 그런지에 대해 답변하고 싶어 굳이 시리즈로 작성한 vue포스트는 &#39;vue를 할 줄 안다.&#39;에서 &#39;vue를 안다.&#39;로 조금은 변화시켜준 것 같다.</p>
<p>그리고 업무중 문법이나 개념을 까먹었을때 내 벨로그에 들어와 내가 포스팅 했던 글을 보러 온다.
이것이 생각보다 큰 도움이 됐다..
내가 쓴 글은 나에게 맞춤 포스팅이 돼주기 때문이다.</p>
<p>이후에는 시간이 생기면 pinia, vite, 플러그인, 커스텀 등 재밌는 주제로 간간이 올려볼 생각이다. 
개인 플젝에 vue를 붙였으니 플젝을 하면서 알게된 것들도 간간이 올릴 것이다.
<br></p>
<p>다음 시리즈의 새로운 주제로는 스프링 프로젝트/디자인패턴 포스팅을 시작하려고 한다.
최근에는 해커랭크의 sql을 공부중이라 3월에 pl/sql까지 마무리하고서야 포스팅을 시작할 수 있지 않을까 싶다.
지금 공부하는 sql은 한건한건 포스트 하긴 의미가 없어보여 이후에 하나의 포스트로 올리는게 좋을 것 같다.</p>
<br>

<p>블로그에 2023년 회고를 꼭 작성하고 싶었는데 이것도 오픈이 마무리되면 작성할 수 있을 것 같다.
어쩌다보니 2024년 첫 포스팅인데 2024년 개발도 화이팅이다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js]  Vue의 생명주기 : Lifecycle Hook]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Vue%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-Lifecycle-Hook</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Vue%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-Lifecycle-Hook</guid>
            <pubDate>Wed, 06 Dec 2023 11:29:38 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-vue의-생명주기--lifecycle">📌 Vue의 생명주기 : Lifecycle</h2>
<blockquote>
<p><strong>각각의 Vue 컴포넌트 인스턴스는 생성되고 소멸될 때 사전에 정의된 몇 단계의 과정을 거치게 되는데 이를 라이프사이클(lifecycle)이라 한다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/6f36ad9b-bfde-4318-a9f2-d125671d615f/image.png" alt=""></p>
<p><strong>라이프사이클 훅(Lifecycle hooks)은</strong> 위의 이미지와 같은 라이프사이클 단계에서 사용자가 자신의 코드를 추가할 수 있는 단계별 기능(function)이다.
즉, 라이프 사이클의 각 단계 사이사이에 실행되는 함수들을 뜻한다.</p>
<p>아래와 같이 접두사 <code>on</code>을 붙여 컴포넌트의 라이프사이클 훅에서 코드를 실행할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/be8daa96-346a-42b9-9e58-8a47f56235a0/image.png" alt=""></p>
<br>
<br>

<hr>
<h2 id="📌-lifecycle-hook-단계">📌 Lifecycle hook 단계</h2>
<blockquote>
<p><strong>Creation(생성) → Mounting(장착) → Updating(수정) → Destruction(소멸)</strong></p>
</blockquote>
<h3 id="1-creation">1) Creation</h3>
<p><strong>- vue3부터는 setup()함수로 대체</strong> -</p>
<p>*<em>컴포넌트 초기화 단계이며 <code>Creation Hooks</code>은 라이프사이클 단계에서 가장 먼저 실행된다. *</em></p>
<ul>
<li>아직 컴포넌트가 DOM에 추가되기 전이므로 DOM에 접근할 수 없다.</li>
<li>서버렌더링에서 지원되는 단계</li>
<li>클라이언트나 서버 렌더 단에서 처리해야 할 일이 있으면 이 단계에서 진행</li>
</ul>
<br>

<h4 id="beforecreate">beforeCreate</h4>
<p>컴포넌트 인스턴스가 초기화 될 때 실행된다. <code>data()</code> 또는 <code>computed</code>와 같은 다른 옵션을 처리하기 전에 즉시 호출된다.</p>
<h4 id="created">created</h4>
<p>컴포넌트 인스턴스가 초기화를 완료한 후 호출되는 훅.</p>
<h4 id="setup">setup</h4>
<p>Composition API의 <code>setup()</code> 훅은 Options API 훅 보다 먼저 호출된다.</p>
<p><code>beforeCreate</code>와 <code>created</code> 라이프사이클 훅은 Options API에서 사용하는 라이프사이클 훅으로 Vue3 Composition API를 활용하여 개발을 진행할 때는 <code>setup()</code>함수로 대체할 수 있다.</p>
<p>단계를 더 잘이해하기 위해 콘솔을 찍어보자.</p>
<pre><code class="language-javascript">export default {
  setup() {
    console.log(&#39;setup&#39;); //setup 출력
    return {};
  },
  data: () =&gt; ({
    dataMessage: &#39;data message&#39;,
  })
  beforeCreate() {
    console.log(&#39;beforeCreate&#39;, this.dataMessage); // undefined 출력
  },
  created() {
    console.log(&#39;create&#39;, this.dataMessage); //datamessge 출력
    console.log(this); // 인스턴스 접근 가능
  },

}</code></pre>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/99e5af5c-98f4-4889-8033-6dd963135916/image.png" alt=""></p>
<p>beforecreate는 인스턴스가 초기화를 완료하기 전에 실행되므로, this.dataMessage, this에 접근할 수 없다.</p>
<br>
<br>

<hr>
<h3 id="2-mounting">2) Mounting</h3>
<p><strong>DOM에 컴포넌트를 삽입하는 단계이다. <code>onBeforeMount</code>와 <code>onMounted</code>가 있다.</strong></p>
<ul>
<li>서버렌더링에서 지원되지 않는다.</li>
<li>초기 렌더링 직전에 돔을 변경하고자 한다면 이 단계에서 활용할 수 있다.</li>
</ul>
<h4 id="onbeforemount">onBeforeMount</h4>
<p>컴포넌트가 마운트되기 직전에 호출된다.</p>
<ul>
<li>대부분의 경우 사용을 권장하지 않는다.</li>
</ul>
<h4 id="onmounted">onMounted</h4>
<p>컴포넌트가 마운트된 후에 호출된다. DOM에 접근할 수 있다.</p>
<ul>
<li>모든 자식 컴포넌트가 마운트되었음을 의미합니다.</li>
<li>자체 DOM 트리가 생성되어 상위 컴포넌트에 삽입되었음을 의미한다.</li>
</ul>
<br>

<p>컴포넌트의 마운트, 돔에 접근할 수 있다는게 무슨 뜻을 의미할까?
예시를 살펴보자.</p>
<pre><code class="language-javascript">&lt;template&gt;
      &lt;div class= &quot;container&quot;&gt;
        &lt;input ref=&quot;inputRef&quot; type=&quot;text&quot; value=&quot;hello world!&quot;&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { onBeforeMount, onMounted, ref } from &#39;vue&#39;;

export default {
    setup() {
        console.log(&#39;setup&#39;);
        const inputRef = ref(null);

        onBeforeMount(() =&gt; {
            console.log(&#39;onBeforeMount&#39;, inputRef.value); //null 출력
        });
        onMounted(() =&gt; {
            console.log(&#39;onMounted&#39;, inputRef.value); //hello world! 출력
        });

          return { inputRef };
    }
}
&lt;/script&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/9f0e7296-3afc-47f5-92d2-c9a714e3f0ff/image.png" alt=""></p>
<p>onBeforeMount에서는 마운트가 완료되기전이기 때문에 돔에 접근할 수 없어 null이 출력된다.
하지만, onMounted에서는 마운트가 완료된 후라 돔의 inputRef.value에 접근할 수 있다.</p>
<p>추가적으로, create는 부모-&gt;자식순으로 완료되고, mount는 자식-&gt;부모순으로 완료된다.
즉, 부모에서 onMounted가 호출되면 모든 자식 컴포넌트가 마운트 되었을을 의미한다.</p>
<br>
<br>

<hr>
<h3 id="updating">Updating</h3>
<p><strong>반응형 상태 변경으로 컴포넌트의 DOM 트리가 업데이트된 후 호출될 콜백을 등록한다.</strong></p>
<ul>
<li>디버깅이나 프로파일링 등을 위해 컴포넌트 재 렌더링 시점을 알고 싶을 때 사용하면 된다.</li>
<li>돔에 렌더링 되지 않은 반응형 변수의 변경에는 호출되지 않는다.<pre><code class="language-html">&lt;!--message 변경될 경우 onUpdated, onBeforeUpdate호출됨--&gt;
&lt;template&gt;
  {{message}} 
&lt;/template&gt;
&lt;script setup&gt;
const message = ref(&#39;&#39;);
&lt;/script&gt;</code></pre>
</li>
</ul>
<pre><code class="language-html">&lt;!--message 변경될 경우 onUpdated, onBeforeUpdate호출되지 않음. 돔에 렌더링되어 상태변화되지 않았기때문.
--&gt;
&lt;template&gt;
    &lt;!--{{message}}--&gt; 
&lt;/template&gt;
&lt;script setup&gt;
  const message = ref(&#39;&#39;);
&lt;/script&gt;</code></pre>
<h4 id="onbeforeupdate">onBeforeUpdate</h4>
<p>반응형 상태 변경으로 컴포넌트의 DOM 트리를 업데이트하기 직전에 호출될 콜백을 등록한다.</p>
<p>컴포넌트에서 사용되는 반응형 상태 값이 변해서, DOM에도 그 변화를 적용시켜야 할 때가 있다. 이 때, 변화 직전에 호출되는 것이 바로 onBeforeUpdate 훅이다.</p>
<h4 id="onupdated">onUpdated</h4>
<p>반응 상태 변경으로 인해 컴포넌트가 DOM 트리를 업데이트한 후에 호출된다.</p>
<p>상위 컴포넌트의 <code>onUpdated</code>훅은 하위 컴포넌트의 훅 이후에 호출된다. (<code>Child</code> → <code>Parent</code>)</p>
<p>이 훅은 다른 상태 변경으로 인해 발생할 수 있는 컴포넌트의 DOM 업데이트 후에 호출된다. 특정 상태 변경 후에 업데이트된 DOM에 액세스해야 하는 경우 대신 <code>nextTick()</code>을 사용하는 것이 추천된다.</p>
<blockquote>
<p><strong>WARNING</strong>
<code>onUpdated</code> 훅에서 컴포넌트 상태를 변경하지 말자. 그러면 무한 업데이트 루프가 발생할 수 있다!</p>
</blockquote>
<pre><code class="language-javascript">// message.value = &#39;Hello World!&#39;로 데이터 변경
&lt;template&gt;
    &lt;p id=&quot;messge&quot;&gt;{{message}}&lt;/p&gt; 
&lt;/template&gt;
&lt;script setup&gt;
  const message = ref(&#39;&#39;);

  onBeforeUpdate(() =&gt; {
      console.log(&#39;onBeforeUpdate&#39;, message.value); 
    //&#39;onBeforeUpdate Hello World!&#39; 출력
    console.log(&#39;DOM Content :&#39; , document.querySelector(&#39;#message&#39;).textContent); 
    // &#39;Dom Content: &#39;출력
  });

  onUpdated(() =&gt; {
      console.log(&#39;onUpdated&#39;, message.value);
    //&#39;onUpdated Hello World!&#39; 출력
    console.log(&#39;DOM Content :&#39; , document.querySelector(&#39;#message&#39;).textContent);
    // &#39;Dom Content: Hello World!&#39;출력
  });
&lt;/script&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/ecda4392-9d97-423c-ae19-4ef3ec97468a/image.png" alt=""></p>
<p>onBeforeUpdate, onUpdated 모두 message.value는 &#39;Hello World!&#39;로 변경된 값이 출력되었다. 
다만, 돔의 document.querySelector(&#39;#message&#39;).textContent 값은 onBeforeUpdate에서는 출력되지 않았다. 돔 트리를 업데이트하기 전에 호출되기 때문이다.</p>
<p>이에 반해 onUpdated에서는 document.querySelector(&#39;#message&#39;).textContent의 값이 &#39;Hello World!&#39;로 출력되었다.
돔 트리를 업데이트 한 후 호출되기 때문이다.</p>
<br>
<br>

<hr>
<h3 id="destruction">Destruction</h3>
<p><strong>해체(소멸)단계 이며 <code>onBeforeUnmount</code>와 <code>onUnmounted</code>가 있다.</strong></p>
<h4 id="onbeforeunmount">onBeforeUnmount</h4>
<p>컴포넌트가 마운트 해제되기 직전에 호출된다.</p>
<h4 id="onunmounted">onUnmounted</h4>
<p>컴포넌트가 마운트 해제된 후 호출된다.</p>
<br>

<p>ETC</p>
<ul>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured"><code>onErrorCaptured()</code></a></strong></li>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#onrendertracked"><code>onRenderTracked()</code></a></strong></li>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#onrendertriggered"><code>onRenderTriggered()</code></a></strong></li>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#onactivated"><code>onActivated()</code></a></strong></li>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#ondeactivated"><code>onDeactivated()</code></a></strong></li>
<li><strong><a href="https://vuejs.org/api/composition-api-lifecycle.html#onserverprefetch"><code>onServerPrefetch()</code></a></strong></li>
</ul>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://vuejs.org/api/composition-api-lifecycle.html">Vue3 공식문서 - LifeCycle</a>
Vue3 기본편 - 짐코딩</p>
<hr>
<p>드디어 벼르고 벼르던 라이프 사이클 훅에 대해 다뤘다.</p>
<p>업무를 하다보면, 라이프 사이클 훅을 사용해야 하는 경우들이 종종 발생한다.
컴포넌트가 마운트 되기전에 처리해야하는 로직들도 있고, 언마운트 되기 전에 처리해야하는 경우도 있다.
생명주기를 잘 알아둬야, 필요한 순간에 적절하게 사용할 수 있다.</p>
<p>이제 정말 vue 포스팅이 얼마남지 않았다.
끝까지 화이팅!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Provide / Inject 자식의 자식의...n에게 데이터 전달하기]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Provide-Inject-yb2ciatv</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Provide-Inject-yb2ciatv</guid>
            <pubDate>Wed, 01 Nov 2023 09:54:03 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-provide--inject">📌 1. Provide / Inject</h2>
<h3 id="1-provide와-inject란">1) Provide와 Inject란?</h3>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/324a1b16-d35f-413d-8a08-a66998ac1d55/image.png" alt=""></p>
<p>부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 Props를 사용했었다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/e202f596-532f-48ce-869d-49643ef84d21/image.png" alt=""></p>
<p>그런데 위와 같이 Props의 깊이가 깊다고 가정해보자.
그것도 아주 많이 깊다고 가정해보면, 계속해서 Props로 전달하는 것은 굉장히 불편할 것이다. 중간에 있는 컴포넌트들은 그저 Props를 전달하기 위해 선언해야 할 것이다.
이렇게 하위 컴포넌트들이 전달하는 용도로만 쓰이는 과정을 Prop Drilling이라고 한다.</p>
<p>이것을 해결할 수 있는 것이 바로 Provide와 Inject이다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/e9c18fbc-f8f8-463d-8693-ad72d8166c3d/image.png" alt=""></p>
<blockquote>
<p><strong>Provide와 Inject를 사용하면, 부모 컴포넌트는 계층구조에 상관없이 자식 컴포넌트에 데이터를 전달할 수 있다.</strong></p>
</blockquote>
<br>
<br>

<hr>
<h3 id="2-provide--inject-사용법">2. Provide / Inject 사용법</h3>
<h4 id="1-provide">(1) Provide</h4>
<pre><code class="language-javascript">import { provide, ref } from &#39;vue&#39;;

export default {
  setup() {
    const message = ref(&#39;Hello World!&#39;);
    provide(&#39;message&#39;, message);
    return {
      message,
    };
  },
};</code></pre>
<ul>
<li>첫 번째 파라미터(주입할 키): <code>문자열</code> 또는 <code>Symbol</code>. 주입 키는 하위 컴포넌트에서 주입된 값을 조회하는 데 사용된다.</li>
<li>두 번째 파라미터(주입할 값): 값은 refs와 같은 반응형 데이터를 포함하여 모든 유형이 될 수 있다.</li>
</ul>
<br>

<h4 id="2-inject">(2) Inject</h4>
<pre><code class="language-javascript">import { inject } from &#39;vue&#39;;
export default {
  setup() {
    const message = inject(&#39;message&#39;);
    const appMessage = inject(&#39;appMessage&#39;);
    return {
      message,
      appMessage,
    };
  },
};</code></pre>
<p>Inject를 통해 상위 컴포넌트에서 제공한 데이터를 삽입할 수 있다.
주입된 값이 ref이면 반응형 연결을 유지할 수 있다.</p>
<p>만약에 Inject로 주입된 키가 상위 체인에서 제공된 적이 없는 경우 런타임 경고가 표시된다. 이 때 두번째 인자로 기본값(default value)를 설정할 수 있다.</p>
<pre><code class="language-javascript">const defaultMessage = inject(&#39;defaultMessage&#39;, &#39;default message&#39;);</code></pre>
<p>기본값으로 팩토리 함수를 제공할 수도 있다.</p>
<pre><code class="language-javascript">const defaultMessage = inject(&#39;defaultMessage&#39;, () =&gt; &#39;default message&#39;);</code></pre>
<br>
<br>

<hr>
<h3 id="3-반응형-데이터-제공시-주의점">3. 반응형 데이터 제공시 주의점</h3>
<p>Provide/Inject를 반응성 데이터로 제공할 때 가능한 모든 변경을 Provider 내부에서 하는 것이 좋다. 예를 들면 자식 컴포넌트에서 주입받은 값을 변경하고 싶으면, Injector 내부 컴포넌트에서 변경하지 말고 Provider에서 데이터 변경 함수를 함께 제공하는 것이 좋다.</p>
<pre><code class="language-javascript">// Provider
const message = ref(&#39;Hello World!&#39;);
const updateMessage = () =&gt; {
  message.value = &#39;world!&#39;;
};
provide(&#39;message&#39;, { message, updateMessage });</code></pre>
<pre><code class="language-javascript">// Injector
const { message, updateMessage } = inject(&#39;message&#39;);</code></pre>
<p>이렇게 Provider 내부에 배치되면 향후 유지관리가 용이하다.</p>
<p>주입된 컴포넌트에서 제공된 값을 변경할 수 없도록 하려면 readonly() 함수를 사용할 수 있다.</p>
<pre><code class="language-javascript">import { provide, readonly, ref } from &#39;vue&#39;;

provide(&#39;count&#39;, readonly(count));</code></pre>
<br>


<h3 id="4-symbol-키-사용">4. Symbol 키 사용</h3>
<p>대규모 애플리케이션에서 다른 개발자와 함께 작업할 때 잠재적 충돌을 피하기 위해 Symbol 주입 키를 사용하는 것이 가장 좋다.</p>
<pre><code class="language-javascript">// keys.js
export const myInjectionKey = Symbol()</code></pre>
<pre><code class="language-javascript">// in provider component
import { provide } from &#39;vue&#39;
import { myInjectionKey } from &#39;./keys.js&#39;

provide(myInjectionKey, {
  /* data to provide */
})</code></pre>
<pre><code class="language-javascript">// in injector component
import { inject } from &#39;vue&#39;
import { myInjectionKey } from &#39;./keys.js&#39;

const injected = inject(myInjectionKey)</code></pre>
<br>
<br>

<h3 id="5-app-level-provide">5. App-level Provide</h3>
<p>컴포넌트에서 데이터를 제공하는 것 외에도 App-level에서 제공할 수도 있다.
App컴포넌트는 모든 자식 컴포넌트의 부모 컴포넌트이므로 App-level에서 제공하면 모든 컴포넌트에서 받아 쓸 수 있다.</p>
<pre><code class="language-javascript">import { createApp } from &#39;vue&#39;;
import App from &#39;./App.vue&#39;;
const app = createApp(App);
app.provide(&#39;appMessage&#39;, &#39;Hello app message&#39;);
app.mount(&#39;#app&#39;);</code></pre>
<p>이것은 <a href="https://vuejs.org/guide/reusability/plugins.html">Plugin</a>을 작성할 때 유용하다.
Vue2에서 컴포넌트 인스턴스 객체를 추가할 때 global property에 추가 했으나, Vue3에서 Composition API Setup 함수에서는 컴포넌트 인스턴스에 접근할 수 없다.</p>
<p>이때 대신 Provide/Inject를 사용할 수 있다.</p>
<br>
<br>


<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://ko.vuejs.org/guide/components/provide-inject.html#provide">vue공식문서 Provide/Inject</a>
인프런 Vue3기본편 - 짐코딩</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Slot이란? - 컴포넌트 컨텐츠 전달]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Slot%EC%9D%B4%EB%9E%80-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%BB%A8%ED%85%90%EC%B8%A0-%EC%A0%84%EB%8B%AC</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Slot%EC%9D%B4%EB%9E%80-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%BB%A8%ED%85%90%EC%B8%A0-%EC%A0%84%EB%8B%AC</guid>
            <pubDate>Wed, 18 Oct 2023 11:06:17 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-slot">📌 Slot</h2>
<blockquote>
<p><strong>html과 마찬가지로 컴포넌트에 컨텐츠를 전달할 수 있도록 해준다.</strong></p>
</blockquote>
<p>한마디로, 특정 내용 뭉텅이를 가져다가 컴포넌트 안에 삽입시키고 싶을 때 쓰는 것이다.</p>
<p>역시 예시로 시작해보자.
FancyButton.vue를 만들었다.</p>
<pre><code class="language-html">&lt;!--fancyButton.vue--&gt;
&lt;template&gt;
  &lt;button class=&quot;fancy-btn&quot;&gt;
    &lt;!--이 안에 삽입하고 싶음--&gt;
  &lt;/button&gt;
&lt;/template&gt;</code></pre>
<p>버튼에서 보여줘야할 텍스트가 화면마다 다르다고 가정해보자. 
A화면에서는 &#39;확인&#39;이라는 텍스트를 띄울거고, B화면에서는 &#39;취소&#39;라는 텍스트를 띄우고 싶다.</p>
<p>버튼은 똑같은 버튼이지만, 버튼에 들어갈 텍스트만 달라지는 것이다. 
이 경우 사용하는 것이 바로 <code>slot</code>이다.</p>
<pre><code class="language-html">&lt;!--fancyButton.vue--&gt;
&lt;template&gt;
  &lt;button class=&quot;fancy-btn&quot;&gt;
    &lt;slot&gt;&lt;/solt&gt;
  &lt;/button&gt;
&lt;/template&gt;</code></pre>
<p>부모창에서 fancyButton.vue 버튼 컴포넌트를 불러와서 사용해보자.</p>
<pre><code class="language-html">&lt;!--theVue.vue--&gt;
&lt;template&gt;
  &lt;fancyButton&gt;확인&lt;/fancyButton&gt;
&lt;/template&gt;</code></pre>
<p>이제 &#39;확인&#39;이라는 텍스트는 fancyButton.vue의 <code>&lt;slot&gt;&lt;/slot&gt;</code> 태그를 지정해놓은 곳에 삽입된다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/2121f212-337f-4705-99e7-eb1d7b7965be/image.png" alt=""></p>
<pre><code class="language-html">&lt;!--fancyButton.vue--&gt;
&lt;template&gt;
  &lt;button class=&quot;fancy-btn&quot;&gt;
    &lt;!--&lt;slot&gt;&lt;/solt&gt;--&gt;
    확인
  &lt;/button&gt;
&lt;/template&gt;</code></pre>
<p>위와 같은 결과가 나오는 것이다.</p>
<p><strong>슬롯은 텍스트뿐만아니라 HTML요소, 컴포넌트 등 다양한 모든 컨텐츠가 될 수 있다.</strong></p>
<br>
<br>

<hr>
<h3 id="1-fallback-content">(1) Fallback Content</h3>
<blockquote>
<p><strong>상위 컴포넌트에서 슬롯 콘텐츠가 제공되지 않을때 슬롯에 대한 폴백(기본 콘텐츠)을 지정할 수 있다.</strong></p>
</blockquote>
<pre><code class="language-html">&lt;!-- FancyButton.vue --&gt;
&lt;template&gt;
  &lt;button class=&quot;btn&quot;&gt;
    &lt;slot&gt;Default Click!!&lt;/slot&gt;
  &lt;/button&gt;
&lt;/template&gt;</code></pre>
<br>

<h3 id="2-named-slots">(2) Named Slots</h3>
<blockquote>
<p><strong><code>&lt;slot&gt;</code> 요소에 이름을 부여하여 여러개의 <code>&lt;slot&gt;</code>을 정의할 수 있다.</strong></p>
</blockquote>
<pre><code class="language-html">&lt;!-- BaseCard.vue --&gt;
&lt;template&gt;
  &lt;article&gt;
    &lt;div&gt;
      &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
    &lt;/div&gt;
    &lt;div&gt;
      &lt;slot&gt;&lt;/slot&gt;
    &lt;/div&gt;
    &lt;div&quot;&gt;
      &lt;slot name=&quot;footer&quot;&gt;&lt;/slot&gt;
    &lt;/div&gt;
  &lt;/article&gt;
&lt;/template&gt;</code></pre>
<ul>
<li><code>&lt;slot&gt;</code>에 <code>name</code>속성을 부여하여 특정 슬롯 컨텐츠가 렌더링 되어야 할 위치를 설정할 수 있다.</li>
<li><code>name</code>이 없는 <code>&lt;slot&gt;</code>의 이름은 암시적으로 <code>default</code>이다.</li>
</ul>
<pre><code class="language-html">&lt;!-- 부모 컴포넌트 사용 예시 --&gt;
&lt;template&gt;
  &lt;BaseCard&gt;
    &lt;template v-slot:header&gt;제목&lt;/template&gt;
    &lt;template v-slot:default&gt;안녕하세요&lt;/template&gt;
        &lt;template v-slot:footer&gt;푸터&lt;/template&gt;
  &lt;/BaseCard&gt;
&lt;/template&gt;</code></pre>
<p>위 예시처럼 <code>name</code>이 부여된 <code>&lt;slot&gt;</code>에 컨텐츠를 전달하려면 <code>v-slot</code> 디렉티브를 사용하여 전달할 수 있다. 그리고 <code>v-slot:전달인자</code>를 사용하여 지정한 슬롯 컨텐츠에 전달할 수 있다.</p>
<p><code>v-slot</code>은 <code>#</code>으로 단축 표현할 수 있다.</p>
<pre><code class="language-html">&lt;!-- 부모 컴포넌트 사용 예시 --&gt;
&lt;template&gt;
  &lt;BaseCard&gt;
    &lt;template #header&gt;제목&lt;/template&gt;
    &lt;template #default&gt;안녕하세요&lt;/template&gt;
        &lt;template #footer&gt;푸터&lt;/template&gt;
  &lt;/BaseCard&gt;
&lt;/template&gt;</code></pre>
<p>그리고 default 슬롯은 암시적으로 처리할 수 있다.</p>
<pre><code class="language-html">&lt;!-- 부모 컴포넌트 사용 예시 --&gt;
&lt;template&gt;
  &lt;BaseCard&gt;
    &lt;template #header&gt;제목&lt;/template&gt;
        &lt;!-- 암시적으로 default slot --&gt;
        안녕하세요
        &lt;template #footer&gt;푸터&lt;/template&gt;
  &lt;/BaseCard&gt;
&lt;/template&gt;</code></pre>
<br>

<h3 id="3-dynamic-slot-named">(3) Dynamic Slot Named</h3>
<blockquote>
<p><strong><code>v-slot</code> 디렉티브 전달인자에 데이터를 바인딩하여 동적으로 변경할 수도 있다.</strong></p>
</blockquote>
<pre><code class="language-html">&lt;BaseCard&gt;
  &lt;template v-slot:[dynamicSlotName]&gt;
    ...
  &lt;/template&gt;

  &lt;!-- with shorthand --&gt;
  &lt;template #[dynamicSlotName]&gt;
    ...
  &lt;/template&gt;
&lt;/BaseCard&gt;</code></pre>
<br>

<h3 id="4-render-scope">(4) Render Scope</h3>
<blockquote>
<p><strong>슬롯 콘텐츠는 상위 컴포넌트에 정의되어 있으므로 상위 컴포넌트의 데이터 영역에 접근은 가능하지만 하위 컴포넌트의 영역에는 접근할 수 없다.</strong></p>
</blockquote>
<br>

<h3 id="5-scoped-slots">(5) Scoped Slots</h3>
<blockquote>
<p><strong>자식 컴포넌트에서 <code>&lt;slot&gt;</code> 요소를 사용할 때 props를 전달하는 것처럼 속성을 슬롯 컨텐츠에 전달할 수 있다.</strong></p>
</blockquote>
<p>(3)Render Scope에서 언급했던 것처럼  슬롯 콘텐츠는 자식 컴포넌트의 데이터에 접근할 수 없다. </p>
<p>다만, 아래와 같이 전달할 수 있다.</p>
<pre><code class="language-html">&lt;!-- MyComponent.vue --&gt;
&lt;!-- MyComponent.vue --&gt;
&lt;template&gt;
  &lt;div&gt;
    &lt;slot :text=&quot;greetingMessage&quot; :count=&quot;count&quot;&gt;&lt;/slot&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
import { ref } from &#39;vue&#39;;

export default {
  setup() {
    const greetingMessage = ref(&#39;Hello World!&#39;);
    const count = ref(1);
    return {
      greetingMessage,
      count,
    };
  },
};
&lt;/script&gt;</code></pre>
<p>default <code>&lt;slot&gt;</code>이 하나 밖에 없는 경우에는 v-slot 디렉티브를 사용하여 props를 전달 받을 수 있다.</p>
<pre><code class="language-html">&lt;MyComponent v-slot=&quot;slotProps&quot;&gt;
  {{ slotProps.text }} {{ slotProps.count }}
&lt;/MyComponent&gt;</code></pre>
<p>구조분해할당 문법으로 더 편리하게 받을 수 있다.</p>
<pre><code class="language-html">&lt;MyComponent v-slot=&quot;{ text, count }&quot;&gt;
  {{ text }} {{ count }}
&lt;/MyComponent&gt;</code></pre>
<br>

<h3 id="6-named-scoped-slots">(6) Named Scoped Slots</h3>
<p>이름이 부여된 슬롯도 유사하게 작동한다. 
<code>v-slot:name=&quot;slotProps”</code></p>
<pre><code class="language-html">&lt;MyComponent&gt;
  &lt;template #header=&quot;headerProps&quot;&gt;
    {{ headerProps }}
  &lt;/template&gt;

  &lt;template #default=&quot;defaultProps&quot;&gt;
    {{ defaultProps }}
  &lt;/template&gt;

  &lt;template #footer=&quot;footerProps&quot;&gt;
    {{ footerProps }}
  &lt;/template&gt;
&lt;/MyComponent&gt;</code></pre>
<p>참고로, 슬롯에 접근하고 싶으면 <code>$slot</code>을 이용하면 된다.</p>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://v3-docs.vuejs-korea.org/api/built-in-special-elements.html#slot">vue3 공식문서 - slot</a>
vue3 완벽마스터 - 짐코딩</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Non-Prop 속성 (fallthrough 속성)]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Non-Prop-%EC%86%8D%EC%84%B1-fallthrough-%EC%86%8D%EC%84%B1</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Non-Prop-%EC%86%8D%EC%84%B1-fallthrough-%EC%86%8D%EC%84%B1</guid>
            <pubDate>Wed, 18 Oct 2023 09:59:01 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-non-prop-속성fallthrough-속성">📌 Non-Prop 속성(fallthrough 속성)</h2>
<blockquote>
<p>*<em>Non-Prop 속성은 props 또는 event 에 명시적으로 선언되지 않은 속성 또는 이벤트이다.  (ex. class, style, id) *</em></p>
</blockquote>
<p> <a href="https://velog.io/@falling_star3/Vue.js-emit-%EC%9E%90%EC%84%B8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0%EB%8B%A4%EC%96%91%ED%95%9C-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%98%88%EC%8B%9C">이전포스팅(emits)</a>에서 &#39;왜 이벤트를 선언해야 하는가?&#39;라는 질문에 &#39;vue가 non-prop 속성에 알려진 리스너(Fallthrough)를 제외할 수 있기 때문&#39;이라고 답한적이 있다.</p>
<p>이번 포스팅은 저 문장을 이해하는 포스팅이 될 것이다.
결론은 간단해서 포스팅을 망설였으나, &#39;why&#39;에 집중하기에 포스팅을 작성해본다.</p>
<p>먼저, 당연하듯 예시부터 살펴보겠다.
<code>LabelInput.vue</code>라는 자식 컴포넌트가 있고, 이를 부모 컴포넌트에서 다음과 같이 사용했다고 가정해보자.</p>
<pre><code class="language-html">&lt;!--부모 컴포넌트--&gt;
&lt;LabelInput label=&quot;이름&quot; class=&quot;non-class&quot; style=&quot;color: red&quot;&gt;</code></pre>
<p>자식 컴포넌트의 이벤트 선언 부분을 살펴보자.</p>
<pre><code class="language-javascript">export default{
    props:[&#39;label&#39;]
}
</code></pre>
<p><code>label</code>은 props에 선언되어 있지만, <code>class</code>와 <code>style</code>은 props에 선언되어 있지 않다. 이때 선언되어 있지 않은 <code>class</code>와 <code>style</code>같은 속성 또는 이벤트를 Non-prop 속성이라 한다.</p>
<p>그럼 이 속성들은 어떻게 될까?
루트 요소의 속성에 자동으로 추가된다. 속성 상속이 이루어지는 것이다.</p>
<br>

<hr>
<h3 id="1-속성-상속">1. 속성 상속</h3>
<blockquote>
<p><strong>Non-prop 속성은 루트요소에 자동으로 추가된다.</strong></p>
</blockquote>
<h4 id="class-style-속성-병합">class, style 속성 병합</h4>
<p>만약, 자식 컴포넌트 루트요소에 이미 <code>class</code>와 <code>style</code> 속성이 정의되어 있으면, 부모로부터 받은 <code>class</code>와 <code>style</code> 속성과 병합한다.</p>
<p>이 외는 덮어씌운다.</p>
<h4 id="v-on-이벤트-리스너-상속">v-on 이벤트 리스너 상속</h4>
<pre><code class="language-html">&lt;labelInput @click=&quot;onClick&quot;&gt;</code></pre>
<p><code>@click</code> 리스너는 <code>&lt;labelInput&gt;</code> 컴포넌트 루트요소에 추가된다.
만약 루트요소에 이미 바인딩된 이벤트가 있다면 두 리스너 모두 트리거 된다.</p>
<p>여기서 주의해야할 점은, <u>루트요소에 추가된다는 것이다.</u>
루트요소에 이벤트가 추가되면 의도치 않은 상황이 발생할 수 있다.</p>
<p>예를 들어, 자식 컴포넌트 labelInput.vue가 다음과 같이 작성되어 있다고 가정해보자.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div class=&quot;bg-danger&quot;&gt;
    &lt;button type=&quot;button&quot;&gt;버튼&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>부모컴포넌트에서 상속받은 non-props 이벤트리스너 <code>@click=&quot;onClick&quot;</code>은 루트요소인 <code>&lt;div class=&quot;bg-danger&quot;&gt;</code>에 상속될 것이다.</p>
<p>즉, 나는 버튼을 클릭했을 때만 이벤트를 실행시키고 싶은데 <code>&lt;div&gt;</code>영역을 클릭하면 이벤트가 실행되는 현상이 나타나는 것이다.</p>
<p>어떻게 해결해야할까? 이때 필요한것이 속성 상속의 비활성화이다.</p>
<br>

<hr>
<h3 id="2-속성-상속-비활성화">2. 속성 상속 비활성화</h3>
<blockquote>
<p><strong>컴포넌트가 자동으로 Non-Prop 속성을 상속하지 않도록 하기위해 컴포넌트의 inheritAttrs: false 옵션을 설정할 수 있다.</strong></p>
</blockquote>
<pre><code class="language-javascript">&lt;script&gt;
export default {
  inheritAttrs: false,
};
&lt;/script&gt;</code></pre>
<p>컴포넌트에 Non-Prop 속성을 비활성화 하는 일반적인 경우는 자식 컴포넌트의 루트요소에 이외의 다른 요소에 Non-Prop 속성을 적용하고 싶을 때이다.</p>
<p>그리고 적용해야하는 요소에 <code>&lt;template&gt;</code>에서 Non-Prop속성에 접근할 수 있는 내장 객체 <code>$attrs</code>로 직접 접근할 수 있다.</p>
<p><code>$attrs</code> 객체에는 컴포넌트에 선언되지 않은 모든 속성 props, emits (ex. class, style, v-on 등)을 포함하고 있다.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;
    &lt;button v-bind=&quot;$attrs&quot;&gt;버튼&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>스크립트 셋업에서는 context로 접근할 수 있다.</p>
<pre><code class="language-javascript">&lt;script&gt;
export default(){
    inheritAttrs: false,
    setup(props, context){
        console.log(context.attrs);
        console.log(context.attrs.class);
        console.log(context.attrs.onClick);
    }
}
&lt;/script&gt;</code></pre>
<br>

<p>💡 <strong>주의사항</strong></p>
<ul>
<li><p>props와 달리 Non-Prop 속성은 JavaScript에서 원래 대소문자를 유지하므로 foo-bar와 같은 속성은 대괄호를 사용하여 <code>$attrs[’foo-bar’]</code>로 접근해야 한다.</p>
</li>
<li><p>@click과 같은 v-on리스너는 <code>$attrs.onClick</code>과 같이 함수로 접근할 수 있다.</p>
</li>
</ul>
<br>
<br>

<hr>
<h3 id="3-여러-루트노드의-속성-상속">3. 여러 루트노드의 속성 상속</h3>
<blockquote>
<p><strong>Vue3에서는 다중 루트 노드 컴포넌트인 fragments를 공식 지원한다.</strong></p>
</blockquote>
<p>vue2에서는 다중 루트 노드가 지원되지 않아서 단일 <code>&lt;div&gt;</code>로 감싸야했다.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;div&gt;
      &lt;header&gt;...&lt;/header&gt;
    &lt;main&gt;...&lt;/main&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<p>하지만, vue3부터는 다중 루트 노드를 가질 수 있다.
다만, 속성을 배포(상속)해야 하는 위치를 명시적으로 정의해야한다. (non-props 속성을 어느 루트에 상속해야 하는지 알지 못하기 때문)</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;header&gt;...&lt;/header&gt;
  &lt;main v-bind=&quot;$attrs&quot;&gt;...&lt;/main&gt;
  &lt;footer&gt;...&lt;/footer&gt;
&lt;/template&gt;</code></pre>
<p>단일 루트 요소가 있는 컴포넌트와 달리 여러 루트 요소가 있는 컴포넌트에는 자동으로 Non-Prop 속성이 상속되지 않는다. 
만약 명시적으로 <code>$attrs</code>를 바인딩 하지 않을 경우 런타입 경고가 발생된다.</p>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://v3-docs.vuejs-korea.org/guide/components/attrs.html#attribute-inheritance">vue3 공식문서 fallthrough</a>
vue3 완벽마스터 - 짐코딩</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] 컴포넌트에 v-model 적용하기]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90-v-model-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@falling_star3/Vue.js-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90-v-model-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 20 Sep 2023 11:09:23 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-컴포넌트에-v-model-만들기">📌 컴포넌트에 v-model 만들기</h2>
<h3 id="1-기본-동작-및-예시">1. 기본 동작 및 예시</h3>
<blockquote>
<p><strong>컴포넌트를 만든 후 해당 컴포넌트에 <code>v-model</code>을 적용하려면 <code>@update:modelValue</code> 이벤트를 사용하여 <code>v-model</code>을 만들 수 있다.</strong></p>
</blockquote>
<p>컴포넌트에 <code>v-model</code>을 적용한다는게 무슨말이냐면,
우리가 기본적으로 v-model로 반응형 변수를 양방향 바인딩 시켰던것처럼, 
import해서 쓰는 컴포넌트에서도 양방향 바인딩을 적용하고 싶다는 것이다.</p>
<p>우리가 이름을 쓰는 창을 A컴포넌트로 만들고 부모창에서 A를 불러와서 썼다고 가정해보자.
<img src="https://velog.velcdn.com/images/falling_star3/post/a6095f66-1ddb-4b0f-89bf-bc0bb7662375/image.png" alt=""></p>
<p>A컴포넌트에서 입력되는 &#39;123123124&#39;라는 값이 <code>v-model</code>처럼 부모창의 반응형 변수 <code>username</code>과 양방향 바인딩 되길 바란다.</p>
<p>이 때 필요한것이 컴포넌트에 <code>v-model</code>을 적용하는 것이다.</p>
<pre><code class="language-html">&lt;LabelInput label=&quot;이름&quot; v-model=&quot;username&quot; /&gt;</code></pre>
<p>지금부터 그 방법을 알아보자. 먼저 내부동작부터 살펴보겠다.</p>
<br>
<br>

<p>기본적으로 <code>v-model</code>은 html요소인 <code>&lt;input&gt;</code>태그에서 사용한다.</p>
<pre><code class="language-html">&lt;input v-model=&quot;username&quot; /&gt;</code></pre>
<p>위의 <code>v-model</code>은 다음과 같은 내부동작을 가지고 있다.</p>
<pre><code class="language-html">&lt;input
  :value=&quot;username&quot;
  @input=&quot;username = $event.target.value&quot;
/&gt;</code></pre>
<p>위의 기본동작 대신 우리가 만든 컴포넌트는 다음과 같이 수행할 것이다.</p>
<pre><code class="language-html">&lt;LabelInput
    :modelValue=&quot;username&quot;
    @update:modelValue=&quot;newValue =&gt; username = newValue&quot;
/&gt;</code></pre>
<p>부모에서<code>Props</code>로 <code>modelValue</code>를 넘겨주고,<code>event</code>로 <code>update</code>를 받는다.</p>
<br>
<br>

<p>이해가 쉽지않다.
예시로 하나하나 설명해보겠다.</p>
<p>예를들어 자식컴포넌트 LabelInput이 있다고 가정해보자.</p>
<pre><code class="language-html">&lt;!--LabelInput 컴포넌트 --&gt;
&lt;template&gt;
  &lt;label&gt;
    {{ label }}
    &lt;input
      type=&quot;text&quot;
      :value=&quot;modelValue&quot;
      @input=&quot;$emit(&#39;update:modelValue&#39;, $event.target.value)&quot;
    /&gt;
  &lt;/label&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
export default {
  props: [&#39;modelValue&#39;, &#39;label&#39;],
  emits: [&#39;update:modelValue&#39;],
};
&lt;/script&gt;</code></pre>
<ul>
<li><code>props</code>의 <code>modelValue</code>를 <code>:value</code>속성에 바인딩 해줬다.</li>
<li><code>@input</code> 이벤트에서 새 <code>update:modelValue</code> 이벤트로 내보낸다.</li>
</ul>
<p>컴포넌트는 다 만들었다.
이제 부모창에서 <code>LabelInput</code> 컴포넌트를 불러와서 써보자.</p>
<pre><code class="language-html">&lt;!-- TheView 부모 컴포넌트 --&gt;
&lt;LabelInput
    v-model:modelValue=&quot;username&quot;
    @update:modelValue=&quot;newValue =&gt; username = newValue&quot;
/&gt;</code></pre>
<p>이제 컴포넌트에 <code>v-model</code>이 연동되었다.</p>
<p>전체적인 기작을 정리해보자.</p>
<p>① 부모 컴포넌트에서 자식 컴포넌트에게<code>props</code>로 modelValue=&quot;username&quot;을 
  보낸다.
② 자식 컴포넌트에서 <code>props</code>로 받은 <code>modelValue</code>를 <code>&lt;input&gt;</code>태그에<br>  :value=&quot;modelValue&quot;로 연결한다.
③ 자식 컴포넌트에서 입력된 값이 <code>@input</code> 이벤트를 통해 부모로 보내진다.
  <code>update:modelValue</code>로 <code>$event.target.value</code>를 내보낸다.
④ 부모 컴포넌트는 받은 파라미터 값으로 <code>username</code>을 업데이트 시킨다.
  @update:modelValue=&quot;newValue =&gt; username = newValue&quot;</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/3684f2d1-fa54-491b-84b4-65406e8bba03/image.png" alt=""></p>
<p>⑤ 위와같이 이름을 입력하는 창이 자식 컴포넌트 창이라면,
  자식컴포넌트 인풋창에 입력한 값이 부모컴포넌트의 <code>username</code>에 <code>v-model</code>로 바인딩 된 것처럼 동작을 할 것이다.</p>
<p>  이것이 바로 컴포넌트에 <code>v-model</code>을 적용한 것이다.</p>
<br>
<br>

<hr>
<h3 id="2-컴포넌트에-v-model-적용하기">2. 컴포넌트에 v-model 적용하기</h3>
<pre><code class="language-html">&lt;LabelInput
    :modelValue=&quot;username&quot;
    @update:modelValue=&quot;newValue =&gt; username = newValue&quot;
/&gt;</code></pre>
<p>위의 코드를 다음과 같이 <code>v-model</code>로 바꿀 수 있다.</p>
<pre><code class="language-html">&lt;LabelInput v-model=&quot;username&quot; label=&quot;이름&quot; /&gt;</code></pre>
<h4 id="computed-이용하기">Computed 이용하기</h4>
<p>컴포넌트 안에서 computed를 사용하여 <code>v-model</code>을 구현할 수 있다.
이 경우, 템플릿의 코드가 훨씬 간단해진다.</p>
<pre><code class="language-html">&lt;!--LabelInput 컴포넌트 --&gt;
&lt;template&gt;
  &lt;label&gt;
    {{ label }}
    &lt;input v-model=&quot;value&quot; type=&quot;text&quot; /&gt;
  &lt;/label&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
export default {
  props: [&#39;modelValue&#39;, &#39;label&#39;],
  emits: [&#39;update:modelValue&#39;],

  setup(props, { emit }){
      const vaue = computed({
        get(){
            return props.modelValue;
        },
        set(value){
            emit(&#39;update:modelValue&#39;, value);
        },
    });
    return { value };
  }
};
&lt;/script&gt;</code></pre>
<br>
<br>

<hr>
<h3 id="3-v-model-전달인자">3. v-model 전달인자</h3>
<h4 id="1-이름-수정">1) 이름 수정</h4>
<p>기본적으로 <code>v-model</code>은 컴포넌트에서 <code>modelValue</code> props와 <code>update:modelValue</code> 이벤트로 사용한다.
하지만 전달인자를 사용하여 이름을 수정할 수 있다.</p>
<pre><code class="language-html">&lt;LabelInput v-model:title=&quot;username&quot; label=&quot;이름&quot; /&gt;</code></pre>
<p>이 경우 자식 컴포넌트에서는 <code>:title</code>을 속성으로 정의하고 <code>update:title</code>로 이벤트를 내보내야 한다.</p>
<pre><code class="language-html">&lt;!--LabelInput 컴포넌트 --&gt;
&lt;template&gt;
  &lt;label&gt;
    {{ label }}
    &lt;input v-model=&quot;value&quot; type=&quot;text&quot; /&gt;
  &lt;/label&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
export default {
  props: [&#39;title&#39;, &#39;label&#39;],
  emits: [&#39;update:title&#39;],

  setup(props, { emit }){
      const vaue = computed({
        get(){
            return props.title;
        },
        set(value){
            emit(&#39;update:title&#39;, value);
        },
    });
    return { value };
  }
};
&lt;/script&gt;</code></pre>
<h4 id="2-다중-v-model-바인딩">2) 다중 v-model 바인딩</h4>
<p><code>v-model</code> 전달인자를 사용하여 컴포넌트에 여러 <code>v-model</code>을 바인딩할 수 있다.</p>
<pre><code class="language-html">&lt;LabelInput v-model:title=&quot;title&quot; 
            v-model:author=&quot;author&quot; /&gt;</code></pre>
<p>이제 <code>LableInput</code>컴포넌트를 보자.</p>
<pre><code class="language-html">&lt;!--LabelInput 컴포넌트 --&gt;
&lt;template&gt;
  &lt;div&gt;
    &lt;input
      type=&quot;text&quot;
      :value=&quot;title&quot;
      @input=&quot;$emit(&#39;update:title&#39;, $event.target.value)&quot;
    /&gt;
  &lt;/div&gt;
  &lt;div&gt;
    &lt;input
      type=&quot;text&quot;
      :value=&quot;author&quot;
      @input=&quot;$emit(&#39;update:author&#39;, $event.target.value)&quot;
    /&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
export default {
  props: [&#39;title&#39;, &#39;author&#39;],
  emits: [&#39;update:title&#39;, &#39;update:author&#39;],
};
&lt;/script&gt;</code></pre>
<h4 id="3-v-model-수식어modifiers핸들링">3) v-model 수식어(Modifiers)핸들링</h4>
<p>필요에 따라 v-model 수식어를 추가할 수 있다. 
예를 들어 첫 글자를 대문자로 표시하는 capitalize 라는 수식어를 만들어 보자.</p>
<pre><code class="language-html">&lt;CustomInput v-model.capitalize=&quot;username&quot;&gt;&lt;/CustomInput&gt;</code></pre>
<p>컴포넌트에 추가된 수식어는 modelModifiers prop을 통해 컴포넌트에 전달된다. 
이제 이벤트를 내보내기 전에 문자열 첫 글자를 대문자로 만들면된다.</p>
<pre><code class="language-javascript">&lt;template&gt;
  &lt;input type=&quot;text&quot; :value=&quot;modelValue&quot; @input=&quot;emitValue&quot; /&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
  props: {
    modelValue: String,
    modelModifiers: { default: () =&gt; ({}) },//기본값이 빈 객체인 modelModifiers props
  },
  emits: [&#39;update:modelValue&#39;],
  setup(props, { emit }) {
    const emitValue = (e) =&gt; {
      let value = e.target.value;
      if (props.modelModifiers.capitalize) {//수식어가 넘어오면 true
        value = value.charAt(0).toUpperCase() + value.slice(1);
      }
      emit(&#39;update:modelValue&#39;, value);
    };
    return {
      emitValue,
    };
  },
};
&lt;/script&gt;</code></pre>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p>vue3 완벽마스터-짐코딩
<a href="https://vuejs.org/guide/components/props.html">vue3 공식문서</a>
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] emit 자세히 살펴보기(다양한 사용법, 예시)]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-emit-%EC%9E%90%EC%84%B8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0%EB%8B%A4%EC%96%91%ED%95%9C-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%98%88%EC%8B%9C</link>
            <guid>https://velog.io/@falling_star3/Vue.js-emit-%EC%9E%90%EC%84%B8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0%EB%8B%A4%EC%96%91%ED%95%9C-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%98%88%EC%8B%9C</guid>
            <pubDate>Sat, 02 Sep 2023 11:07:01 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@falling_star3/Vue.js-Props-Emits-%EB%B6%80%EB%AA%A8%EC%9E%90%EC%8B%9D-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC">이전 포스팅</a>에서 <code>props</code>와 <code>emit</code>에 대해 다뤘다.
이번 포스팅에서는 그 중 <code>emit</code>에 대해 좀 더 자세히 다뤄보겠다.</p>
<br>

<h2 id="📌-emit-이벤트-내보내기">📌 emit 이벤트 내보내기</h2>
<h3 id="1-이벤트-발신수신">1. 이벤트 발신/수신</h3>
<blockquote>
<p><strong>자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달 또는 트리거의 목적으로 이벤트를 내보낼 수 있다. 이벤트는 컴포넌트의 emit 메서드를 통하여 발생시킬 수 있다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/1a053b31-3b29-4856-b7a0-56aa3f0f62f9/image.png" alt=""></p>
<p>컴포넌트의 <code>&lt;template&gt;</code> 블록 안에서 내장 함수 $emit()을 사용하여 직접 커스텀한 이벤트를 내보낼 수 있다.</p>
<p>예시를 살펴보자.</p>
<h4 id="✨-예제-1">✨ 예제 1</h4>
<pre><code class="language-html">&lt;!-- PostCreate.vue 자식 컴포넌트 --&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;button @click=&quot;$emit(&#39;createPost&#39;&quot;&gt;&lt;/button&gt; &lt;!-- 자식에서 부모로 이벤트 &#39;createPost&#39;내보내기 --&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-html">&lt;!-- TheView.vue 부모 컴포넌트 --&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;PostCreate @create-post=&quot;callFunction&quot; &gt;&lt;/PostCreate&gt; &lt;!-- 부모에서 이벤트 수신 --&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
  const callFunction = () =&gt; {
      console.log(&#39;이벤트 수신&#39;);
  }
&lt;/scritp&gt;</code></pre>
<p>단계는 다음과 같다.</p>
<p>(1) 버튼 클릭 이벤트 발생 <code>$emit(&#39;createPost&#39;)</code> 실행
(2) 자식 -&gt; 부모 &#39;createPost&#39; 이벤트 내보냄
(3) 부모에서 @create-post로 이벤트 수신하고 callFunction 함수 실행
(4) 콘솔창에 &#39;이벤트 수신&#39; 출력됨.</p>
<br>

<p>여기서 잠깐, 이상한 점을 발견할 수 있다.
자식에서 보낸 이벤트는 &#39;createPost&#39;로 카멜케이스였지만, 부모에서는 &#39;create-post&#39; 케밥케이스로 수신했다.</p>
<p>이게 가능한 것일까?
가능하다. 심지어 추천되는 방법이다.</p>
<h4 id="💡-자식은-카멜케이스로-발신-부모는-케밥케이스로-수신">💡 자식은 카멜케이스로 발신, 부모는 케밥케이스로 수신</h4>
<blockquote>
<p><strong>자식에서 카멜케이스 형식으로 이벤트를 발신했지만, 부모에서 케밥케이스 표기로 리스너를 사용하여 이를 수신할 수 있다.</strong></p>
</blockquote>
<p><code>@</code>는 <code>v-on</code>이다. <code>v-on</code>이벤트리스너는 항상 자동으로 소문자 변환을 하기때문에 &#39;createPost&#39;가 아닌 &#39;createpost&#39;로 변환된다. 이러한 변환 과정으로 인해 카멜케이스는 호출에 있어 문제를 발생시킬 수 있다.</p>
<p>따라서, 리스너 이벤트 이름은 케밥케이스로 작성하는 것이 좋다.</p>
<br>
<br>

<hr>
<h3 id="2-이벤트-파라미터">2. 이벤트 파라미터</h3>
<blockquote>
<p><strong>이벤트와 함께 특정 값을 내보낼 수 있다. 
<code>$emit</code> 함수 이벤트명에 추가로 파라미터를 넘길 수 있다.</strong></p>
</blockquote>
<br>

<h4 id="✨-예제-2">✨ 예제 2</h4>
<pre><code class="language-html">&lt;!-- PostCreate.vue 자식 컴포넌트 --&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;button @click=&quot;$emit(&#39;createPost&#39;, &#39;토끼는&#39;, &#39;개발개발&#39;&quot;&gt;&lt;/button&gt; &lt;!-- 자식에서 부모로 이벤트 &#39;createPost&#39;내보내기 --&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-html">&lt;!-- TheView.vue 부모 컴포넌트 --&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;PostCreate @create-post=&quot;callFunction&quot; &gt;&lt;/PostCreate&gt; &lt;!-- 부모에서 이벤트 수신 --&gt;
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
  const callFunction = (word1, word2) =&gt; {
      console.log(word1, word2); // 토끼는 개발개발 출력
  }
&lt;/scritp&gt;</code></pre>
<p><code>예제2</code>처럼 컴포넌트 내장메서드 <code>$emit</code>을 사용할 수도 있고,
<code>setup</code>함수의 <code>context.emit</code>을 사용하여 스크립트에서 처리할 수도 있다.</p>
<h4 id="✨-예제-3">✨ 예제 3</h4>
<pre><code class="language-html">&lt;!-- PostCreate.vue 자식 컴포넌트 --&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;button @click=&quot;createPost&quot;&gt;&lt;/button&gt; 
  &lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
export default{
  setup(props, {emit}){ //context.emit 구조분해할당
    const createPost = () =&gt; {
        emit(&#39;createPost&#39;, &#39;토끼는&#39;, &#39;개발개발&#39;);
    }
    return { createPost};
  }
}
&lt;/scritp&gt;</code></pre>
<br>
<br>

<hr>
<h3 id="3-이벤트-선언">3. 이벤트 선언</h3>
<blockquote>
<p><strong>vue3에서는 <code>emits</code> 옵션을 사용하여 이벤트를 선언할 수 있다.
이벤트 선언 방법에는 (1) 문자열 배열 선언, (2) 객체 문법 선언 두 가지 형식이 있다.</strong></p>
</blockquote>
<h4 id="1-문자열-배열-선언">(1) 문자열 배열 선언</h4>
<p><code>emits</code>에 이벤트를 문자열 배열로 선언하였다.</p>
<h4 id="✨-예제-4">✨ 예제 4</h4>
<pre><code class="language-javascript">&lt;script&gt;
export default{
  emits: [&#39;createPost&#39;]
  setup(props, {emit}){ //context.emit 구조분해할당
    emit(&#39;createPost&#39;, &#39;토끼는&#39;, &#39;개발개발&#39;);
  }
}
&lt;/scritp&gt;</code></pre>
<br>

<h4 id="2-객체-문법-선언">(2) 객체 문법 선언</h4>
<p>객체문법으로 선언할 경우 validation 로직을 추가할 수 있다. 만약 validation이 없다면 null로 설정하면 된다.</p>
<h4 id="✨-예제-5">✨ 예제 5</h4>
<pre><code class="language-javascript">&lt;script&gt;
export default{
  emits: {
          // 유효성 검사가 없는 이벤트 선언
          createPost: null,

          // 유효성 검사가 있는 이벤트 선언
          createPost: newTitle =&gt; {
              console.log(newTitle);
              if(!newTitle){
                  return false;
              }
              return true;
          }
        }
    },
  setup(props, {emit}) {
    context.emit(&#39;createPost&#39;, &#39;토끼는&#39;, &#39;개발개발&#39;)
  }
}
&lt;/scritp&gt;</code></pre>
<br>

<p>이벤트 선언 방법 두 가지에 대해 알아봤다.
자, 그럼 이제 의문점이 하나 생겼을 것이다.</p>
<h4 id="왜-이벤트를-선언해야-하는가">&quot;왜 이벤트를 선언해야 하는가?&quot;</h4>
<p>선언하지 않아도 잘 돌아가는데 왜 <code>emits</code>로 이벤트를 선언해야 하는지에 대한 의문 말이다.</p>
<p>선택사항이겠지만, 다음과 같은 이유가 있다.
① 컴포넌트가 작동하는 방식을 더 잘 문서화 하기 위해
② 또한, vue가 non-prop 속성에 알려진 리스너(Fallthrough)를 제외할 수 있다.</p>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://ko.vuejs.org/guide/components/events.html#emitting-and-listening-to-events">vue공식문서</a>
vue3 완벽정리(기본편) - 짐코딩</p>
<hr>
<h4 id="오늘의-한-줄">오늘의 한 줄</h4>
<p>이벤트 선언 부분에서, 이벤트를 선언하지 않아도 잘 돌아가는데 &#39;왜 이벤트를 선언해야하는가?&#39;에 대한 답으로 컴포넌트의 문서화를 답했다.</p>
<p>컴포넌트의 문서화, 다시 말해 읽기 편하고 유지보수가 쉬운 코드.
내가 실무에서 nexacro -&gt; vue 전환 프로젝트에서&lt;개발 표준&gt;에 대해 고민하며 굉장히 중요하다고 생각했던 부분이다.
전환 프로젝트뿐만 아니라 모든 업무에 있어서도 중요하다고 생각하는 부분이다.</p>
<p>개발을 혼자 공부하던 취준생 시절 &#39;가독성이 좋은 코드&#39;, &#39;유지보수가 쉬운 코드&#39;에 대해 대충 감으로만 느꼈었는데 이게 얼마나 중요한지 개발 업무를 하며 깨달았다.</p>
<p>단순히, 짧고 간결한 코드가 좋은 코드가 아니다.
<strong>타개발자가 내 코드를 봤을 때 얼마나 직관적으로 빠르고 명료하게 그 컴포넌트의 기능과 구현을 읽어낼 수 있느냐가 포인트다.</strong></p>
<p>특정 기능을 수정해야 할 때 그 기능들이 어디에 어떻게 구현되어 있으며 선언된 변수들과 함수들은 어떤 역할을 하고있는지 명확하게 파악할 수 있는 것이 진짜 좋은 코드라고 생각한다.</p>
<p>아 이거 정말 중요하다.
나만 볼 수 있는 구조와 명명으로 나만 편하게 작성해놓으면
내 코드를 수정하러 온 동료는 매우 빡이 칠 것이다.</p>
<p>내 동료를 화나게 하지말자..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Props, Emit 부모·자식 컴포넌트 데이터 전달(사용법)]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Props-Emits-%EB%B6%80%EB%AA%A8%EC%9E%90%EC%8B%9D-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Props-Emits-%EB%B6%80%EB%AA%A8%EC%9E%90%EC%8B%9D-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A0%84%EB%8B%AC</guid>
            <pubDate>Thu, 31 Aug 2023 16:54:59 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-props">📌 1. Props</h2>
<h3 id="1-1-props란">1-1. props란?</h3>
<blockquote>
<p><strong>컴포넌트에 등록할 수 있는 <u>사용자 정의 속성</u>.
간단히 말하면, 자식 컴포넌트에서 props를 선언하면 부모 컴포넌트에서 데이터(속성)를 전달할 수 있다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/b50fcbae-d341-4aaf-9286-f3dd940b001c/image.png" alt=""></p>
<p>위의 그림을 통해 직관적으로 알 수 있다.
부모 컴포넌트의 데이터를 자식 컴포넌트로 전달시키는 역할이다.</p>
<p>쉽게 예시 먼저 살펴보자.</p>
<pre><code class="language-html">&lt;!-- 부모 컴포넌트 TheView.vue--&gt;
&lt;template&gt;
  &lt;AppCard title=&quot;제목1&quot; contents=&quot;내용1&quot;&gt;             &lt;/AppCard&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-html">&lt;!--자식 컴포넌트 AppCard.vue--&gt;
&lt;template&gt;
  &lt;p&gt; {{ title }} &lt;/p&gt; &lt;!--제목1--&gt; 
  &lt;p&gt; {{ contents }} &lt;/p&gt; &lt;!--내용1--&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script setup&gt;
  export default {
    props: [&#39;title&#39;, &#39;contents&#39;],
    setup() {
      return {}
    }
  }
&lt;/script&gt;
</code></pre>
<p>부모 컴포넌트 <code>TheView.vue</code>에서 자식 컴포넌트인 <code>AppCard.vue</code>에 title, contents 데이터를 전달했고,
자식 컴포넌트인 <code>AppCard.vue</code>에서 <code>props</code>를 선언하여 전달 받았다.</p>
<p>이처럼, <code>Props</code>는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 쓰인다.</p>
<br>
<br>

<h3 id="1-2-props-객체문법-선언추천">1-2. Props 객체문법 선언(추천!)</h3>
<p>1-1처럼 문자열 배열을 사용하여 <code>props</code>를 선언할 수도 있지만, 객체 문법을 사용하여 속성 타입과 함께 선언할 수도 있다.</p>
<pre><code class="language-javascript">//자식 컴포넌트 AppCard.vue
export default {
  props: {
    title: {
      type: String,
      default: &#39;news&#39;
    },
    contents: {
      type: String,
      required: true 
    }
  },
  setup(){
      return {}
  }
}</code></pre>
<p>데이터의 타입과 옵션을 설정해주므로 더욱 추천되는 방법이다.</p>
<ul>
<li><code>type</code> : <code>String</code>, <code>Number</code>, ... 모든 기본 생성자 또는 모든 사용자 정의 타입이 올 수 있다. 배열을 이용하여 여러개의 타입을 선언할 수도 있다. (ex. [Number, String])</li>
<li><code>defalut</code> : 속성값이 비어있거나 <code>undefined</code>를 전달 받는 경우 기본값을 선언할 수 있다. </li>
<li><code>required</code> : 속성이 필수값이라면 <code>true</code>로 해서 설정할 수 있다.</li>
<li><code>validator</code> : 속성값의 유효성 검사가 필요할 때 사용할 수 있다.</li>
</ul>
<p>❗ 컴포넌트 사용시 명시된 사항을 위반할 때 개발모드에서 콘솔 경고가 발생된다.</p>
<br>

<p>물론, 부모 컴포넌트에서도 데이터를 보낼때도 객체로 보낼 수 있다.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;AppCard :title=&quot;post.title&quot; :contents=&quot;post.contents&quot;&gt;&lt;/AppCard&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script setup&gt;
const title = ref(&quot;제목1&quot;);
const contents = ref(&quot;내용1&quot;);
&lt;/script&gt;</code></pre>
<p>v-bind:title=&quot;post.title&quot; 를 간단히 :title=&quot;post.title&quot; 로 쓸 수 있다.</p>
<br>
<br>

<h3 id="13-props-단방향-데이터-흐름">1.3 Props 단방향 데이터 흐름</h3>
<blockquote>
<p>** 모든 <code>props</code>는 상위 속성과 하위 속성간에 단방향 바인딩으로 형성되어 있다.**</p>
</blockquote>
<p>상위 속성 업데이트 -&gt; 하위 속성 업데이트 (o)
하위 속성 업데이트 -&gt; 상위 속성 업데이트 (x)</p>
<p>이러한 성질은 하위 속성 변경 실수로 상위 속성을 변경하여 데이터 흐름을 이해하기 어렵게 만드는 것을 방지할 수 있다.</p>
<p>또한, 상위 컴포넌트가 업데이트될 때마다 하위 컴포넌트의 모든 <code>props</code> 의 최신 상태도 초기화 된다.
그렇기 때문에 자식 컴포넌트 내부에서 <code>props</code>를 변경하지 않아야 한다.</p>
<pre><code class="language-javascript">//자식 컴포넌트 AppCard.vue
export default {
  props: {
    title: {
      type: String,
      default: &#39;news&#39;
    },
    contents: {
      type: String,
      required: true 
    }
  },
  setup(props){
    props.title = &quot;제목2&quot;; //불가능. 반영되지 않으며 콘솔창 경고 출력
      return {}
  }
}</code></pre>
<p>부모로부터 전달받은 props.title을 자식 컴포넌트에서 변경할 수 없다.</p>
<p>그럼 다른 방법이 없을까?
그것은 <strong>자식컴포넌트에서 부모컴포넌트로 이벤트를 보내 부모컴포넌트에서 변경 이벤트를 발생시키는 것이다.</strong></p>
<p>emits에 대해 알아보자.</p>
<br>
<br>

<hr>
<h2 id="📌-2-emits">📌 2. emits</h2>
<blockquote>
<p>** <code>emit</code>을 이용하면 자식 컴포넌트에서 부모 컴포넌트로 이벤트를 내보낼 수 있다. **</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/1fcb861d-8b5e-43ff-b5bf-e1d9407ab1c7/image.png" alt=""></p>
<p>이벤트를 내보낸다는게 도대체 무슨말이냐면,</p>
<p>(1) 부모 컴포넌트에서 전달받은 데이터 <code>title</code>을 자식 컴포넌트에서 변경할 수 없다.
(2) 자식 컴포넌트에서 부모 컴포넌트로 이벤트를 보낼 수 있다. (<code>emit</code>)
(3) 그렇다면 데이터 <code>title</code>을 변경해야 되면, 자식 컴포넌트에서 부모 컴포넌트로 <code>changeTitle</code> 이벤트를 내보내겠다.
(4) <code>changeTitle</code> 이벤트를 받은 부모 컴포넌트는 해당 이벤트를 실행하여 <code>title</code>을 변경한다.</p>
<p>한마디로, 자식 컴포넌트에서 변경할 수 없으니 이벤트를 부모로 보내서 부모에서 변경을 실행하겠다는 것이다.</p>
<p>사용법은 예시를 살펴보자.</p>
<pre><code class="language-javascript">//자식 컴포넌트 AppCard.vue
export default {
  props: {
    title: {
      type: String,
      default: &#39;news&#39;
    },
    contents: {
      type: String,
      required: true 
    }
  },
  emits: [&#39;changeTitle&#39;],
  setup(props, context){
    const buttonEvent = () =&gt; {
        context.emit(&#39;changeTitle&#39;);
    }
      return {buttonEvent}
  }
}</code></pre>
<p><code>props</code>와 마찬가지로 <code>emits</code>를 선언해주어야 한다.
<code>changeTitle</code>이벤트를 보냈다.</p>
<p>부모에서 이벤트를 받아보자.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;AppCard 
       :title=&quot;post.title&quot;     
       :contents=&quot;post.contents&quot;
       @changeTitle = &quot;post.title = &#39;제목2&#39;&quot;&gt;
  &lt;/AppCard&gt;
&lt;/template&gt;</code></pre>
<p>자식에서 부모로 이벤트를 보낼 때, 부모는 @로 받는다.
부모에서 보낼 때는 : , 부모에서 받을 때는 @이다.</p>
<p>부모와 자식간의 데이터 전달은 단방향으로 이루어지는 것이다.</p>
<blockquote>
<p><strong><code>props</code> : 부모 -&gt; 자식 
<code>emits</code> : 자식 -&gt; 부모</strong></p>
</blockquote>
<br>
<br>

<hr>
<h2 id="📌-3-객체배열-props-업데이트">📌 3. 객체/배열 Props 업데이트</h2>
<blockquote>
<p><strong>Javascript 특성상 객체나 배열이 props로 전달되면 자식 컴포넌트에서는 prop 바인딩(값 변경)을 변경할 수 없지만 객체 또는 배열의 중첩 속성은 변경할 수 있다.</strong></p>
</blockquote>
<h3 id="이건-정말정말-중요한-내용이다">이건 정말정말 중요한 내용이다!!!</h3>
<p>왜냐면, 많은 개발자들이 &quot;어?? 되네??&quot;하고 시도했다가 후에 데이터 흐름 추론이나 데이터 업데이트가 꼬여 골치아파지기 때문이다. (내 경험..)</p>
<p>중첩 속성은 변경할 수 있다는게 무슨 말이냐면,
자식 컴포넌트에서 <code>props.title</code>은 변경할 수 없었지만, <code>props.post.title</code>은 변경할 수 있다.</p>
<p>예시부터 보자.</p>
<p>위에서 처음에는 이렇게 보냈었다.</p>
<pre><code class="language-html">&lt;!--부모 컴포넌트 --&gt;
&lt;template&gt;
  &lt;AppCard 
       :title=&quot;post.title&quot;&gt;
  &lt;/AppCard&gt;
&lt;/template&gt;</code></pre>
<p>그런데, 보낼 때 <code>post</code> 객체 자체를 보낸다고 생각해보자.</p>
<pre><code class="language-html">&lt;!--부모 컴포넌트 --&gt;
&lt;template&gt;
  &lt;AppCard 
       :post=&quot;post&quot;&gt;
  &lt;/AppCard&gt;
&lt;/template&gt;</code></pre>
<pre><code class="language-javascript">&lt;script&gt;
  export default {
    setup(){
        const post = reactive({
            title: &quot;제목&quot;
        });

          return { post }
    }
  }
&lt;/script&gt;</code></pre>
<p>자식에서는 이렇게 받을 것이다.</p>
<pre><code class="language-javascript">//자식 컴포넌트 AppCard.vue
export default {
  props: {
    post: {
      type: Object,
      default: () =&gt; ({})
    },
  },
  setup(props){
    const buttonEvent = () =&gt; {
      //props.title = &quot;제목2&quot;; 불가능
      props.post.title = &quot;제목2&quot;; // 가능
    }
      return {buttonEvent}
  }
}</code></pre>
<p>props.title은 변경하지 못했는데, props.post.title은 변경할 수 있다. 객체 또는 배열의 중첩 속성은 변경할 수 있기 때문이다.</p>
<p>이것은 JavaScript에서 객체와 배열이 참조 타입(Reference Type)으로 전달되고 Vue가 이러한 변경을 방지하는것은 부당한 비용이 들기 때문에 가능하게 된 것이다.</p>
<p>이러한 변경은 데이터 흐름 추론에 어려움을 발생시키며, 부모에서 데이터를 업데이트 했을때 예상치 못한 문제가 발생할 수 있다.</p>
<p>(부모로부터 받은 데이터가 초기화만 되고, 업데이트 되지 않기를 바란다면 json.stringfy를 이용할 수 있다.)</p>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p>Vue3 완전정복 - 짐코딩
<a href="https://ko.vuejs.org/guide/components/props.html">Vue3 공식문서</a></p>
<hr>
<p>팝업 호출, 컴포넌트 재사용 등에서 가장 중요한 props와 emits에 대한 내용이다.</p>
<p>script setup에서는 context가 아닌 defineProps, defineEmits를 사용한다. </p>
<p>이것에 대한 건 추후 script setup을 포스팅할 때 작성하도록 하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] SFC CSS와 스타일 가이드]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-SFC-CSS%EC%99%80-%EC%8A%A4%ED%83%80%EC%9D%BC-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@falling_star3/Vue.js-SFC-CSS%EC%99%80-%EC%8A%A4%ED%83%80%EC%9D%BC-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Sat, 26 Aug 2023 11:47:52 GMT</pubDate>
            <description><![CDATA[<p>싱글파일컴포넌트에서 CSS기능 (scoped / 모듈) 그리고 컴포넌트 등록시 명명 규칙등의 가이드를 분리하여 정리한 포스팅입니다.</p>
<p>지속적으로 가이드를 추가 수정 할 예정입니다.</p>
<br>

<h2 id="📌-1-css-기능-scoped--module">📌 1. CSS 기능 (scoped / module)</h2>
<h3 id="1-scoped-css">1) Scoped CSS</h3>
<blockquote>
<p>*<em><code>&lt;style&gt;</code>태그에 scoped속성이 있는 경우 해당 CSS는 현재 컴포넌트의 요소에만 적용된다. *</em></p>
</blockquote>
<pre><code class="language-html">&lt;template&gt;
  &lt;p class=&quot;greeting&quot;&gt;greeting&lt;/p&gt;
&lt;/template&gt;
&lt;style scoped&gt;
.greeting {
  color: red;
  font-weight: bold;
}
&lt;/style&gt;</code></pre>
<p>해당 CSS는 현재 컴포넌트의 요소에만 적용된다.</p>
<p>이게 무슨말이냐면, scoped 속성이 없는 경우에는 A컴포넌트에서 적용한 스타일이 B컴포넌트에 영향을 미칠 수 있다는 얘기다.</p>
<p>나는 A컴포넌트의 스타일을 고쳤는데 B컴포넌트 화면이 이상하게 되어버리는.. 현상이 일어날 수 있다.</p>
<p>scoped를 쓰지 않는 경우 화면 명을 클래스네임으로 붙여주고 test01.greeting{ } 스타일을 적용하는 방법도 있다.(scoped를 몰랐을 때 회사에서 이렇게 개발했었음,, 매우 비효율적)</p>
<p>원리는 다음과 같다.</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;p class=&quot;greeting&quot; data-v-7ba5bd90&gt;greeting&lt;/p&gt;
&lt;/template&gt;
&lt;style scoped&gt;
.greeting[data-v-7ba5bd90] {
  color: red;
  font-weight: bold;
}
&lt;/style&gt;</code></pre>
<p>클래스 뒤에 data-v-7ba5bd90(해시) 가 생성되어 적용되는 것이다.
scoped를 모를때 쓰던 방법과 원리가 같다.</p>
<p>scoped라는 기능이 있으니 편리하게 사용하도록 하자.</p>
<br>
<br>

<h3 id="2css-모듈">2.CSS 모듈</h3>
<blockquote>
<p><code>&lt;style module&gt;</code> 은 CSS 모듈로 컴파일되고, CSS 클래스를 $style 객체의 속성으로 노출한다.</p>
</blockquote>
<pre><code class="language-html">&lt;template&gt;
  &lt;p :class=&quot;$style.red&quot;&gt;This should be red&lt;/p&gt;
&lt;/template&gt;

&lt;style module&gt;
.red {
  color: red;
}
&lt;/style&gt;</code></pre>
<p>결과 클래스는 충돌을 피하기 위해 해시되어 CSS 범위를 현재 컴포넌트로만 지정하는 것과 동일한 효과를 얻는다.</p>
<br>
<br>

<hr>
<h2 id="📌-2-스타일-가이드명명-규칙">📌 2. 스타일 가이드(명명 규칙)</h2>
<blockquote>
<p><strong>자세한 내용은 <a href="https://ko.vuejs.org/style-guide/#%E1%84%8B%E1%85%AE%E1%84%89%E1%85%A5%E1%86%AB%E1%84%89%E1%85%AE%E1%86%AB%E1%84%8B%E1%85%B1-b-%E1%84%80%E1%85%B2%E1%84%8E%E1%85%B5%E1%86%A8-%E1%84%8C%E1%85%A5%E1%86%A8%E1%84%80%E1%85%B3%E1%86%A8-%E1%84%80%E1%85%AF%E1%86%AB%E1%84%8C%E1%85%A1%E1%86%BC-%E1%84%80%E1%85%A1%E1%84%83%E1%85%A9%E1%86%A8%E1%84%89%E1%85%A5%E1%86%BC-%E1%84%92%E1%85%A3%E1%86%BC%E1%84%89%E1%85%A1%E1%86%BC%E1%84%8B%E1%85%B3%E1%86%AF-%E1%84%8B%E1%85%B1%E1%84%92%E1%85%A1%E1%86%B7">Vue 공식 스타일가이드 문서</a>를 참고하자.</strong></p>
</blockquote>
<p>프로젝트 구조 및 컴포넌트 간 종속관계를 좀 더 빠르고 편리하게 파악할 수 있도록 뷰의 공식 스타일 가이드를 따르는 것이 좋다.</p>
<p><strong>1. 싱글 파일 컴포넌트의 파일명은 항상 파스칼 케이스이거나 항상 케밥 케이스여야 한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/e62e565f-25c6-456c-934d-e615148340f6/image.png" alt=""></p>
<p><strong>💡 파스칼케이스</strong>
: 첫 단어를 포함해 모든 단어가 대문자로 시작(RocketLaunch)</p>
<p><strong>💡 케밥케이스</strong>
: 모든 단어가 소문자로 시작하고 단어와 단어 사이는 &#39;-&#39;로 연결(rocket-launch)</p>
<br>

<p><strong>2. 앱별 스타일과 규칙을 적용하는 기본 컴포넌트는 모두 Base, App 또는 V와 같은 특정 접두사로 시작해야 한다.</strong></p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/cf5f5f29-386c-4a4c-b4c1-952ad3327c7a/image.png" alt=""></p>
<br>


<p><strong>3. 활성 인스턴스가 하나만 있어야 하는 컴포넌트는 The 접두사로 시작하여 하나만 있을 수 있음을 나타내야 한다.</strong></p>
<p>이는 컴포넌트가 단일 페이지에서만 사용된다는 뜻이 아니라 페이지당 한 번만 사용된다는 뜻이다.</p>
<p><img src="https://velog.velcdn.com/images/falling_star3/post/23ea40ea-429a-4027-ae71-f6ab4c894095/image.png" alt=""></p>
<br>

<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://ko.vuejs.org/style-guide/#%E1%84%8B%E1%85%AE%E1%84%89%E1%85%A5%E1%86%AB%E1%84%89%E1%85%AE%E1%86%AB%E1%84%8B%E1%85%B1-b-%E1%84%80%E1%85%B2%E1%84%8E%E1%85%B5%E1%86%A8-%E1%84%8C%E1%85%A5%E1%86%A8%E1%84%80%E1%85%B3%E1%86%A8-%E1%84%80%E1%85%AF%E1%86%AB%E1%84%8C%E1%85%A1%E1%86%BC-%E1%84%80%E1%85%A1%E1%84%83%E1%85%A9%E1%86%A8%E1%84%89%E1%85%A5%E1%86%BC-%E1%84%92%E1%85%A3%E1%86%BC%E1%84%89%E1%85%A1%E1%86%BC%E1%84%8B%E1%85%B3%E1%86%AF-%E1%84%8B%E1%85%B1%E1%84%92%E1%85%A1%E1%86%B7">Vue 공식 스타일가이드 문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Single-File Component(SFC)]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Single-File-ComponentSFC</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Single-File-ComponentSFC</guid>
            <pubDate>Sat, 26 Aug 2023 11:16:41 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-컴포넌트sfc--string">📌 1. 컴포넌트(SFC / String)</h2>
<h3 id="1-single-file-componentsfc">1. Single File Component(SFC)</h3>
<blockquote>
<p><strong>기본적으로 Single-File Component는 화면의 특정 영역에 대한 HTML, CSS, JS 코드를 한 파일에서 관리하는 방법이다.</strong></p>
</blockquote>
<p>Vue에서 Single-file component는 <strong><u>템플릿(template), 로직(script), 스타일(style)을 하나의 파일로 캡슐화한 특수 파일 형식</u></strong>(*.vue)을 말한다.
빌드도구를 사용할 때 컴포넌트는 일반적으로 SFC로 정의할 수 있다.</p>
<pre><code>&lt;template&gt;
    &lt;p&gt;템플릿 영역입니다.&lt;/p&gt;
&lt;/template&gt;

&lt;script&gt;
    &lt;p&gt;로직 영역입니다.&lt;/p&gt;
&lt;/script&gt;

&lt;style&gt;
    &lt;p&gt;스타일 영역입니다.&lt;/p&gt;
&lt;/style&gt;</code></pre><p><strong>1) <code>&lt;template&gt;</code> 영역</strong></p>
<ul>
<li>각 *.vue 파일은 한 번에 최대 하나의 top-level <code>&lt;template&gt;</code> 블록을 포함할 수 있다.</li>
<li>콘텐츠는 추출되어 @vue/compiler-dom으로 전달되고, JavaScript 렌더 기능으로 사전 컴파일되고, render 옵션으로 내보내어 컴포넌트에 첨부된다.</li>
</ul>
<p><strong>2) <code>&lt;script&gt;</code> 영역</strong></p>
<ul>
<li>각 *.vue 파일은 한 번에 최대 하나의 <code>&lt;script&gt;</code> 블록을 포함할 수 있다.
(<code>&lt;script setup&gt;</code> 제외. <code>&lt;script&gt;</code>와 <code>&lt;script setup&gt;</code>은 공존할 수 있다.)</li>
<li>스크립트는 ES모듈로 실행된다.</li>
<li>default export는 일반 객체 또는 defineComponent의 반환 값으로 Vue 컴포넌트 옵션 객체여야 한다.</li>
</ul>
<p><strong>3) <code>&lt;style&gt;</code> 영역</strong></p>
<ul>
<li>단일 *.vue 파일에는 여러 <code>&lt;style&gt;</code> 태그가 포함될 수 있다.</li>
<li><code>&lt;style&gt;</code> 태그는 현재 컴포넌트에 스타일을 캡슐화하는 데 도움이 되도록 scoped 또는 module 속성을 가질 수 있다. </li>
</ul>
<br>

<p>SFC말고 다른 방법도 있을까?
문자열 템플릿(string template)이 있다.</p>
<br>
<br>
<br>



<h3 id="2-문자열-템플릿string-template">2. 문자열 템플릿(string template)</h3>
<blockquote>
<p><strong>빌드 도구를 사용하지 않을 때 컴포넌트는 Vue 옵션을 포함하는 일반 JavaScript 객체로 정의할 수 있다.</strong></p>
</blockquote>
<pre><code class="language-javascript">import { ref } from &#39;vue/dist/vue.esm-bundler.js&#39;;
export default {
  setup() {
    const counter = ref(0);
    return {
      counter,
    };
  },
  template: `
      &lt;button @click=&quot;counter++&quot;&gt;클릭 횟수 {{ counter }}&lt;/button&gt;
  `,
};</code></pre>
<p>💡<strong>_ vue.esm-bundler.js 이란?_</strong>
런타임 컴파일러를 포함한다. 빌드도구(Vite)를 사용하지만 여전히 런타임 문자열 템플릿을 원하는 경우 vue.esm-bundler.js를 사용한다.</p>
<br>
<br>

<hr>
<h2 id="📌-2-컴포넌트-등록">📌 2. 컴포넌트 등록</h2>
<blockquote>
<p>Vue 컴포넌트는 <code>&lt;template&gt;</code>안에서 발견 되었을 때 Vue가 구현 위치를 알 수 있도록 등록을 해놓아야 한다. <strong>컴포넌트를 등록하는 방법에는 전역(Global), 지역(Local) 두 가지가 있다.</strong></p>
</blockquote>
<h3 id="1-전역-등록">1) 전역 등록</h3>
<p><strong>전역 등록된 컴포넌트는 애플리케이션 어떤 곳에서든 사용 가능하다.</strong></p>
<p><code>app.component()</code> 메서드를 사용하여 현재 Vue 애플리케이션에서 전역적으로 사용할 수 있도록 등록할 수 있다.</p>
<pre><code class="language-javascript">// main.js파일
import { createApp } from &#39;vue&#39;;
import App from &#39;./App.vue&#39;;

import AppCard from &#39;./components/AppCard.vue&#39;;

const app = createApp(App)
app.component(&#39;AppCard&#39;, AppCard)
app.mount(&#39;#app&#39;);</code></pre>
<p>이렇게 등록해놓으면 어떤 곳에서든 사용 가능하다.</p>
<pre><code class="language-html">// TheView.vue 파일

&lt;template&gt;
     &lt;AppCard&gt;&lt;/AppCard&gt;
&lt;/template&gt;
</code></pre>
<br>

<p><strong>전역등록 단점</strong></p>
<ul>
<li>컴포넌트를 전역 등록하면 컴포넌트를 사용하지 않더라도 계속해서 최종 빌드에 해당 컴포넌트가 포함된다. 이는 사용자가 다운로드하는 파일의 크기를 불필요하게 증가시킨다.</li>
<li>전역등록을 하게 되면 애플리케이션의 컴포넌트간 종속 관계를 명시적을 확인하기 힘들다. 상위 컴포넌트, 하위 컴포넌트의 구분이 힘들면 유지보수가 어렵게 된다.</li>
</ul>
<br>
<br>

<h3 id="2-지역등록">2) 지역등록</h3>
<p><strong>지역 등록된 컴포넌트는 현재 컴포넌트 영역에서만 사용할 수 있다.</strong></p>
<p> Vue 컴포넌트 인스턴스의 <code>components</code> 옵션을 사용해서 등록할 수 있다.</p>
<pre><code class="language-javascript">// ParentComponent.vue 파일
import ChildComponent from &#39;./ChildComponent.vue&#39;

export default {
    components: {
        ChildComponent
    },
    setup() {
        // ...
    }
}</code></pre>
<p>ParentComponent  컴포넌트에 로컬 등록된 ChildComponent는 현재 컴포넌트인 ParentComponent 컴포넌트에서만 사용 가능하다.</p>
<br>
<br>

<hr>
<h2 id="📌-3-컴포넌트-사용">📌 3. 컴포넌트 사용</h2>
<p>등록된 컴포넌트는 <code>&lt;template&gt;</code>에서 원하는 만큼 사용할 수 있다.</p>
<pre><code class="language-javascript">&lt;h2&gt;Single-File Component&lt;/h2&gt;
&lt;ButtonCounter&gt;&lt;/ButtonCounter&gt;
&lt;ButtonCounter&gt;&lt;/ButtonCounter&gt;</code></pre>
<p>컴포넌트는 사용할 때마다 해당 컴포넌트의 새 인스턴스가 생성된다. 
즉, 사용할 때마다 setup() 함수 가 실행 된다는 것을 의미한다.</p>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://vuejs.org/api/sfc-spec.html">Vue공식문서</a>
Vue3 완벽마스터 - 짐코딩</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] Watch, WatchEffect]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-Watch-WatchEffect</link>
            <guid>https://velog.io/@falling_star3/Vue.js-Watch-WatchEffect</guid>
            <pubDate>Tue, 15 Aug 2023 17:10:45 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-1-watch">📌 1. Watch</h2>
<blockquote>
<p><strong>composition API의 <code>watch</code>는 반응형 상태가 변경 될 때마다, 이를 감지하여 특정 작업을 수행하게 하는 &quot;감시자 역할&quot;을 한다.</strong></p>
</blockquote>
<pre><code class="language-javascript">watch(/* Source Type */, (newValue, oldValue) =&gt; {});</code></pre>
<p>한 마디로, 반응형 상태가 변경 되었을 때 이를 감지하여 다른 작업(DOM변경, 비동기 작업 등등..)을 해야하는 상황에서 사용하는 속성이다.</p>
<p>간단한 예시를 살펴보자.</p>
<h5 id="✨-예제-1">✨ 예제 1</h5>
<pre><code class="language-javascript">&lt;script setup&gt;
const message = ref(&#39;Hello&#39;);

watch(message, (newValue, oldValue) =&gt; {
    console.log(&#39;newValue&#39; : newValue);
      console.log(&#39;oldValue&#39; : oldValue);
})
&lt;/script&gt;</code></pre>
<p>위의 예시에서 <code>message</code>의 값이 &#39;Hello World!&#39;로 변경된다면, 콘솔창에는 다음과 같이 출력될 것이다.</p>
<pre><code>newValue : Hello World!
oldValue : Hello</code></pre><br>
<br>

<hr>
<p><code>watch</code>의 첫 번째 매개변수는 다양한 타입(<code>ref</code>, <code>reactive</code>, <code>computed</code>, <code>array</code>등)이 될 수 있다.</p>
<h5 id="✨-예제-2">✨ 예제 2</h5>
<pre><code class="language-javascript">const x = ref(0);
const y = ref(0);

// ref
watch(x, (newX) =&gt; {
  console.log(newX);
})

// getter
watch(
  () =&gt; x.value + y.value,
  (sum) =&gt; {
    console.log(sum);
  }
)

// array
watch([x, () =&gt; y.value], ([newX, newY]) =&gt; {
  console.log(newX, newY);
})</code></pre>
<br>
<br>

<hr>
<p>여기서 주의할 점은 <strong>위와 같은 방식으로는 반응형 객체의 속성을 볼 수 없다는 것이다.</strong></p>
<p>우리는 너무나 당연하게도 <code>watch</code>를 객체의 속성에도 사용하려고 시도해볼 것이다. (나도 그랬으므로...)</p>
<h5 id="✨-예제-3">✨ 예제 3</h5>
<pre><code class="language-javascript">const obj = reactive({ count: 0 });

watch(obj.count, (newValue) =&gt; {
    console.log(&#39;newValue: &#39;, newValue);
});</code></pre>
<p>watch가 제대로 작동하지 않는다.
왜 그럴까?</p>
<pre><code class="language-javascript">console.log(typeof obj.count);
// number 출력</code></pre>
<p>obj.count의 타입은 반응형 객체가 아닌 &#39;number&#39;타입이다.
그러므로 watch가 동작하여 감지할 수 없다.</p>
<p>그러면 방법이 없을까?
대신 getter함수를 사용하면 된다.</p>
<pre><code class="language-javascript">const obj = reactive({ count: 0 });
watch(() =&gt; obj.count, (newValue) =&gt; {
  console.log(&#39;newValue: &#39;, newValue);
});</code></pre>
<br>
<br>

<hr>
<p>또, 여기서 객체의 속성이 아닌 객체 그 자체를 첫번째 매개변수로 주면 어떻게 될까?</p>
<h5 id="✨-예제-4">✨ 예제 4</h5>
<pre><code class="language-javascript">&lt;script setup&gt;
const obj = reactive({ count: 0 });

watch(obj, (newValue, oldValue) =&gt; {
    console.log(&#39;newValue&#39; : newValue);
      console.log(&#39;oldValue&#39; : oldValue);
})
&lt;/script&gt;</code></pre>
<p><code>newValue</code>, <code>oldValue</code> 모두 같은 객체를 바라보므로, count가 1로 변경될 때 <code>newValue</code>, <code>oldValue</code> 모두 1을 출력한다.</p>
<br>
<br>
<br>

<hr>
<h2 id="📌-2-deepimmediate-option">📌 2. deep/immediate option</h2>
<blockquote>
<p>** deep과 immediate는 watch 오브젝트의 옵션이다.
deep : 지정한 속성 안에 있으며, 지정한 속성의 속성 값도 감시한다.
immediate : watch의 처리를 페이지를 최초에 즉시 실행한다.**</p>
</blockquote>
<h3 id="1-deep">1. deep</h3>
<p><code>deep</code>은, 지정한 속성안에 있는 속성의 값도 감시하게 하는 <code>watch</code>의 옵션이다.</p>
<p>반응형 객체를 직접 <code>watch()</code> 하면 암시적으로 깊은 감시자가 생성된다. 즉, 속성 뿐만아니라 모든 중첩된 속성에도 트리거된다.</p>
<p>예시를 통해 살펴보자.</p>
<h5 id="✨-예제-5">✨ 예제 5</h5>
<pre><code class="language-javascript">const person = reactive({
  name: &#39;홍길동&#39;,
  age: 30,
  hobby: &#39;운동&#39;,
  obj: {
    count: 0,
  },
});

watch(person, (newValue) =&gt; {
  console.log(&#39;newValue: &#39;, newValue);
});</code></pre>
<p><code>person</code>객체의 <code>obj</code>속성의 <code>count</code>가 변경되어도, 이를 감지하여 콘솔창에 출력된다.</p>
<br>
<br>

<hr>
<p>다만, <code>getter</code>함수로 객체를 넘길 경우에는 객체의 값이 바뀔 경우에만 트리거 된다. 중첩된 속성은 트리거 되지 않는다.</p>
<p>위에서 우리는 객체의 속성을 첫번째 매개변수로 사용할때 <code>watch</code>가 동작하지 않아 <code>getter</code>함수를 사용했었다.</p>
<pre><code class="language-javascript">watch(
    () =&gt; person.obj,
    (newValue) =&gt; {
        // 객체의 값이 바뀔 경우에만 트리거 된다.
    }
);</code></pre>
<p>이 경우, <code>obj</code>의 속성인 <code>count</code>가 변경되어도 <code>watch</code>가 동작하지 않는다. <code>obj</code>자체가 변경될 때만 동작한다. 
ex) obj: &quot;Hello!&quot; 로 obj가 변경됐을 경우에만 동작.</p>
<p><strong><code>deep</code> 옵션을 사용하면 깊은 감시자로 강제할 수 있다.</strong></p>
<h4 id="✨-예제-6">✨ 예제 6</h4>
<pre><code class="language-javascript">watch(
  () =&gt; person.obj,
  (newValue) =&gt; {
    console.log(&#39;newValue: &#39;, newValue);
  },
  { deep: true } //마지막 매개변수
);</code></pre>
<br>
<br>


<hr>
<h3 id="2-immediate">2. immediate</h3>
<p><code>immediate</code>는 최초에 즉시실행 하게 하는 옵션이다.</p>
<p><code>watch</code>는 반응형 데이터를 감시하다가, 반응형 데이터의 변화를 감지했을 때 콜백 함수가 실행된다.
하지만, <code>immeditate</code> 옵션을 사용하면 최초에 페이지를 읽었을 때 즉시실행하게 만들 수 있다.</p>
<h4 id="✨-예제-7">✨ 예제 7</h4>
<pre><code class="language-javascript">const message = ref(&#39;Hello World!&#39;);
const reverseMessage = ref(&#39;&#39;);

watch(
  message,
  (newValue) =&gt; {
    reverseMessage.value = newValue.split(&#39;&#39;).reverse().join(&#39;&#39;);
  },
  {
    immediate: true,
  }
);</code></pre>
<p><code>immditate</code> 옵션을 주지 않았을 때는, <code>message</code>의 변경이 없었으므로 <code>reverseMessage</code>의 값도 여전히 &#39;&#39;이다.</p>
<p><code>message</code>에 변경이 있어야만 <code>reverseMessage</code>에 &#39;!dlroW olleH&#39;가 담긴다.</p>
<p>하지만, <code>immediate</code> 옵션을 <code>true</code>로 주면 페이지가 최초 로드될때 즉시실행되어 바로 <code>reverseMessage</code>에 &#39;!dlroW olleH&#39;가 담긴다.</p>
<br>

<p><strong>🚫 주의사항</strong></p>
<p>deep 옵션은 큰 데이터 구조에서 사용할 때 비용이 많이 들 수 있다. 필요한 경우에만 사용하고 성능 영향에 주의해야한다.</p>
<br>
<br>


<hr>
<h3 id="3-computec-vs-watch">3. computec VS watch</h3>
<p><code>computed</code>와 <code>watch</code>는 비슷한 역할을 수행한다.</p>
<pre><code class="language-javascript">//computed
 computed(() =&gt;
  message.value.split(&#39;&#39;).reverse().join(&#39;&#39;)
 );

//watch
watch(
  message,
  (newValue) =&gt; {
    reverseMessage.value = newValue.split(&#39;&#39;).reverse().join(&#39;&#39;);
  }
);</code></pre>
<ul>
<li><strong>computed</strong>
Vue 인스턴스의 상태(ref, reactive 변수)의 종속 관계를 자동으로 세팅하고자 할 때는 <code>computed</code>로 구현하는 것이 좋다.
위 예시 처럼 <code>reverseMessage</code>는 <code>message</code> 값에 따라 결정되어지는 종속관계에 있다.  이 종속관계 코드가 복잡해지면 <code>watch</code>로 구현할 경우 더 복잡해지거나 중복계산 또는 오류를 발생시킬 수 있다.<br>


</li>
</ul>
<ul>
<li><strong>watch</strong>
Vue 인트턴스의 상태(ref, reactive 변수)의 변경 시점에 특정 액션(call api, push route 등)을 취하고자 할때 적합하다.
대게의 경우 <code>computed</code>로 구현 가능한 것이라면 <code>watch</code>가 아니라 <code>computed</code>로 구현하는게 대부분 옳다.</li>
</ul>
<br>
<br>

<hr>
<h2 id="📌-3-watcheffect">📌 3. watchEffect</h2>
<blockquote>
<p><strong>WatchEffect는 콜백 함수 안의 반응성 데이터에 변화가 감지되면 자동으로 반응하여 실행한다. 
그리고 WatchEffect의 코드는 컴포넌트가 생성될 때 즉시 실행된다.</strong></p>
</blockquote>
<p>예시를 살펴보자.</p>
<h4 id="✨-예제-8">✨ 예제 8</h4>
<pre><code class="language-javascript">const message = ref(&#39;&#39;);

watchEffect(()=&gt; {
    console.log(message.value);
})</code></pre>
<p>위의 예시의 경우, <code>message</code> 반응형 데이터가 변경될 때마다 콘솔이 출력된다.
콜백 함수 안의 반응형 데이터가 변경되면 자동으로 감지하여 실행되는 것이다.</p>
<p>이것은 언제 사용할까?
자동저장 기능을 만든다고 생각해보자.</p>
<p><code>save()</code> 로 저장함수를 만들어 놓고, 이와 같이 watchEffect를 사용하는 것이다.</p>
<pre><code class="language-javascript">const message = ref(&#39;&#39;);

watchEffect(()=&gt; {
    save(message.value);
})</code></pre>
<p>위와 같이 코드를 작성하면, 내용이 수정될때마다 자동으로 저장함수 <code>save()</code>가 실행된다.</p>
<p><strong>TIP!</strong> 바인딩된<code>v-model</code>에 <code>.lazy</code> 옵션을 준다면 포커스가 이동되었을때 저장하는 방식으로도 변경할 수 있을 것이다.</p>
<br>

<h3 id="watch-vs-watcheffect">watch VS watchEffect</h3>
<p><code>watch</code>와 <code>watchEffect</code> 둘 다 관련 작업(api call, push route 등)을 반응적으로 수행할 수 있게 해준다. 하지만 주요한 차이점은 관련된 반응형 데이터를 추적하는 방식이다.</p>
<ul>
<li><strong>watch</strong>
명시적으로 관찰된 소스(첫번째 매개변수)만 추적한다. 콜백 내에서 액세스한 항목은 추적하지 않는다. 또한, 콜백은 소스가 실제로 변경된 경우에만 트리거된다. 콜백이 실행되어야 하는 시기를 보다 정확하게 제어할 수 있다.</li>
<li><strong>watchEffect</strong>
콜백 내에 담긴 모든 반응 속성을 자동으로 추적한다. 이것은 더 편리하고 일반적으로 더 간결한 코드를 생성하지만 반응성 종속성을 덜 명시적으로 만든다.</li>
</ul>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p>인프런 vue3 기본편 - 짐코딩
<a href="https://ko.vuejs.org/api/options-state.html#watch">https://ko.vuejs.org/api/options-state.html#watch</a></p>
<br>

<hr>
<h4 id="오늘의-한마디">오늘의 한마디</h4>
<p>객체나 배열을 주로 사용하는 실무에서 watch가 잘 동작하지 않는 경우가 많았다.
watch를 사용하는 것이 늘 불편했었는데 이렇게 포스팅하고 나니 제대로 정리 된 기분이다.</p>
<p>이 포스팅은 나를 위한 포스팅이다.. 앞으로도 자주 방문할 나를 위해 응원을 전한다! watch를 편리하게 잘 사용할 수 있기를!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue.js] 양방향 바인딩(v-model)]]></title>
            <link>https://velog.io/@falling_star3/Vue.js-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%B0%94%EC%9D%B8%EB%94%A9v-model</link>
            <guid>https://velog.io/@falling_star3/Vue.js-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%B0%94%EC%9D%B8%EB%94%A9v-model</guid>
            <pubDate>Mon, 07 Aug 2023 15:18:30 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-양방향-바인딩-v-model">📌 양방향 바인딩 v-model</h2>
<h3 id="1-v-model-이란">1. v-model 이란?</h3>
<blockquote>
<p><strong>입력 요소의 상태와 자바스크립트의 상태를 동기화 시켜주는 디렉티브.</strong></p>
</blockquote>
<p>즉, v-model은 양방향 바인딩을 시켜주는 디렉티브이다. </p>
<p>양방향 바인딩이란 무엇일까? 말 그대로, 단방향이 아닌 양방향을 연결시켜주는 바인딩이다.
우리가 이전에 주로 사용했던 v-bind를 살펴보자.  v-bind는 단방향 바인딩 디렉티브이다.</p>
<p>먼저 v-bind를 살펴보자.</p>
<pre><code class="language-hrml">&lt;input v-bind=&quot;textValue&quot;&gt;
&lt;script setup&gt;
  const textValue = ref();
  textValue.value = &quot;안녕하세요&quot;;
&lt;/script&gt;</code></pre>
<p>자바스크립트에서 작성한 <code>&quot;안녕하세요&quot;</code>는 <code>&lt;input&gt;</code>의 <code>textValue</code>로 전달된다.
하지만, input 입력창에 사용자가 입력한 데이터는 자바스크립트의 <code>textValue</code>로 전달되지 않는다.</p>
<p>쉽게 말하면, <strong>javaScript → html 방향으로는 데이터가 가고 있는데 javaScript ← html 방향으로는 데이터가 가지 않는 것이다.</strong></p>
<img src="https://velog.velcdn.com/images/falling_star3/post/6238a2e6-34fd-4388-93ee-161727cefbc5/image.png" >


<p>실제로 <code>console.log(textValue.value)</code>를 찍어보면, 사용자가 &quot;안녕!!&quot;이라고 입력해도 <code>textValue.value</code> 값이 바뀌지 않는다.</p>
<br>

<p>사용자가 input입력창에 입력하는 것을 바로바로 자바스크립트로 전달해 <code>textValue</code> 반응형 변수의 값을 업데이트 하려면 어떻게 해야될까?</p>
<pre><code>
&lt;input
  :value=&quot;textValue&quot;
  @input=&quot;event =&gt; textValue = event.target.value&quot; /&gt;</code></pre><p>value를 바인딩하고 @input이벤트로 textValue의 값을 event.target.value로 변경하는 것이다.
이는 양방향 처리에 있어 꽤나 번거로운 일이다.</p>
<p>그래서 Vue에서는 이러한 작업은 단순화 하도록 양방향을 바인딩할 수 있는 <code>v-model</code>디렉티브를 제공한다.</p>
<pre><code>&lt;input v-model=&quot;textValue&quot; /&gt;</code></pre><p><code>v-model</code> 디렉트브를 이용해 간단하게 양방향 바인딩을 구현할 수 있다.</p>
<img src = "https://velog.velcdn.com/images/falling_star3/post/daab9225-730e-4a90-a694-fc98e9124179/image.png">

<p>이제는 input창에 사용자가 입력한 값이 textValue에 바인딩되어 textValue값이 바뀌는 것을 볼 수 있다.
textarea, checkbox, radio, select 또한 <code>v-model</code>  값을 바인딩한다.</p>
<br>
<br>

<hr>
<h3 id="2-v-model-수식어modifiers">2. v-model 수식어(modifiers)</h3>
<p>1) <strong><code>.lazy</code></strong></p>
<p>기본적으로, <code>v-model</code>은 각 <code>input</code> 이벤트 후 입력과 데이터를 동기화 한다.
<code>lazy</code> 수식어를 추가하여 <code>change</code> 이벤트 이후에 동기화 할 수 있다. </p>
<pre><code class="language-html">&lt;input v-model.lazy=&quot;textValue&quot; /&gt;</code></pre>
<p>이렇게 하면 실시간으로 데이터가 업데이트가 되는 것이 아닌 커서 포인터가 다른 곳을 클릭했을 때 <code>change</code>이벤트가 일어나며 이후에 데이터가 업데이트 된다.</p>
<br>

<p>2) <strong><code>.number</code></strong></p>
<p>사용자 입력이 자동으로 number 타입으로 형변환 되기를 원하면,  <code>.number</code> 수식어를 추가하면 된다.</p>
<pre><code class="language-html">&lt;input v-model.number=&quot;textValue&quot; /&gt;</code></pre>
<p>3) <strong><code>.trim</code></strong></p>
<p>사용자가 입력한 내용에서 자동으로 앞뒤 공백을 제거하는 트림처리가 되길 바란다면, <code>v-model</code>이 관리하는 input에 <code>trim</code> 수식어를 추가하면 된다.</p>
<pre><code class="language-html">&lt;input v-model.trim=&quot;text&quot; /&gt;</code></pre>
<br>
<br>

<hr>
<h4 id="참고문헌">참고문헌</h4>
<p><a href="https://ko.vuejs.org/guide/components/v-model.html">https://ko.vuejs.org/guide/components/v-model.html</a></p>
]]></description>
        </item>
    </channel>
</rss>