<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>JJuuuunn</title>
    <link>https://ysjun96.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 10 Apr 2026 04:12:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>JJuuuunn</managingEditor>
    <image>
      <title>JJuuuunn</title>
      <url>https://tistory1.daumcdn.net/tistory/6812509/attach/29c4ed4b1ad6403e86c12ea1659f9029</url>
      <link>https://ysjun96.tistory.com</link>
    </image>
    <item>
      <title>[DataBase] 트랜잭션 이란?</title>
      <link>https://ysjun96.tistory.com/entry/DataBase-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EC%9D%B4%EB%9E%80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 트랜잭션이란 무엇인가요?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;트랜잭션(Transaction)&lt;/b&gt;이란 데이터베이스의 상태를 변환시키는 하나의 논리적인 작업 단위를 의미합니다. 여러 개의 SQL 명령어(쿼리)가 하나의 묶음처럼 처리되어, 이 묶음 속의 작업들이 모두 성공하거나 (Commit), 모두 실패하여 원래 상태로 되돌아가야 (Rollback) 하는 특성을 가집니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;가장 대표적인 예는 은행 계좌 이체입니다. A 계좌에서 돈을 인출하는 작업과 B 계좌로 돈을 입금하는 작업은 단 하나의 논리적 작업(이체)이며, 둘 중 하나라도 실패하면 데이터의 불일치(돈이 사라지거나 생성됨)가 발생하므로 전체 작업을 취소해야 합니다. 트랜잭션은 이러한 데이터의 &lt;b&gt;일관성&lt;/b&gt;을 보장하는 핵심 메커니즘입니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;6&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 트랜잭션의 핵심: ACID 속성&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;모든 트랜잭션은 데이터의 무결성과 일관성을 보장하기 위해 반드시 ACID라는 네 가지 속성을 만족해야 합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.95353%;&quot;&gt;속성&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;원어&lt;/td&gt;
&lt;td style=&quot;width: 78.721%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.95353%;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;원자성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;Atomicity&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.721%;&quot;&gt;&lt;span data-path-to-node=&quot;9,1,2,0&quot;&gt;트랜잭션 내의 모든 작업은 전부 성공하거나 전부 실패하여 취소되어야 합니다. (All or Nothing)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.95353%;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;일관성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;Consistency&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.721%;&quot;&gt;&lt;span data-path-to-node=&quot;9,2,2,0&quot;&gt;트랜잭션이 성공적으로 완료되면 데이터베이스는 언제나 일관된 상태를 유지해야 합니다. (데이터 제약 조건 준수)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.95353%;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,0,0&quot;&gt;격리성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,1,0&quot;&gt;Isolation&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.721%;&quot;&gt;&lt;span data-path-to-node=&quot;9,3,2,0&quot;&gt;동시에 실행되는 여러 트랜잭션은 서로에게 영향을 미치지 않고 독립적으로 실행되어야 합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.95353%;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,0,0&quot;&gt;영속성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.2093%;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,1,0&quot;&gt;Durability&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.721%;&quot;&gt;&lt;span data-path-to-node=&quot;9,4,2,0&quot;&gt;트랜잭션이 성공적으로 완료(Commit)되면, 그 결과는 시스템 오류에도 불구하고 영구적으로 보존되어야 합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-path-to-node=&quot;10&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 트랜잭션 격리 레벨 상세 분석  &lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;**격리성(Isolation)**은 동시성 제어의 핵심이며, 데이터베이스는 여러 트랜잭션이 동시에 접근할 때 발생하는 충돌(Concurrency Problem)을 방지하기 위해 네 가지 **격리 레벨(Isolation Level)**을 제공합니다. 격리 수준이 높을수록 데이터 일관성은 높아지지만, 동시 처리 성능은 낮아집니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. 동시성 문제 3가지 (격리 레벨이 해결해야 하는 문제)&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;14&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6976%;&quot;&gt;문제 유형&lt;/td&gt;
&lt;td style=&quot;width: 79.1861%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6976%;&quot;&gt;&lt;span data-path-to-node=&quot;14,1,0,0&quot;&gt;Dirty Read&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.1861%;&quot;&gt;&lt;span data-path-to-node=&quot;14,1,1,0&quot;&gt;커밋되지 않은(롤백될 가능성이 있는) 데이터를 다른 트랜잭션이 읽는 현상.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6976%;&quot;&gt;&lt;span data-path-to-node=&quot;14,2,0,0&quot;&gt;Non-Repeatable Read&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.1861%;&quot;&gt;&lt;span data-path-to-node=&quot;14,2,1,0&quot;&gt;한 트랜잭션 내에서 같은 데이터를 두 번 조회했을 때, 그 사이에 다른 트랜잭션이 수정 및 커밋하여 조회 결과가 달라지는 현상.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6976%;&quot;&gt;&lt;span data-path-to-node=&quot;14,3,0,0&quot;&gt;Phantom Read&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.1861%;&quot;&gt;&lt;span data-path-to-node=&quot;14,3,1,0&quot;&gt;한 트랜잭션 내에서 특정 조건으로 레코드를 두 번 조회했을 때, 그 사이에 다른 트랜잭션이 새로운 레코드를 삽입 및 커밋하여 조회 결과의 행 개수가 달라지는 현상.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. 네 가지 격리 레벨과 해결 관계&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;16&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;격리 레벨&lt;/td&gt;
&lt;td&gt;Dirty Read 방지&lt;/td&gt;
&lt;td&gt;Non-Repeatable Read 방지&lt;/td&gt;
&lt;td&gt;Phantom Read 방지&lt;/td&gt;
&lt;td&gt;성능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,0,0&quot;&gt;Read Uncommitted&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,1,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,2,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,3,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,4,0&quot;&gt;가장 높음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,0,0&quot;&gt;Read Committed&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,1,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,2,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,3,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,4,0&quot;&gt;높음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,0,0&quot;&gt;Repeatable Read&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,1,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,2,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,3,0&quot;&gt;&lt;span data-math=&quot;\text{X}&quot;&gt;$\text{X}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,4,0&quot;&gt;보통&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,4,0,0&quot;&gt;Serializable&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,4,1,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,4,2,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,4,3,0&quot;&gt;&lt;span data-math=&quot;\text{O}&quot;&gt;$\text{O}$&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,4,4,0&quot;&gt;가장 낮음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;1. Read Uncommitted (레벨 0)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명: 커밋되지 않은 데이터도 읽기 허용(가장 낮은 격리성).&lt;/li&gt;
&lt;li&gt;주요 문제: Dirty Read 발생. (매우 불안정)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;2. Read Committed (레벨 1)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명: 커밋된 데이터만 읽을 수 있도록 허용. Dirty Read를 방지하는 기본 수준입니다.&lt;/li&gt;
&lt;li&gt;기본 설정: Oracle, SQL Server, PostgreSQL 등 다수 상용 DB의 기본값으로, 일관성과 성능의 적절한 균형을 제공합니다.&lt;/li&gt;
&lt;li&gt;주요 문제: Non-Repeatable Read, Phantom Read는 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;3. Repeatable Read (레벨 2)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명: 트랜잭션 내에서 동일 데이터를 조회하면 항상 같은 값을 보장합니다. Non-Repeatable Read를 방지합니다.&lt;/li&gt;
&lt;li&gt;기본 설정: MySQL의 기본값입니다.&lt;/li&gt;
&lt;li&gt;주요 문제: Phantom Read는 발생할 수 있습니다. (새로운 행 삽입에 대해서는 락을 걸지 못할 수 있음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;4. Serializable (레벨 3)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명: 가장 엄격한 격리 수준으로, 트랜잭션을 순차적으로 실행하는 것과 동일한 효과를 내어 모든 동시성 문제를 해결합니다.&lt;/li&gt;
&lt;li&gt;단점: 동시성이 크게 떨어져 성능 저하가 가장 심합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;25&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Spring Boot에서의 트랜잭션 활용: @Transactional&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot 환경에서는 @Transactional 어노테이션을 사용하여 비즈니스 로직에 트랜잭션을 쉽게 적용할 수 있습니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjM2sHazp2RAxUAAAAAHQAAAAAQ3QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Service
public class UserService {

    @Transactional
    public void transferMoney(Long fromId, Long toId, int amount) {
        // ... 메서드 내용
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 롤백 정책: @Transactional은 기본적으로 언체크 예외 (RuntimeException) 발생 시 Rollback을 수행합니다. 체크 예외 (Exception) 발생 시에는 기본적으로 Commit을 수행합니다.&lt;/li&gt;
&lt;li&gt;격리 레벨 지정: 필요에 따라 격리 레벨을 지정할 수 있습니다.
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Transactional(isolation = Isolation.READ_COMMITTED)
public void readOnlyOperation() { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;30&quot; data-ke-size=&quot;size16&quot;&gt;트랜잭션과 격리 레벨을 이해하는 것은 데이터를 다루는 모든 백엔드 개발자에게 안정적인 시스템 구축을 위한 필수 지식입니다.&lt;/p&gt;</description>
      <category>CS/DataBase</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>transaction</category>
      <category>격리</category>
      <category>데이터베이스</category>
      <category>영속성</category>
      <category>원자성</category>
      <category>일관성</category>
      <category>트랜잭션</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/76</guid>
      <comments>https://ysjun96.tistory.com/entry/DataBase-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EC%9D%B4%EB%9E%80#entry76comment</comments>
      <pubDate>Tue, 2 Dec 2025 20:00:29 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Boot] JPA의 ddl-auto 옵션들</title>
      <link>https://ysjun96.tistory.com/entry/Spring-Boot-JPA%EC%9D%98-ddl-auto-%EC%98%B5%EC%85%98%EB%93%A4</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. ddl-auto란?&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ddl-auto&lt;/b&gt;는 &lt;b&gt;Data Definition Language(DDL)&lt;/b&gt;의 &lt;b&gt;자동&lt;/b&gt; 처리를 의미합니다. 이는 Spring Boot에서 &lt;b&gt;JPA(Java Persistence API) 구현체&lt;/b&gt;인 &lt;b&gt;Hibernate&lt;/b&gt;를 사용할 때 데이터베이스 스키마(테이블, 컬럼, 제약 조건 등)를 애플리케이션 시작 시점에 &lt;b&gt;자동으로 관리&lt;/b&gt;하도록 지시하는 설정 옵션입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말해, 우리가 정의한 &lt;b&gt;JPA 엔티티(Java 클래스)&lt;/b&gt;와 &lt;b&gt;실제 데이터베이스의 스키마&lt;/b&gt;를 동기화하는 방식을 결정하는 핵심 설정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 옵션을 통해 개발자는 매번 수동으로 SQL DDL 문을 작성할 필요 없이 편리하게 스키마를 관리할 수 있지만, 운영 환경에서는 매우 신중하게 사용해야 합니다.(가능한 none 또는 validate 추천)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 설정 파일 위치 (application.yml / application.properties)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 애플리케이션에서 JPA(Hibernate)의 ddl-auto 옵션을 설정하는 가장 기본적인 방법은 설정 파일(yml / properties)을 이용하는 것입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwi9_qu81eeQAxUAAAAAHQAAAAAQcg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;## application.yml
spring:
  jpa:
    hibernate:
      ddl-auto: [원하는 옵션 입력] # 예: none, validate, update, create-drop 등
    show-sql: true # SQL 쿼리 로그 출력 여부 (선택 사항)

## application.properties
spring.jpa.hibernate.ddl-auto=[원하는 옵션 입력] # 예: none
spring.jpa.show-sql=true # SQL 쿼리 로그 출력 여부 (선택 사항)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwi9_qu81eeQAxUAAAAAHQAAAAAQcw&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. ddl-auto 옵션들&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 99.3022%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;ddl-auto 옵션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;&lt;b&gt;동작&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;추천 사용 환경&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;&lt;b&gt;주의사항&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;none&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;스키마 자동 변경 작업 &lt;b&gt;없음&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;프로덕션 (운영)&lt;/b&gt;  &lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;validate&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;엔티티와 DB 스키마 일치 여부 &lt;b&gt;검증&lt;/b&gt;만 수행&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;프로덕션 (운영)&lt;/b&gt;  &lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;일치하지 않으면 앱 시작 실패. 데이터 보호 목적.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;update&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;스키마를 비교하여 &lt;b&gt;차이점만 변경&lt;/b&gt; (데이터 유지)&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;개발&lt;/b&gt;  ️&lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;프로덕션에서 사용 시 예상치 못한 오류 발생 위험이 큽니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;create&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;기존 스키마 &lt;b&gt;삭제&lt;/b&gt; 후 &lt;b&gt;새로 생성&lt;/b&gt; (데이터 삭제)&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;개발 초기&lt;/b&gt;&amp;nbsp; &lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;매번 데이터가 초기화됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.2562%;&quot;&gt;&lt;b&gt;create-drop&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.8299%;&quot;&gt;create 후, 애플리케이션 &lt;b&gt;종료 시 삭제&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 17.226%;&quot;&gt;&lt;b&gt;테스트 환경&lt;/b&gt; ⚙️&lt;/td&gt;
&lt;td style=&quot;width: 31.8793%;&quot;&gt;임시 DB 상태 유지가 필요할 때 유용합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 운영 환경에서 고려하면 좋은 사항  &lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 환경(프로덕션)은 &lt;b&gt;데이터의 무결성과 안정적인 서비스 연속성&lt;/b&gt;이 최우선입니다. 따라서 ddl-auto 옵션은 자동 스키마 변경을 시도하는 update, create, create-drop을 &lt;b&gt;절대 사용해서는 안 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안전한 운영을 위해 고려해야 할 사항은 다음과 같습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4 - 1. ddl-auto 설정의 원칙 준수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 환경에서는 반드시 다음 중 하나의 옵션을 사용하여 Hibernate가 DB 스키마를 건드리지 않도록 해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;none&lt;/b&gt;: 가장 보수적이고 안전한 설정. 스키마 관리 책임을 Hibernate에서 완전히 분리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;validate&lt;/b&gt;: 스키마 변경은 하지 않지만, 앱 시작 시 엔티티와 DB 스키마가 일치하는지 &lt;b&gt;검증&lt;/b&gt;하여 잠재적인 문제를 미리 발견합니다.&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahcKEwi9_qu81eeQAxUAAAAAHQAAAAAQdw&quot; data-hveid=&quot;0&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4 -&lt;span&gt;&amp;nbsp;&lt;/span&gt;2. 데이터베이스 마이그레이션 도구 활용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영 환경에서 스키마 변경이 필요할 때는 Hibernate의 자동 기능을 사용하는 대신, &lt;b&gt;버전 관리&lt;/b&gt;와 &lt;b&gt;롤백 기능&lt;/b&gt;을 제공하는 전문 도구를 사용해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Flyway&lt;/b&gt; 또는 &lt;b&gt;Liquibase&lt;/b&gt;: SQL 스크립트 기반으로 스키마 변경 이력을 관리하여, 배포 시점에 안전하고 제어된 방식으로 스키마 변경을 적용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4 -&lt;span&gt;&amp;nbsp;&lt;/span&gt;3. 환경별 설정 분리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 개발 환경과 운영 환경의 설정 파일을 분리하는 것이 중요합니다. Spring Boot의 &lt;b&gt;Profile 기능&lt;/b&gt;을 사용하여 환경(예: application-dev.yml, application-prod.yml)에 따라 ddl-auto 옵션을 다르게 설정해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개발 환경 예시:&lt;/b&gt; ddl-auto: update&lt;/li&gt;
&lt;li&gt;&lt;b&gt;운영 환경 예시:&lt;/b&gt; ddl-auto: none 또는 ddl-auto: validate&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Backend</category>
      <category>backend</category>
      <category>DATABASE</category>
      <category>DB</category>
      <category>DDL</category>
      <category>Hibernate</category>
      <category>JPA</category>
      <category>springboot</category>
      <category>백엔드</category>
      <category>스프링부트</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/75</guid>
      <comments>https://ysjun96.tistory.com/entry/Spring-Boot-JPA%EC%9D%98-ddl-auto-%EC%98%B5%EC%85%98%EB%93%A4#entry75comment</comments>
      <pubDate>Mon, 10 Nov 2025 22:51:04 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] Watch 사용 시 ref 와 reactive 차이</title>
      <link>https://ysjun96.tistory.com/entry/Vuejs-Watch-%EC%82%AC%EC%9A%A9-%EC%8B%9C-ref-%EC%99%80-reactive-%EC%B0%A8%EC%9D%B4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. &lt;code&gt;ref&lt;/code&gt;와 &lt;code&gt;reactive&lt;/code&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/b&gt;: 주로 원시 타입(String, Number, Boolean 등)을 반응형으로 만들 때 사용하지만, 객체나 배열도 감쌀 수 있습니다.&lt;br /&gt;&lt;b&gt;&lt;code&gt;.value&lt;/code&gt;&lt;/b&gt;를 통해 값에 접근하고 변경합니다.&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;reactive&lt;/code&gt;&lt;/b&gt;: 객체(Object)나 배열(Array)과 같은 참조 타입만을 반응형으로 만들 때 사용합니다. &lt;br /&gt;&lt;b&gt;&lt;code&gt;.value&lt;/code&gt; 없이 직접 속성에 접근하고 변경합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. &lt;code&gt;watch(ref)&lt;/code&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;watch&lt;/code&gt;&lt;/b&gt; 함수에 &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/b&gt;로 선언된 변수를 직접 전달하면, &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;의 &lt;code&gt;.value&lt;/code&gt; 속성 변화를 감지합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;p&amp;gt;Count: {{ count }}&amp;lt;/p&amp;gt;
    &amp;lt;button @click=&quot;increment&quot;&amp;gt;Increment Count&amp;lt;/button&amp;gt;

    &amp;lt;p&amp;gt;User Name: {{ user.name }}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;User Age: {{ user.age }}&amp;lt;/p&amp;gt;
    &amp;lt;button @click=&quot;changeUserName&quot;&amp;gt;Change User Name&amp;lt;/button&amp;gt;
    &amp;lt;button @click=&quot;replaceUser&quot;&amp;gt;Replace User Object&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref, watch } from 'vue';

const count = ref(0);
const user = ref({ name: 'Alice', age: 30 });

watch(count, (newValue, oldValue) =&amp;gt; {
  console.log(`count가 ${oldValue}에서 ${newValue}로 변경되었습니다.`);
});


watch(user, (newValue, oldValue) =&amp;gt; {
  console.log('user 객체가 변경되었습니다.', newValue, oldValue);
}, { deep: true }); // 객체 내부의 변화까지 감지하려면 deep: true 필요

const increment = () =&amp;gt; {
  count.value++;
};

const changeUserName = () =&amp;gt; {
  user.value.name = 'Bob'; // 내부 속성 변경
};

const replaceUser = () =&amp;gt; {
  user.value = { name: 'Charlie', age: 25 }; // 새로운 객체 할당
};
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ref&lt;/code&gt;가 &lt;b&gt;원시 타입&lt;/b&gt;일 경우: &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;의 &lt;code&gt;.value&lt;/code&gt;&lt;/b&gt;가 변경될 때마다 콜백 함수가 실행됩니다.&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ref&lt;/code&gt;가 &lt;b&gt;객체/배열&lt;/b&gt;일 경우: &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;의 &lt;code&gt;.value&lt;/code&gt;&lt;/b&gt;에 새로운 객체/배열이 할당될 때 (즉, 참조가 바뀔 때) 감지됩니다. &lt;br /&gt;&lt;b&gt;객체/배열 &lt;/b&gt;내부의 속성 변화까지 감지하려면 &lt;b&gt;&lt;code&gt;deep: true&lt;/code&gt;&lt;/b&gt;&lt;b&gt;옵션을 사용해야 합니다. &lt;/b&gt;&lt;code&gt;.value&lt;/code&gt;를 직접 감시하는 것은 권장되지 않으며, &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/b&gt;자체를 감시하고&lt;b&gt;&lt;code&gt;deep: true&lt;/code&gt;를 사용하는 것이 일반적입니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. &lt;code&gt;watch(reactive)&lt;/code&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;watch&lt;/code&gt;&lt;/b&gt; 함수에 &lt;b&gt;&lt;code&gt;reactive&lt;/code&gt;&lt;/b&gt;로 선언된 객체를 직접 전달하면, 해당 객체 내부의 모든 속성 변화를 깊게 감지합니다. &lt;b&gt;&lt;code&gt;deep: true&lt;/code&gt;&lt;/b&gt;&lt;code&gt;&lt;/code&gt; 옵션을 명시적으로 설정할 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;p&amp;gt;State Name: {{ state.name }}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;State Age: {{ state.age }}&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;State City: {{ state.address.city }}&amp;lt;/p&amp;gt;
    &amp;lt;button @click=&quot;changeName&quot;&amp;gt;Change Name&amp;lt;/button&amp;gt;
    &amp;lt;button @click=&quot;changeCity&quot;&amp;gt;Change City&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { reactive, watch } from 'vue';

const state = reactive({
  name: 'Alice',
  age: 30,
  address: {
    city: 'Seoul',
    zip: '12345'
  }
});

// reactive 객체 내부의 어떤 속성이든 변화하면 감지 (deep 옵션 불필요)
watch(state, (newValue, oldValue) =&amp;gt; {
  console.log('state 객체에 변경이 발생했습니다.', newValue, oldValue);
});

const changeName = () =&amp;gt; {
  state.name = 'Bob'; // 얕은 속성 변경
};

const changeCity = () =&amp;gt; {
  state.address.city = 'Busan'; // 깊은 속성 변경
};

// reactive 객체 자체를 새로운 객체로 '교체'하는 것은 반응형을 잃게 만듭니다.
// 이는 reactive의 설계 목적과 맞지 않습니다.
// state = { name: 'Charlie', age: 25 }; // 이 방법은 reactive의 반응성을 깨뜨림!
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;reactive&lt;/code&gt;&lt;/b&gt;는 항상 객체/배열만을 다루며, &lt;b&gt;&lt;code&gt;watch&lt;/code&gt;&lt;/b&gt;에 &lt;b&gt;&lt;code&gt;reactive&lt;/code&gt;&lt;/b&gt; 객체를 전달하면 기본적으로 &lt;b&gt;깊은 감지(deep watching)&lt;/b&gt;가 활성화됩니다.&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;reactive&lt;/code&gt; 객체 자체를 새로운 객체로 재할당하는 것은 반응성을 잃게 만듭니다.&lt;/b&gt; &lt;b&gt;&lt;code&gt;reactive&lt;/code&gt;&lt;/b&gt;는 객체 내부의 변경에 최적화되어 있습니다. 만약 객체 자체를 교체해야 한다면 &lt;b&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/b&gt;를 사용하는 것이 더 적합할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 언제 무엇을 사용해야 할까?&lt;/h2&gt;
&lt;figure class=&quot;table-row&quot; contenteditable=&quot;false&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/figure&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 111px;&quot;&gt;구분&lt;/th&gt;
&lt;th style=&quot;width: 419px;&quot;&gt;&lt;code&gt;watch(ref)&lt;/code&gt;&lt;/th&gt;
&lt;th style=&quot;width: 322px;&quot;&gt;&lt;code&gt;watch(reactive)&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;b&gt;감지 대상&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 419px;&quot;&gt;&lt;b&gt;&lt;code&gt;ref&lt;/code&gt;의 &lt;code&gt;.value&lt;/code&gt;의 변화&lt;/b&gt; (원시 타입, 객체/배열 교체)&lt;/td&gt;
&lt;td style=&quot;width: 322px;&quot;&gt;&lt;b&gt;&lt;code&gt;reactive&lt;/code&gt; 객체 내부의 모든 속성 변화&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;b&gt;깊은 감지&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 419px;&quot;&gt;객체/배열일 경우 &lt;b&gt;&lt;code&gt;deep: true&lt;/code&gt; 옵션 필요&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 322px;&quot;&gt;&lt;b&gt;기본적으로 깊은 감지 활성화&lt;/b&gt; (옵션 불필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;b&gt;새로운 객체 할당&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 419px;&quot;&gt;&lt;code&gt;ref.value = newObject&lt;/code&gt; 형태로 객체 교체 가능&lt;/td&gt;
&lt;td style=&quot;width: 322px;&quot;&gt;&lt;code&gt;reactive&lt;/code&gt; 객체 자체 교체는 &lt;b&gt;반응성을 잃음&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;b&gt;주요 사용처&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 419px;&quot;&gt;- 단일 원시 값의 변화 감지&lt;br /&gt;- 객체/배열의 &lt;b&gt;참조 변경&lt;/b&gt; 감지&lt;br /&gt;- 특정 객체/배열의 내부 깊은 변화를 &lt;b&gt;선택적으로&lt;/b&gt; 감지 &lt;br /&gt;(&lt;code&gt;deep: true&lt;/code&gt;와 함께)&lt;/td&gt;
&lt;td style=&quot;width: 322px;&quot;&gt;- 복잡한 객체/배열의 다양한 내부 속성 변화 감지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;b&gt;주의 사항&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 419px;&quot;&gt;객체/배열 내부 변화 감지 시 &lt;code&gt;deep: true&lt;/code&gt; 사용 여부 고려&lt;/td&gt;
&lt;td style=&quot;width: 322px;&quot;&gt;&lt;b&gt;&lt;code&gt;reactive&lt;/code&gt; 객체 자체를 통째로 교체하지 말 것&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;figure class=&quot;table-row&quot; contenteditable=&quot;false&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론적으로:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단일 값 (원시 타입 또는 참조 자체가 중요한 객체/배열)&lt;/b&gt;의 변화를 감지할 때는 &lt;b&gt;&lt;code&gt;watch(ref)&lt;/code&gt;&lt;/b&gt;를 사용하고 필요에 따라 &lt;code&gt;deep: true&lt;/code&gt;를 고려&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;복잡한 객체/배열&lt;/b&gt;의 내부 속성 변경을 자동으로 깊게 감지하고 싶을 때는 &lt;b&gt;&lt;code&gt;watch(reactive)&lt;/code&gt;&lt;/b&gt;를 사용하는 것이 편리합니다. 단, &lt;b&gt;&lt;code&gt;reactive&lt;/code&gt; 객체 자체를 통째로 교체하는 상황은 피해야 합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Frondend/Vue.js</category>
      <category>Deep</category>
      <category>javascript</category>
      <category>js</category>
      <category>reactive</category>
      <category>Ref</category>
      <category>VUE</category>
      <category>Watch</category>
      <category>객체</category>
      <category>깊은 감시</category>
      <category>반응형</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/74</guid>
      <comments>https://ysjun96.tistory.com/entry/Vuejs-Watch-%EC%82%AC%EC%9A%A9-%EC%8B%9C-ref-%EC%99%80-reactive-%EC%B0%A8%EC%9D%B4#entry74comment</comments>
      <pubDate>Sun, 3 Aug 2025 10:33:14 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] Grid에서 % 와 fr 단위 차이</title>
      <link>https://ysjun96.tistory.com/entry/CSS-Grid%EC%97%90%EC%84%9C-%EC%99%80-fr-%EB%8B%A8%EC%9C%84-%EC%B0%A8%EC%9D%B4</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Intro&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 프로젝트를 진행하는 도중 Grid를 사용하여 레이아웃을 짜는 도중에 row가 5줄이고 각각 14px 만큼 gap을 가지는 레이아웃을 만들기 위해 처음에는 % 단위를 사용하여 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;grid-template-rows&lt;/span&gt;를 값을 넣고 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;row-gap&lt;/span&gt;을 추가하였을 때 전체 높이(height)가 부모 요소의 크기를 초과하는 문제가 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해 fr 단위를 사용했더니 정확히 부모 요소 높이에 맞춰서 원하는 레이아웃이 배치가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 정리하며 CSS Grid에서 %와 fr 단위의 차이를 알아보려 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;문제 원인&lt;/h2&gt;
&lt;pre id=&quot;code_1747794272842&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;grid-template-rows: repeat(5, 20%);
row-gap: 14px;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;% 단위는 부모 요소의 height를 기준으로 계산되기에 위와 같이 CSS 를 적용 시키면 gap은 계산에 포함되지 않고 별도로 추가 되어 전체 높이(height)는&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;(20% + 20% +&amp;nbsp; 20% +&amp;nbsp; 20% +&amp;nbsp; 20%) + (14px * 4) = 100% + 56px&lt;/span&gt; 이 되어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결 방법 : fr&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;% 단위 대신 fr 단위를 사용할 경우 전체 높이(height)에서 먼저 gap 의 총 크기를 먼저 계산 한 후 남은 공간에 대해서 계산이 들어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fr (fraction)은 남은 공간을 기준으로 비율을 나누기 때문에 아래와 같이 작성하면,&lt;/p&gt;
&lt;pre id=&quot;code_1747795022634&quot; class=&quot;css&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;css&quot;&gt;&lt;code&gt;grid-template-rows: repeat(5, 1fr);
row-gap: 14px;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 row의 크기는 (100% - (14px * 4)) / 5 의 크기가 되어 부모 요소의 크기보다 커지는 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;fr은&amp;nbsp;gap까지&amp;nbsp;고려된&amp;nbsp;상태에서&amp;nbsp;균등&amp;nbsp;분배되는&amp;nbsp;구조&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1606&quot; data-start=&quot;1413&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;%&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;fr (fraction)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1494&quot; data-start=&quot;1455&quot;&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1460&quot; data-start=&quot;1455&quot;&gt;기준&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1472&quot; data-start=&quot;1460&quot;&gt;부모 요소의 크기&lt;/td&gt;
&lt;td data-end=&quot;1494&quot; data-start=&quot;1472&quot; data-col-size=&quot;sm&quot;&gt;&lt;b&gt;gap을 제외한 남은 공간&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1529&quot; data-start=&quot;1495&quot;&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1504&quot; data-start=&quot;1495&quot;&gt;gap 고려&lt;/td&gt;
&lt;td data-end=&quot;1514&quot; data-start=&quot;1504&quot; data-col-size=&quot;sm&quot;&gt;❌ (무시됨)&lt;/td&gt;
&lt;td data-end=&quot;1529&quot; data-start=&quot;1514&quot; data-col-size=&quot;sm&quot;&gt;✅ (제외 후 분배)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1556&quot; data-start=&quot;1530&quot;&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1545&quot; data-start=&quot;1530&quot;&gt;실제 높이 초과 가능성&lt;/td&gt;
&lt;td data-end=&quot;1550&quot; data-start=&quot;1545&quot; data-col-size=&quot;sm&quot;&gt;있음&lt;/td&gt;
&lt;td data-end=&quot;1556&quot; data-start=&quot;1550&quot; data-col-size=&quot;sm&quot;&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1606&quot; data-start=&quot;1557&quot;&gt;
&lt;td style=&quot;text-align: center;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1566&quot; data-start=&quot;1557&quot;&gt;유용한 상황&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1584&quot; data-start=&quot;1566&quot;&gt;부모 크기 정확히 아는 경우&lt;/td&gt;
&lt;td data-end=&quot;1606&quot; data-start=&quot;1584&quot; data-col-size=&quot;sm&quot;&gt;동적 높이, 균등 분배할 때 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Frondend/Css</category>
      <category>%</category>
      <category>css</category>
      <category>fr</category>
      <category>Fraction</category>
      <category>frontend</category>
      <category>GRID</category>
      <category>grid-template</category>
      <category>grid-template-rows</category>
      <category>Row</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/73</guid>
      <comments>https://ysjun96.tistory.com/entry/CSS-Grid%EC%97%90%EC%84%9C-%EC%99%80-fr-%EB%8B%A8%EC%9C%84-%EC%B0%A8%EC%9D%B4#entry73comment</comments>
      <pubDate>Wed, 21 May 2025 12:40:43 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] Closure 란?</title>
      <link>https://ysjun96.tistory.com/entry/JavaScript-Closure-%EB%9E%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;JavaScript에서 클로저(Closure)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저(Closure)는 함수가 자신이 선언된 렉시컬 환경(Lexical Environment)을 기억하고, 그 환경에 접근할 수 있는 기능을 의미합니다. 즉, 내부 함수가 외부 함수의 변수에 접근할 수 있으며, 외부 함수 실행이 끝난 후에도 변수의 값을 유지할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클로저의 기본 개념&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;함수 내부에서 선언된 함수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 보통 함수 내부에서 정의된 또 다른 함수로 구성됩니다. 내부 함수는 외부 함수의 변수를 참조할 수 있으며, 외부 함수 실행이 종료된 후에도 변수의 값을 유지합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;예제 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function outerFunction(outerVariable) {
    return function innerFunction(innerVariable) {
        console.log(`Outer Variable: ${outerVariable}, Inner Variable: ${innerVariable}`);
    };
}

const newFunction = outerFunction('Hello');
newFunction('World'); // Outer Variable: Hello, Inner Variable: World&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클로저의 활용 사례&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 은닉 (Encapsulation)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저를 활용하면 외부에서 직접 접근할 수 없는 변수를 만들고, 특정 함수만이 이를 조작할 수 있도록 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function counter() {
    let count = 0;
    return {
        increment: function () {
            count++;
            console.log(count);
        },
        decrement: function () {
            count--;
            console.log(count);
        }
    };
}

const myCounter = counter();

myCounter.increment(); // 1
myCounter.increment(); // 2
myCounter.decrement(); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이벤트 리스너와 클로저&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 이벤트 핸들러에서도 유용하게 사용됩니다. 예를 들어, 버튼을 클릭할 때 특정 값을 유지하고 싶을 때 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function attachClickEvent(buttonId) {
    let count = 0;
    document.getElementById(buttonId).addEventListener('click', function () {
        count++;
        console.log(`Button clicked ${count} times`);
    });
}
attachClickEvent('myButton');
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;closure 를 사용하여 memoize 구현하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;closure를 사용하여 memoize 함수 안에 캐시 기능을 하는 map 객체를 구현하여 동일한 인자값을 들어오는 경우 불필요한 연산 처리 없이 바로 값을 리턴하도록 구현&lt;/p&gt;
&lt;pre id=&quot;code_1743251878418&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const memoize = (func) =&amp;gt; {
    const cache = new Map();
    return (x) =&amp;gt; {
        if (cache.has(x)) {
            console.log('캐시에서 가져옴');
        }

        const result = func(x);
        cache.set(x, result);
        
        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클로저의 주의점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;메모리 관리&lt;br /&gt;클로저는 외부 함수의 변수를 유지하기 때문에 불필요한 메모리 사용을 초래할 수 있습니다. 따라서, 사용이 끝난 클로저는 참조를 제거하여 가비지 컬렉션이 가능하도록 해야 합니다.&lt;/li&gt;
&lt;li&gt;성능 이슈&lt;br /&gt;클로저가 너무 많아지면 성능 저하를 유발할 수 있으므로, 필요할 때만 사용하도록 주의해야 합니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Frondend/JavaScript</category>
      <category>closure</category>
      <category>javascript</category>
      <category>memoize</category>
      <category>렉시컬 환경</category>
      <category>메모리</category>
      <category>자바스크립트</category>
      <category>클로저</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/72</guid>
      <comments>https://ysjun96.tistory.com/entry/JavaScript-Closure-%EB%9E%80#entry72comment</comments>
      <pubDate>Sat, 29 Mar 2025 21:39:49 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] 리스트 렌더링</title>
      <link>https://ysjun96.tistory.com/entry/Vuejs-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%A0%8C%EB%8D%94%EB%A7%81</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Vue.js 리스트 렌더링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js에서 리스트 렌더링은 배열이나 객체를 기반으로 동적인 목록을 생성하는 데 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 &lt;code&gt;v-for&lt;/code&gt; 디렉티브를 사용하며, 각 항목을 반복하여 렌더링할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본적인 &lt;code&gt;v-for&lt;/code&gt; 사용법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;v-for&lt;/code&gt; 디렉티브는 배열의 각 요소를 반복하여 출력할 때 사용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 숫자 범위
&amp;lt;ul&amp;gt;
  &amp;lt;li v-for=&quot;n in 10&quot;&amp;gt;
    {{ n }}
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

// 배열 또는 객체
&amp;lt;ul&amp;gt;
  &amp;lt;li v-for=&quot;item in items&quot;&amp;gt;
    {{ item.text }}
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱스 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 선택 인자를 통해서 인덱스를 가져와서 사용할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li v-for=&quot;(item, index) in items&quot;&amp;gt;
    {{ index + 1 }}번쨰 : {{ item.text }}
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체 사용시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 속성을 반복할 때, 객체를 받아서 사용할 수도 잇찌만 아래와 같이 value, key 형식으로 따로 받아서 사용가능 하며 이때는 세번째에 선택인자로 인덱스를 가져올 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li v-for=&quot;(value, key) in myObject&quot; :key=&quot;key&quot;&amp;gt;
    {{ key }}: {{ value }}
  &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Key 속성을 통한 상태 유지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v-for로 렌더링 된 리스트를 업데이트 할 경우 기본적으로 in-place patch 전략을 사용하며 아이템의 순서가 변경된 경우 DOM 요소를 이동하는 대신 변경이 필요한 인덱스의 요소를 패치하여 렌더링 합니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리스트 업데이트 시 주의점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Vue는 리스트 업데이트 시 &lt;code&gt;:key&lt;/code&gt;를 사용하여 효율적으로 DOM을 갱신합니다.&lt;/li&gt;
&lt;li&gt;가능하면 고유한 &lt;code&gt;id&lt;/code&gt; 값을 &lt;code&gt;:key&lt;/code&gt;에 지정하는 것이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;v-if와 v-for를 같이 사용한 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v-if가 우선순위가 더 높으므로 v-if가 먼저 동작한 뒤 v-for가 동작합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js의 리스트 렌더링은 &lt;code&gt;v-for&lt;/code&gt; 디렉티브를 활용하여 쉽게 구현할 수 있으며, 배열뿐만 아니라 객체에도 적용할 수 있습니다. 성능 최적화를 위해 &lt;code&gt;:key&lt;/code&gt; 속성을 적절히 활용하는 것이 중요합니다.&lt;/p&gt;</description>
      <category>Frondend/Vue.js</category>
      <category>For</category>
      <category>frontend</category>
      <category>in-place patch</category>
      <category>Key</category>
      <category>v-for</category>
      <category>Vue.js</category>
      <category>객체</category>
      <category>렌더링</category>
      <category>리스트</category>
      <category>리스트 렌더링</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/71</guid>
      <comments>https://ysjun96.tistory.com/entry/Vuejs-%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%A0%8C%EB%8D%94%EB%A7%81#entry71comment</comments>
      <pubDate>Sat, 22 Mar 2025 16:00:07 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] 조건부 렌더링</title>
      <link>https://ysjun96.tistory.com/entry/Vuejs-%EC%A1%B0%EA%B1%B4%EB%B6%80-%EB%A0%8C%EB%8D%94%EB%A7%81</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Vue.js 조건부 렌더링이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js에서 조건부 렌더링이란 특정 조건에 따라 DOM 요소를 표시하거나 제거하는 기능을 의미하며, 이를 통해 사용자는 동적으로 화면을 구성할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;v-if&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;v-if&lt;/code&gt;는 조건이 참일 경우 요소를 렌더링하고, 거짓이면 DOM에서 제거합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;button v-if=&quot;isVisible&quot; @click=&quot;isVisible = false&quot;&amp;gt;내용 숨기기&amp;lt;/button&amp;gt;
  &amp;lt;button v-else @click=&quot;isVisible = true&quot;&amp;gt;내용 보이기&amp;lt;/button&amp;gt;
  &amp;lt;p v-if=&quot;isVisible&quot;&amp;gt;v-if를 이용하여 내용이 사라지게도 보이게 할 수 있습니다.&amp;lt;/p&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref } from 'vue'

const isVisible = ref(true);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;v-else 및 v-else-if&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;v-else&lt;/code&gt;는 &lt;code&gt;v-if&lt;/code&gt; 조건이 거짓일 때만 요소를 렌더링하며, &lt;code&gt;v-else-if&lt;/code&gt;는 추가적인 조건을 설정할 때 사용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;p v-if=&quot;status === 'A'&quot;&amp;gt;버튼 A를 눌렀습니다.&amp;lt;/p&amp;gt;
  &amp;lt;p v-else-if=&quot;status === 'B'&quot;&amp;gt;버튼 B를 눌렀습니다.&amp;lt;/p&amp;gt;
  &amp;lt;p v-else&amp;gt;나머지 버튼들을 눌렀습니다.&amp;lt;/p&amp;gt;
  &amp;lt;button @click=&quot;status = 'A'&quot;&amp;gt;버튼 A&amp;lt;/button&amp;gt;
  &amp;lt;button @click=&quot;status = 'B'&quot;&amp;gt;버튼 B&amp;lt;/button&amp;gt;
  &amp;lt;button @click=&quot;status = 'C'&quot;&amp;gt;버튼 C&amp;lt;/button&amp;gt;
  &amp;lt;button @click=&quot;status = 'D'&quot;&amp;gt;버튼 D&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref } from 'vue'

const status = ref(&quot;loading&quot;);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;v-show&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;v-show&lt;/code&gt;는 &lt;code&gt;display&lt;/code&gt; 속성을 변경하여 요소를 숨깁니다. &lt;code&gt;v-if&lt;/code&gt;와 달리 요소를 제거하지 않으므로, 자주 변경되는 경우에 더 적합합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;app&quot;&amp;gt;
  &amp;lt;p v-show=&quot;isVisible&quot;&amp;gt;이 문장은 보일 수도 있고 숨겨질 수도 있습니다.&amp;lt;/p&amp;gt;
  &amp;lt;button @click=&quot;isVisible = !isVisible&quot;&amp;gt;토글&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
  const app = Vue.createApp({
    data() {
      return {
        isVisible: true
      };
    }
  }).mount(&quot;#app&quot;);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-size: 1.62em;&quot;&gt;결론&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js의 조건부 렌더링을 사용하면 동적으로 요소를 표시하거나 숨길 수 있으며, &lt;code&gt;v-if&lt;/code&gt;는 조건에 충족하지 못하는 경우 DOM을 조작하여 요소를 제거하고, &lt;code&gt;v-show&lt;/code&gt;는 CSS를 사용하여(display: none;) 요소를 숨깁니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 렌더링 시 부담을 줄이고 싶은 경우에는 v-if를 사용하고, 자주 변경이 필요한 경우에는 v-show를 사용하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frondend/Vue.js</category>
      <category>frontend</category>
      <category>v-else</category>
      <category>v-else-if</category>
      <category>v-if</category>
      <category>v-show</category>
      <category>Vue.js</category>
      <category>디렉티브</category>
      <category>렌더링</category>
      <category>조건부 렌더링</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/70</guid>
      <comments>https://ysjun96.tistory.com/entry/Vuejs-%EC%A1%B0%EA%B1%B4%EB%B6%80-%EB%A0%8C%EB%8D%94%EB%A7%81#entry70comment</comments>
      <pubDate>Fri, 21 Mar 2025 20:00:36 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] ref 와 reactive 차이점</title>
      <link>https://ysjun96.tistory.com/entry/Vuejs-ref-%EC%99%80-reactive-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Vue.js에서 상태 관리를 위해 &lt;code&gt;ref&lt;/code&gt;와 &lt;code&gt;reactive&lt;/code&gt;를 사용할 수 있습니다. 두 방식 모두 반응형(Reactivity) 시스템을 제공하지만, 사용 방법과 동작 방식에서 차이가 있다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ref란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ref&lt;/code&gt;는 Vue 3에서 제공하는 반응형 상태 관리 방법 중 하나로, 기본형(Primitive) 데이터와 객체(Object) 모두를 반응형 상태로 만들 수 있습니다. 반응형 변수를 개별적으로 관리할 때 유용하며, 값에 접근할 때 &lt;code&gt;.value&lt;/code&gt;를 사용해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ref의 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본형 데이터(숫자, 문자열, 불리언 등)와 객체를 감쌀 수 있음&lt;/li&gt;
&lt;li&gt;반응형으로 관리하기 위해 &lt;code&gt;.value&lt;/code&gt; 프로퍼티를 사용&lt;/li&gt;
&lt;li&gt;템플릿에서 자동으로 언래핑(자동으로 &lt;code&gt;.value&lt;/code&gt;가 적용됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본형 데이터에서 ref 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형 데이터를 다룰 때 &lt;code&gt;ref&lt;/code&gt;를 사용하는 예제입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);
    
    function increment() {
      count.value++;
    }
    
    return { count, increment };
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체에서 ref 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 &lt;code&gt;ref&lt;/code&gt;로 감싸는 경우에도 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ref } from 'vue';

export default {
  setup() {
    const user = ref({ name: 'Alice', age: 25 });
    
    function updateAge() {
      user.value.age++;
    }
    
    return { user, updateAge };
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ref의 자동 언래핑(Auto-unwrapping)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿에서는 &lt;code&gt;.value&lt;/code&gt;를 사용하지 않아도 자동으로 반응형 데이터가 접근됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;p&amp;gt;Count: {{ count }}&amp;lt;/p&amp;gt;
  &amp;lt;button @click=&quot;increment&quot;&amp;gt;증가&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;reactive란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;reactive&lt;/code&gt;는 객체(Object)만 반응형으로 만들 수 있으며, 속성 그대로 접근할 수 있습니다. &lt;code&gt;reactive&lt;/code&gt;를 사용하면 객체 내부의 모든 속성이 반응형으로 처리됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;reactive 예제&lt;/h3&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: 0
    });
    
    function increment() {
      state.count++;
    }
    
    return { state, increment };
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ref와 reactive의 차이점&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;ref&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;reactive&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;기본형 데이터와 객체 모두 감싸서 반응형 상태로 변환&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;객체만 반응형 상태로 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;code&gt;.value&lt;/code&gt;를 사용하여 값에 접근&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;속성 그대로 접근 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;반응형 변수를 개별적으로 관리 가능&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;객체의 모든 속성이 반응형으로 처리됨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ref&lt;/code&gt;는 기본형 데이터와 객체 모두를 반응형으로 만들 수 있으며, &lt;code&gt;.value&lt;/code&gt;를 통해 접근해야 합니다. 반면, &lt;code&gt;reactive&lt;/code&gt;는 객체만 반응형으로 만들 수 있으며, &lt;code&gt;.value&lt;/code&gt; 없이 속성 그대로 접근할 수 있습니다. 프로젝트의 요구사항에 맞춰 적절한 방식을 선택하는 것이 중요합니다.&lt;/p&gt;</description>
      <category>Frondend/Vue.js</category>
      <category>composition API</category>
      <category>reactive</category>
      <category>Ref</category>
      <category>Set Up</category>
      <category>VUE</category>
      <category>Vue 3</category>
      <category>반응형</category>
      <category>상태관리</category>
      <category>프론트엔드</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/68</guid>
      <comments>https://ysjun96.tistory.com/entry/Vuejs-ref-%EC%99%80-reactive-%EC%B0%A8%EC%9D%B4%EC%A0%90#entry68comment</comments>
      <pubDate>Mon, 3 Mar 2025 23:06:40 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] LocalStorage 와 SessionStorage</title>
      <link>https://ysjun96.tistory.com/entry/HTML-LocalStorage-%EC%99%80-SessionStorage</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;WebStorage(웹 스토리지)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Web Storage(웹 스토리지) 는 브라우저에 데이터를 저장하는 방법 중 하나로, 클라이언트 측에서 데이터를 영구적 또는 일시적으로 저장할 수 있도록 합니다. 대표적으로 &lt;b&gt;LocalStorage&lt;/b&gt;와 &lt;b&gt;SessionStorage&lt;/b&gt;가 있으며, 기존의 쿠키(Cookie)보다 더 많은 데이터를 저장할 수 있고 보안적으로도 안전합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LocalStorage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LocalStorage는 사용자가 데이터를 삭제하지 않는 한 브라우저에 영구적으로 저장됩니다. 즉, 페이지를 닫거나 브라우저를 종료해도 데이터가 유지됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// LocalStorage 데이터 저장
localStorage.setItem('username', 'JohnDoe');

// 데이터 가져오기
const user = localStorage.getItem('username');
console.log(user); // JohnDoe

// 데이터 삭제
localStorage.removeItem('username');
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SessionStorage&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SessionStorage는 사용자가 페이지를 닫거나 브라우저를 종료하면 데이터가 자동으로 삭제됩니다. 즉, 세션이 유지되는 동안만 데이터를 저장합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SessionStorage 데이터 저장
sessionStorage.setItem('sessionData', 'Temporary Info');

// 데이터 가져오기
const sessionData = sessionStorage.getItem('sessionData');
console.log(sessionData); // Temporary Info

// 데이터 삭제
sessionStorage.removeItem('sessionData');
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;쿠키(Cookie)란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키는 웹 사이트가 사용자의 브라우저에 저장하는 작은 데이터 파일입니다. 주로 사용자 인증, 세션 유지, 광고 추적 등에 사용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 쿠키 저장 (유효기간 설정)
document.cookie = &quot;username=JohnDoe; expires=Fri, 31 Dec 2025 23:59:59 GMT; path=/&quot;;

// 쿠키 가져오기
console.log(document.cookie);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LocalStorage, SessionStorage, 쿠키 비교&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7675%; text-align: center;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.4186%; text-align: center;&quot;&gt;&lt;b&gt;LocalStorage&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 23%; text-align: center;&quot;&gt;&lt;b&gt;SessionStorage&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.8139%; text-align: center;&quot;&gt;&lt;b&gt;Cookie(쿠키)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7675%; text-align: center;&quot;&gt;데이터 유지 기간&lt;/td&gt;
&lt;td style=&quot;width: 22.4186%;&quot;&gt;영구적&lt;/td&gt;
&lt;td style=&quot;width: 23%;&quot;&gt;세션 종료 시 삭제&lt;/td&gt;
&lt;td style=&quot;width: 68.8139%;&quot;&gt;설정된 만료일에 따라 다름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7675%; text-align: center;&quot;&gt;저장 용량&lt;/td&gt;
&lt;td style=&quot;width: 22.4186%;&quot;&gt;최대 5MB&lt;/td&gt;
&lt;td style=&quot;width: 23%;&quot;&gt;최대 5MB&lt;/td&gt;
&lt;td style=&quot;width: 68.8139%;&quot;&gt;약 4KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7675%; text-align: center;&quot;&gt;서버 전송&lt;/td&gt;
&lt;td style=&quot;width: 22.4186%;&quot;&gt;전송되지 않음&lt;/td&gt;
&lt;td style=&quot;width: 23%;&quot;&gt;전송되지 않음&lt;/td&gt;
&lt;td style=&quot;width: 68.8139%;&quot;&gt;매 요청마다 서버로 전송됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7675%; text-align: center;&quot;&gt;보안&lt;/td&gt;
&lt;td style=&quot;width: 22.4186%;&quot;&gt;JavaScript에서 접근 가능 (XSS 공격 주의)&lt;/td&gt;
&lt;td style=&quot;width: 23%;&quot;&gt;JavaScript에서 접근 가능 (XSS 공격 주의)&lt;/td&gt;
&lt;td style=&quot;width: 68.8139%;&quot;&gt;보안 취약 (HTTPOnly 옵션 사용 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LocalStorage와 SessionStorage는 쿠키보다 더 많은 데이터를 저장할 수 있고, HTTP 요청 시 불필요한 데이터 전송을 방지할 수 있는 장점이 있습니다. 그러나 XSS 공격에 취약할 수 있으므로 민감한 정보는 저장하지 않는 것이 좋습니다. 쿠키는 서버와의 통신이 필요한 경우 유용하지만, 데이터 용량이 작고 보안 취약점이 존재하므로 사용 시 주의해야 합니다.&lt;/p&gt;</description>
      <category>Frondend</category>
      <category>axios</category>
      <category>interceptor</category>
      <category>request</category>
      <category>response</category>
      <category>transform</category>
      <category>엑시오스</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/67</guid>
      <comments>https://ysjun96.tistory.com/entry/HTML-LocalStorage-%EC%99%80-SessionStorage#entry67comment</comments>
      <pubDate>Thu, 20 Feb 2025 16:00:56 +0900</pubDate>
    </item>
    <item>
      <title>[Frontend] Axios Interceptor vs Transform(Request/Response)</title>
      <link>https://ysjun96.tistory.com/entry/Frontend-Axios-Interceptor-vs-TransformRequestResponse</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Axios란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는 브라우저와 Node.js 환경에서 사용 가능한 HTTP 클라이언트 라이브러리입니다. 주로 API 요청을 보낼 때 사용되며, 응답을 처리하는 기능을 제공합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Axios Interceptor&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Interceptor는 요청(request) 또는 응답(response)이 처리되기 전후에 실행되는 기능입니다. 이를 통해 공통적인 요청/응답 로직을 중앙에서 관리할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요청 인터셉터(Request Interceptor)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 보내기 전에 특정 작업을 수행할 수 있습니다. 예를 들어, 모든 요청에 인증 토큰을 추가하는 경우가 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios.interceptors.request.use(
  (config) =&amp;gt; {
    config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
    return config;
  },
  (error) =&amp;gt; {
    return Promise.reject(error);
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;응답 인터셉터(Response Interceptor)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 응답을 받은 후 데이터 변환, 오류 처리 등을 수행할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios.interceptors.response.use(
  (response) =&amp;gt; {
    return response.data; // 응답 데이터만 반환
  },
  (error) =&amp;gt; {
    console.error('API Error:', error);
    return Promise.reject(error);
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Axios Transform(Request/Response)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transform 기능은 요청을 보내거나 응답을 받기 전에 데이터를 변환하는 기능을 제공합니다. 특정 요청 또는 응답에서만 변환이 필요할 때 유용합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요청 데이터 변환(Request Transform)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 보내기 전에 데이터를 변환하는 기능입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios.post('/user', { name: 'John' }, {
  transformRequest: [(data, headers) =&amp;gt; {
    return JSON.stringify(data); // 데이터를 JSON 문자열로 변환
  }]
});&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;응답 데이터 변환(Response Transform)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답을 받은 후 데이터를 가공하는 기능입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739770295134&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios.get('/user', {
  transformResponse: [(data) =&amp;gt; {
    return JSON.parse(data).map(user =&amp;gt; user.name.toUpperCase());
  }]
}).then(response =&amp;gt; console.log(response));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Interceptor vs Transform 비교&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Interceptor&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Transform&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;글로벌하게 요청/응답을 가로채어 처리 가능&lt;/td&gt;
&lt;td&gt;개별 요청/응답에서 데이터 변환 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;모든 API 요청에 공통적인 로직을 적용할 때 사용&lt;/td&gt;
&lt;td&gt;특정 API 요청/응답에서만 변환이 필요할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주로 인증 토큰 추가, 로딩 스피너 표시, 공통 오류 처리 등에 활용&lt;/td&gt;
&lt;td&gt;데이터 포맷 변경, 특정 응답 가공 등에 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios의 Interceptor와 Transform은 각각의 역할이 다릅니다. Interceptor는 모든 요청/응답을 가로채는 데 유용하며, Transform은 특정 요청이나 응답에서만 데이터 변환이 필요할 때 사용됩니다. 개발자는 프로젝트의 요구사항에 따라 적절한 방식을 선택해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;[참고]&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://apidog.com/kr/blog/axios-api-interceptors-2/#axios-api-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;APIDog - Axios 문서&lt;/a&gt;&lt;/p&gt;</description>
      <category>Frondend</category>
      <category>axios</category>
      <category>interceptor</category>
      <category>request</category>
      <category>response</category>
      <category>transform</category>
      <category>엑시오스</category>
      <author>JJuuuunn</author>
      <guid isPermaLink="true">https://ysjun96.tistory.com/66</guid>
      <comments>https://ysjun96.tistory.com/entry/Frontend-Axios-Interceptor-vs-TransformRequestResponse#entry66comment</comments>
      <pubDate>Tue, 18 Feb 2025 23:00:04 +0900</pubDate>
    </item>
  </channel>
</rss>