<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>서카츄</title>
    <link>https://seokachu.tistory.com/</link>
    <description>  seokachuu@gmail.com
</description>
    <language>ko</language>
    <pubDate>Tue, 7 Apr 2026 08:30:51 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>서카츄</managingEditor>
    <image>
      <title>서카츄</title>
      <url>https://tistory1.daumcdn.net/tistory/5734099/attach/c4ebeee64294443c81ef6c08457ad4d2</url>
      <link>https://seokachu.tistory.com</link>
    </image>
    <item>
      <title>AI로 완벽한 웹사이트를 만드는 5가지 전략</title>
      <link>https://seokachu.tistory.com/400</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;1094&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVX7qQ/dJMcagZhEI0/nSFIq74kTQI5vFpisAfZ4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVX7qQ/dJMcagZhEI0/nSFIq74kTQI5vFpisAfZ4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVX7qQ/dJMcagZhEI0/nSFIq74kTQI5vFpisAfZ4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVX7qQ%2FdJMcagZhEI0%2FnSFIq74kTQI5vFpisAfZ4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1366&quot; height=&quot;1094&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;1094&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;AI라는 마법사에게 '제대로' 명령하는 법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 개발자와 기획자들이 AI를 활용해 웹사이트 제작에 도전하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이내 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&quot;결과물이 모호하다&quot;&lt;/span&gt;거나 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&quot;기대에 못 미친다&quot;&lt;/span&gt;는 &lt;b&gt;기술적 정체(Technical Stagnation)를 경험한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 모든 것을 알아서 해결해 주는 마법사가 아니라, 정교한 설계도에 따라 움직이는 고도의 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;'실행 엔진'&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 도구에 의존하는 사용자를 넘어, AI를 완벽하게 통제하고 지휘하는 마스터의 관점에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조적 결핍을 제거하는 전략이 필요한 시점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NGtL9/dJMcafzkGbJ/4dcy81QWuXAuhHJh0YRWxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NGtL9/dJMcafzkGbJ/4dcy81QWuXAuhHJh0YRWxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NGtL9/dJMcafzkGbJ/4dcy81QWuXAuhHJh0YRWxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNGtL9%2FdJMcafzkGbJ%2F4dcy81QWuXAuhHJh0YRWxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1332&quot; height=&quot;784&quot; data-origin-width=&quot;1332&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 예쁜 디자인보다 '구조의 해부'가 먼저다 (Reverse Engineering)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적인 웹 빌딩의 첫 단추는 시각적인 화려함에 현혹되지 않는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시니어 전략가는 레퍼런스를 대할 때 심미적 감상이 아닌 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;'논리적 해부'&lt;/span&gt;를 시도한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이아웃의 위계, 픽셀(px) 단위의 간격, 그리고 애니메이션의 이면에 숨겨진 알고리즘을 정밀 분석해야 한다.&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; 제미나이(Gemini)와 같은 멀티모달 AI를 활용하여 레퍼런스에서 단순 색상이 아닌, Hex 코드 배열, Rem 기반의 스페이싱 스케일, 애니메이션을 위한 베지에 곡선(Bezier curve) 값 등 정밀한 데이터를 추출한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;논리적 설계의 선행:&lt;/b&gt; 코드를 생성하기 전, 추출된 데이터를 바탕으로 웹사이트의 전체적인 뼈대를 머릿속에 완벽히 구축해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;디자인은 눈이 아니라 논리로 읽어야 하는 것&quot;&lt;/b&gt; 철저한 역설계가 뒷받침될 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI는 비로소 우리가 의도한 정밀한 결과물을 산출하기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/siBaY/dJMcad2v0lK/syOoF3PJRgBbBLU30qT660/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/siBaY/dJMcad2v0lK/syOoF3PJRgBbBLU30qT660/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/siBaY/dJMcad2v0lK/syOoF3PJRgBbBLU30qT660/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsiBaY%2FdJMcad2v0lK%2FsyOoF3PJRgBbBLU30qT660%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1420&quot; height=&quot;794&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;794&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. AI에게 자유를 주지 마라: 도구 실행 전 목표 확정 (Constraint Setting)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI의 성능은 지침이 광범위할 때 저하되며, 구체적이고 좁을수록 압도적으로 극대화됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'멋지게'와 같은 주관적 단어는 AI의 연산력을 낭비하게 만든다&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; '3D 이커머스 기반 스토리텔링'과 같이 목표를 수치화하고, 시간 변수(Time variables)나 사운드 요소까지 코드로 제어하도록 지시해야한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Authority(권한 설정):&lt;/b&gt; AI의 역할과 권한을 명확히 정의하여 임의의 판단을 원천 차단해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Constraint:&lt;/b&gt; &quot;개선하거나 수정하지 말고 레퍼런스와 똑같이 만들 것&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 엄격한 제약은 AI가 기획된 디자인 시스템과 섹션별 규칙에서 벗어나지 않도록 고정하는 핵심 장치가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UYMLG/dJMcaax1p2M/KTic53jJ0zUmgPJOIJU1b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UYMLG/dJMcaax1p2M/KTic53jJ0zUmgPJOIJU1b0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UYMLG/dJMcaax1p2M/KTic53jJ0zUmgPJOIJU1b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUYMLG%2FdJMcaax1p2M%2FKTic53jJ0zUmgPJOIJU1b0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1406&quot; height=&quot;796&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;796&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 마스터 프롬프트 구축 (The Master Blueprint)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과물이 의도와 다르다면, 그것은 피드백이 충분히 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;'데이터화'되지 않았다는 증거&lt;/span&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;좌표 기반의 지시:&lt;/b&gt; &quot;여백을 좀 더 줘&quot;라는 모호한 표현 대신 &quot;히어로 컨테이너 너비 1200px, 중앙 정렬, 상단 패딩 80px&quot;와 같이 수치로 소통해야한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영역의 한정:&lt;/b&gt; 수정 요청 시 &quot;Fix only these items&quot; (맨 마지막에는 이 항목들만 수정해주세요. 이외에 다른것들은 절대 수정하지 마세요) 라는 제약을 반드시 추가하자.&lt;br /&gt;이는 AI가 문제를 해결하는 과정에서 기존의 안정적인 코드를 오염시키는 것을 방지하고, 개발 효율성을 비약적으로 높여줌&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIaPz5/dJMcajuVjfY/Zikz8BNffYbdGk4tfublpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIaPz5/dJMcajuVjfY/Zikz8BNffYbdGk4tfublpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIaPz5/dJMcajuVjfY/Zikz8BNffYbdGk4tfublpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIaPz5%2FdJMcajuVjfY%2FZikz8BNffYbdGk4tfublpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1416&quot; height=&quot;784&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 정밀한 반복 및 피드백 (Iterative Refinement)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 사이트를 한 번에 생성하려는 시도는 구조적 붕괴로 가는 지름길이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 프로젝트일수록 문제를 최소 단위로 격리하여 독립된 환경(Sandboxed Environment)에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 해결하는 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;'단일 작업 원칙'&lt;/span&gt;을 고수해야 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전문가 수준의 격리 및 빌드 프로세스:&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;기초 요소 생성:&lt;/b&gt; 독립된 캔버스에서의 3D 오브젝트 빌드.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특수 효과 적용:&lt;/b&gt; 셰이더(Shader) 작성을 통한 시각적 디테일 완성.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 로직 추가:&lt;/b&gt; 스크롤 애니메이션 및 인터랙티브 요소 구현.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최종 결합:&lt;/b&gt; 개별적으로 검증된 모듈들을 유기적으로 통합.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 문제를 분리하여 해결하면 오류 추적이 용이해지며, 각 모듈의 완성도를 최상으로 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U2UQJ/dJMcajuVjhc/8TGoUFnkWcmkxzg6MDsI11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U2UQJ/dJMcajuVjhc/8TGoUFnkWcmkxzg6MDsI11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U2UQJ/dJMcajuVjhc/8TGoUFnkWcmkxzg6MDsI11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU2UQJ%2FdJMcajuVjhc%2F8TGoUFnkWcmkxzg6MDsI11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1392&quot; height=&quot;812&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. AI는 조수일 뿐, 주도권은 개발자에게 있다 (Owner's Logic)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI가 생성한 코드를 원리도 모른 채 복사하고 붙여넣는 것은 '기술적 부채'를 쌓는 행위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;로직의 100% 이해:&lt;/b&gt; AI가 작성한 코드의 흐름과 아키텍처를 완벽히 파악해야 한다. 이는 단순한 디버깅을 넘어, 향후 유지보수(Maintenance)와 기술적 인수인계(Hand-off)를 위한 필수 조건이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기술적 주권(Technical Sovereignty):&lt;/b&gt; 초안은 AI가 잡을 수 있지만, 결과물의 논리적 완성도를 결정하고 최종 승인하는 주권은 반드시 인간 개발자에게 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로직의 흐름을 장악하는 것이야말로 AI 시대에 대체 불가능한 전문가로 남는 유일한 길이다.&lt;/p&gt;</description>
      <category>  Dev Log/Article</category>
      <category>AI</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/400</guid>
      <comments>https://seokachu.tistory.com/400#entry400comment</comments>
      <pubDate>Wed, 1 Apr 2026 20:28:17 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 Date의 시대가 끝났다: 우리가 Temporal을 기다려온 이유</title>
      <link>https://seokachu.tistory.com/399</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1782&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caY8ZS/dJMcac98SyE/cwTyI9VmwtLDqEKMDwKQA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caY8ZS/dJMcac98SyE/cwTyI9VmwtLDqEKMDwKQA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caY8ZS/dJMcac98SyE/cwTyI9VmwtLDqEKMDwKQA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaY8ZS%2FdJMcac98SyE%2FcwTyI9VmwtLDqEKMDwKQA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1782&quot; height=&quot;1328&quot; data-origin-width=&quot;1782&quot; data-origin-height=&quot;1328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;자바스크립트 생태계에서 수십 년간 괴롭혔던 Date 객체를 뒤로하고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 표준 API인 &lt;b&gt;'Temporal'&lt;/b&gt;이 마침내 들어왔다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LxckG/dJMcagxYwfU/UvMRTfaLwVQ8j2jBeQs9F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LxckG/dJMcagxYwfU/UvMRTfaLwVQ8j2jBeQs9F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LxckG/dJMcagxYwfU/UvMRTfaLwVQ8j2jBeQs9F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLxckG%2FdJMcagxYwfU%2FUvMRTfaLwVQ8j2jBeQs9F1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1536&quot; height=&quot;864&quot; data-origin-width=&quot;1536&quot; data-origin-height=&quot;864&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;자바스크립트 개발자라면 알고 있는 'Date'의 유산&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;자바스크립트의 창시자 브렌던 아이크(Brendan Eich)는 &lt;br /&gt;언어 설계 초기, 당시 대세였던 자바(Java)의 Date 설계를 그대로 가져왔다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 자바스크립트의 유연하고 동적인 특성과 &lt;br /&gt;자바의 정적인 설계 방식은 태생부터 부조화를 이루었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;타임존 계산 오류, 비직관적인 월(Month) 인덱스 등 수많은 버그의 온상이 되었고, &lt;br /&gt;이를 해결하기 위해 Moment.js나 Day.js 같은 외부 라이브러리에 의존하며 기술 부채를 쌓아왔다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn1hY9/dJMcabXLb2s/VkznmdcakeCBSvsKfaknmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn1hY9/dJMcabXLb2s/VkznmdcakeCBSvsKfaknmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn1hY9/dJMcabXLb2s/VkznmdcakeCBSvsKfaknmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn1hY9%2FdJMcabXLb2s%2FVkznmdcakeCBSvsKfaknmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1618&quot; height=&quot;882&quot; data-origin-width=&quot;1618&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;가변성(Mutability)과의 작별: 이제는 '불변성'의 시대&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 Date 객체의 가장 치명적인 결함은 바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;u&gt;'가변성'&lt;/u&gt;&lt;/b&gt;이다.&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;setFullYear() 같은 메서드를 호출하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;원본 객체 자체가 수정되어 버린다.&lt;/b&gt;&lt;br /&gt;이는 의도치 않은 데이터 오염을 발생시키고 코드의 예측 가능성을 심각하게 떨어뜨린다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;908&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqPyP1/dJMcabQYI0Z/kpn9HEGlcUgxuDAm6Qwlk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqPyP1/dJMcabQYI0Z/kpn9HEGlcUgxuDAm6Qwlk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqPyP1/dJMcabQYI0Z/kpn9HEGlcUgxuDAm6Qwlk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqPyP1%2FdJMcabQYI0Z%2Fkpn9HEGlcUgxuDAm6Qwlk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1664&quot; height=&quot;908&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;반면, Temporal은 철저히 &lt;b&gt;불변성(Immutability)&lt;/b&gt;을 지킨다.&lt;br /&gt;add() 메서드 등을 사용해 시간을 조작하면 원본은 그대로 유지되고 &lt;br /&gt;계산된 결과가 담긴 새로운 객체가 반환된다.&lt;br /&gt;&lt;br /&gt;이는 현대 상태 관리 패턴과 완벽히 부합하며, &lt;br /&gt;버그 없는 안정적인 코드를 작성할 수 있게 해준다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서머타임과 타임존: 더 이상 수동 계산은 없다&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b12lup/dJMcahcAUzN/sE21BKoNCaJ0M00xerN1h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b12lup/dJMcahcAUzN/sE21BKoNCaJ0M00xerN1h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b12lup/dJMcahcAUzN/sE21BKoNCaJ0M00xerN1h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb12lup%2FdJMcahcAUzN%2FsE21BKoNCaJ0M00xerN1h0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1660&quot; height=&quot;896&quot; data-origin-width=&quot;1660&quot; data-origin-height=&quot;896&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;글로벌 서비스를 운영할 때 가장 골치 아픈 것이 서머타임(DST)과 타임존 처리이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Temporal은 상황에 맞는 명확한 객체 구분을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.814%; height: 17px;&quot;&gt;Temporal.Instant&lt;/td&gt;
&lt;td style=&quot;width: 64.186%; height: 17px;&quot;&gt;1970년 1월 1일 UTC 기준의 절대적 시점(타임스탬프)을 기록&lt;br /&gt;기존 new Date().getTime()의 표준적 대체재이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.814%; height: 17px;&quot;&gt;Temporal.ZonedDateTime&lt;/td&gt;
&lt;td style=&quot;width: 64.186%; height: 17px;&quot;&gt;타임존과 서머타임 정보가 포함된 객체&lt;br /&gt;예를 들어 서머타임 경계에서 12시 30분에 1시간을 더했을 때, &lt;br /&gt;엔진이 자동으로 시계 바늘이 한 시간 점프하는 것을 인지하여 &lt;br /&gt;2시 30분이라는 정확한 결과를 반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.814%; height: 17px;&quot;&gt;Temporal.PlainDate&lt;/td&gt;
&lt;td style=&quot;width: 64.186%; height: 17px;&quot;&gt;타임존 계산이 필요 없는 순수한 날짜(생일, 기념일 등)를 다룰 때 적합함. &lt;br /&gt;서버와 클라이언트 간의 시차 때문에 생일이 하루 밀리는 등&lt;br /&gt;고질적인 문제를 원천 봉쇄할 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;시간의 '범위'를 다루는 Duration 객체를 새롭게 도입&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N3dE6/dJMcaakfzyC/IOKxXOaEgMZPyRvR3yO3iK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N3dE6/dJMcaakfzyC/IOKxXOaEgMZPyRvR3yO3iK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N3dE6/dJMcaakfzyC/IOKxXOaEgMZPyRvR3yO3iK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN3dE6%2FdJMcaakfzyC%2FIOKxXOaEgMZPyRvR3yO3iK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1634&quot; height=&quot;892&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;130시간 20분은 총 몇 초인가?&quot;&lt;/b&gt;와 같은 &lt;br /&gt;복잡한 시간 단위 변환과 계산을 단 몇 줄의 코드로 명쾌하게 해결할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;또한, 글로벌 표준답게 히브리 달력 등&lt;b&gt; 다양한 달력 체계 옵션을 제공&lt;/b&gt;하며,&lt;br /&gt;inLeapYear 프로퍼티를 통해 해당 연도가 윤년인지 여부를 &lt;br /&gt;즉시 확인할 수 있는 등 실무에서 유용한 세부 기능을 대거 포함하고 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론: Stage 4 도달, 이제는 건너갈 준비를 할 때&lt;br /&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1646&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vSR6T/dJMcahjoXpt/smh8yCLhIQUFXHeT2NsiYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vSR6T/dJMcahjoXpt/smh8yCLhIQUFXHeT2NsiYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vSR6T/dJMcahjoXpt/smh8yCLhIQUFXHeT2NsiYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvSR6T%2FdJMcahjoXpt%2Fsmh8yCLhIQUFXHeT2NsiYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1646&quot; height=&quot;874&quot; data-origin-width=&quot;1646&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Temporal은 현재 자바스크립트 표준 제정의 최종 단계인 &lt;br /&gt;&lt;b&gt;스테이지 4(Stage 4)&lt;/b&gt;에 도달했다.&lt;br /&gt;&lt;br /&gt;이는 모든 사양 확정이 완료되었음을 의미하며, &lt;br /&gt;내년쯤이면 대다수의 모던 브라우저에서 &lt;br /&gt;폴리필(Polyfill) 없이 네이티브로 사용할 수 있게 될 전망이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기존 Date보다 압도적으로 강력하고 예측 가능한 &lt;b&gt;Temporal로의 전환은 이제 선택이 아닌 필수&lt;/b&gt;이다.&lt;br /&gt;표준 API의 도입은 곧 기술 부채 해결과 코드 품질 향상으로 이어질 것이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로젝트에서 가장 먼저 교체하고 싶은 'Date' 로직은 무엇인가?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>  Dev Log/Article</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/399</guid>
      <comments>https://seokachu.tistory.com/399#entry399comment</comments>
      <pubDate>Sun, 15 Mar 2026 16:04:41 +0900</pubDate>
    </item>
    <item>
      <title>React19v의 ESLint 규칙 강화</title>
      <link>https://seokachu.tistory.com/398</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.23.48.png&quot; data-origin-width=&quot;2414&quot; data-origin-height=&quot;1320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/17wvs/dJMcabpWlm3/WZ2oyafKijzWZluVMleyQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/17wvs/dJMcabpWlm3/WZ2oyafKijzWZluVMleyQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/17wvs/dJMcabpWlm3/WZ2oyafKijzWZluVMleyQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F17wvs%2FdJMcabpWlm3%2FWZ2oyafKijzWZluVMleyQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2414&quot; height=&quot;1320&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.23.48.png&quot; data-origin-width=&quot;2414&quot; data-origin-height=&quot;1320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;React 19와 새로운 렌더링 패러다임&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1773479755793&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useEffect, useState } from &quot;react&quot;;

const Test = () =&amp;gt; {
  const [count, setCount] = useState(0);
  useEffect(() =&amp;gt; {
    setCount((count) =&amp;gt; count + 1);
  }, []);

  return &amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;;
};

export default Test;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;위의 테스트코드는 기존에 사용하던 익숙한 코드이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;리액트 19에서는 useEffect 내부에서 setState를&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;동기적으로 호출하는 것을 지양하는 규칙이 강화되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이는 새로운 규칙이 추가된 것을 넘어&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;리액트가 지향하는 코드 패러다임이&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;근본적으로 변화하고 있음을 의미한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;setState in Effect 규칙의 등장과 연쇄 렌더링의 함정&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ut2cb/dJMcaaYPAQV/zXRq5kmcAdCM5m6LYcfLr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ut2cb/dJMcaaYPAQV/zXRq5kmcAdCM5m6LYcfLr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ut2cb/dJMcaaYPAQV/zXRq5kmcAdCM5m6LYcfLr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUt2cb%2FdJMcaaYPAQV%2FzXRq5kmcAdCM5m6LYcfLr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1814&quot; height=&quot;644&quot; data-origin-width=&quot;1814&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;새로운 ESLint 규칙이 경고하는 핵심은&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;연쇄적인 렌더링(Cascading Rendering)&lt;/b&gt;&lt;/span&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실제 린트 에러 메시지를 살펴보면 다음과 같은 문구가 등장한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&quot;이펙트 내부에서 setState를 동기적으로 호출하면 연쇄적인 렌더링을 요할 수 있다&quot;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.29.28.png&quot; data-origin-width=&quot;2370&quot; data-origin-height=&quot;1286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dujnRx/dJMcahRbXxO/cVhGZLYW1hv0OI2AsGTPuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dujnRx/dJMcahRbXxO/cVhGZLYW1hv0OI2AsGTPuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dujnRx/dJMcahRbXxO/cVhGZLYW1hv0OI2AsGTPuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdujnRx%2FdJMcahRbXxO%2FcVhGZLYW1hv0OI2AsGTPuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2370&quot; height=&quot;1286&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.29.28.png&quot; data-origin-width=&quot;2370&quot; data-origin-height=&quot;1286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;의존성 배열을 비워두면([]) 마운트 시점에&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;단 한 번만 실행되므로 성능에 큰 영향이 없을 것이라 오해한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만&amp;nbsp;리액트&amp;nbsp;19에서는&amp;nbsp;의존성&amp;nbsp;배열의&amp;nbsp;유무와&amp;nbsp;상관없이&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이펙트 내에서의 동기적&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;setState 호출 자체를 지양&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;렌더링 흐름 5단계 vs 2단계&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.29.58.png&quot; data-origin-width=&quot;2402&quot; data-origin-height=&quot;1294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgYOCE/dJMcabDsuaK/EBBzdmGRDbI6wTt73ixlg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgYOCE/dJMcabDsuaK/EBBzdmGRDbI6wTt73ixlg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgYOCE/dJMcabDsuaK/EBBzdmGRDbI6wTt73ixlg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgYOCE%2FdJMcabDsuaK%2FEBBzdmGRDbI6wTt73ixlg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2402&quot; height=&quot;1294&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.29.58.png&quot; data-origin-width=&quot;2402&quot; data-origin-height=&quot;1294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;왜 리액트가 이 패턴을 그토록 싫어하는지&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;렌더링 흐름을 단계별로 쪼개보면 명확해진다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;useEffect 내에서 setState를 사용할 경우,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;브라우저는 다음과 같은 5단계를 거쳐야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;*&amp;nbsp;1단계:&amp;nbsp;&lt;/b&gt;컴포넌트&amp;nbsp;렌더링&lt;br /&gt;&lt;b&gt;*&amp;nbsp;2단계:&lt;/b&gt;&amp;nbsp;DOM&amp;nbsp;업데이트&amp;nbsp;(첫&amp;nbsp;번째&amp;nbsp;페인트)&lt;br /&gt;&lt;b&gt;*&amp;nbsp;3단계:&amp;nbsp;&lt;/b&gt;이펙트(useEffect)&amp;nbsp;실행&lt;br /&gt;&lt;b&gt;*&amp;nbsp;4단계:&lt;/b&gt;&amp;nbsp;setState&amp;nbsp;호출로&amp;nbsp;인한&amp;nbsp;상태&amp;nbsp;변경&lt;br /&gt;&lt;b&gt;*&amp;nbsp;5단계:&amp;nbsp;&lt;/b&gt;컴포넌트&amp;nbsp;재렌더링&amp;nbsp;및&amp;nbsp;다시&amp;nbsp;DOM&amp;nbsp;업데이트&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;3번부터 5번까지의 과정은 사실상 불필요한 비용이다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;만약 처음부터 상태의 초기값을 적절히 설정하거나&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;렌더링 로직 내에서 값을 계산한다면 ?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2단계(렌더링 -&amp;gt; 업데이트)만으로&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;동일한 화면을 보여줄 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;리액트&amp;nbsp;컴파일러와&amp;nbsp;'Rules&amp;nbsp;of&amp;nbsp;React'의&amp;nbsp;강제화&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2354&quot; data-origin-height=&quot;1288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI1NXs/dJMcabpWlFo/mkMesmbNyMyXgMY4IGAlV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI1NXs/dJMcabpWlFo/mkMesmbNyMyXgMY4IGAlV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI1NXs/dJMcabpWlFo/mkMesmbNyMyXgMY4IGAlV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI1NXs%2FdJMcabpWlFo%2FmkMesmbNyMyXgMY4IGAlV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2354&quot; height=&quot;1288&quot; data-origin-width=&quot;2354&quot; data-origin-height=&quot;1288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이&amp;nbsp;규칙이&amp;nbsp;지금&amp;nbsp;이&amp;nbsp;시점에&amp;nbsp;강조되는&amp;nbsp;결정적인&amp;nbsp;이유는&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;리액트 컴파일러(React Compiler)의 등장&lt;/span&gt;&lt;/b&gt; 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;컴파일러는 모든 개발자가 Rules of React(리액트 규칙, 룰리트)를&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;정확히 준수한다고 가정하고 자동 최적화를 수행한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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; 렌더링 과정이 예측 가능할 때, 컴파일러는 불필요한 재렌더링을 제거하고 안전하게 메모이제이션을 적용함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;렌더링의 철학:&lt;/b&gt; 리액트는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;렌더(Render)는 계산이고, 이펙트(Effect)는 외부 시스템과의 동기화를 위해서만 사용하라&lt;/b&gt;&lt;/span&gt;는 철학을 강조함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;리액트의 핵심 철학에 따르면 렌더링은 순수한 &lt;b&gt;'계산'&lt;/b&gt;이어야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 과정이 예측 가능해야만 컴파일러가 불필요한 재렌더링을 안전하게 제거할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;setState in Effect 규칙을 지키는 것은&amp;nbsp;최신 리액트의&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;최적화 엔진을 온전히 가동하기 위한 전제 조건이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 마운트 시점의 분기 처리가 반드시 필요한 상황에서는 어떻게 해야 할까?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;분기처리에 따른 렌더링&lt;/b&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;useSyncExternalStore 활용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.41.37.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4YOCh/dJMcaaxMNZk/fVlpObocKkybT1ctLFRauK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4YOCh/dJMcaaxMNZk/fVlpObocKkybT1ctLFRauK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4YOCh/dJMcaaxMNZk/fVlpObocKkybT1ctLFRauK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4YOCh%2FdJMcaaxMNZk%2FfVlpObocKkybT1ctLFRauK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2192&quot; height=&quot;1314&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.41.37.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;useEffect 대신 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;useSyncExternalStore&lt;/span&gt;훅을 활용하여&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;커스텀 훅(예: useIsMounted)을 만들어 사용하는 것이 권장된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 방식을 사용하면 setState in Effect 에러를 회피하면서도&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;동일한 조건부 렌더링 기능을 구현할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773481876026&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useSyncExternalStore } from &quot;react&quot;;

/**
 * 서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링(CSR)의 일치를 돕는 훅
 * 리액트 19의 'setState in Effect' 지양 원칙을 준수합니다.
 */
const useMounted = () =&amp;gt; {
  return useSyncExternalStore(
    // 1. subscribe: 클라이언트에서 마운트된 후 변경 사항이 없으므로 빈 함수 반환
    () =&amp;gt; () =&amp;gt; {}, 
    // 2. getSnapshot: 브라우저(클라이언트) 환경일 때 반환할 값
    () =&amp;gt; true, 
    // 3. getServerSnapshot: 서버 환경(SSR)일 때 반환할 값
    () =&amp;gt; false 
  );
};

export default useMounted;&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;연쇄 렌더링(Cascading) 방지&lt;/b&gt;: useEffect 안에서 setCount(1)을 하면 0으로 렌더링 -&amp;gt; 이펙트 실행 -&amp;gt; 1로 다시 렌더링이라는 2번의 과정이 생기지만, 위 방식은 리액트가 렌더링 단계에서 즉시 마운트 여부를 판단하게 도와준다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;Hydration 오류 해결&lt;/b&gt;: 서버에서는 false를, 클라이언트에서는 true를 반환하게 하여 서버와 클라이언트의 HTML 구조가 달라 발생하는 에러를 해결한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0&quot;&gt;컴파일러 최적화&lt;/b&gt;: 상태 변경(setState)이 이펙트 안에서 일어나지 않으므로, &lt;b data-index-in-node=&quot;46&quot; data-path-to-node=&quot;9,2,0&quot;&gt;리액트 컴파일러&lt;/b&gt;가 이 컴포넌트는 &quot;순수하다&quot;고 판단하여 훨씬 강력한 최적화(메모이제이션)를 적용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론: 리액트 철학의 이해와 미래를 위한 준비&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.46.53.png&quot; data-origin-width=&quot;2480&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beXAe6/dJMcajg8kbo/2dApuis2UnuHNxVTfocLi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beXAe6/dJMcajg8kbo/2dApuis2UnuHNxVTfocLi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beXAe6/dJMcajg8kbo/2dApuis2UnuHNxVTfocLi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeXAe6%2FdJMcajg8kbo%2F2dApuis2UnuHNxVTfocLi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2480&quot; height=&quot;1364&quot; data-filename=&quot;스크린샷 2026-03-14 오후 6.46.53.png&quot; data-origin-width=&quot;2480&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결국 렌더링은 순수한 계산이고,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이펙트는 오직 외부 시스템과의 동기화에만&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사용한다는 정석적인 철학을 강제함으로&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;더 높은 품질의 애플리케이션을 만들도록 가이드하는 것이다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/Article</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/398</guid>
      <comments>https://seokachu.tistory.com/398#entry398comment</comments>
      <pubDate>Sat, 14 Mar 2026 18:55:32 +0900</pubDate>
    </item>
    <item>
      <title>바이브코딩으로 macOS 페이지 만들기</title>
      <link>https://seokachu.tistory.com/397</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Mar-09-2026 05-51-31.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YLHPk/dJMcahwP9mi/J6vFhdkyhC2Gvd9Wr9Vv51/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YLHPk/dJMcahwP9mi/J6vFhdkyhC2Gvd9Wr9Vv51/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YLHPk/dJMcahwP9mi/J6vFhdkyhC2Gvd9Wr9Vv51/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/YLHPk/dJMcahwP9mi/J6vFhdkyhC2Gvd9Wr9Vv51/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;398&quot; data-filename=&quot;Mar-09-2026 05-51-31.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이런 웹페이지는 어떻게 만들까...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;매일 연구하고 배워야 할게 많아서 미루고 있었는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바이브코딩으로 만들어 봄&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mac-os-portfolio-sandy.vercel.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mac-os-portfolio-sandy.vercel.app/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1773080166509&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Seokachu Portfolio&quot; data-og-description=&quot;This Portfolio is designed for desktop/tabled screens only.&quot; data-og-host=&quot;mac-os-portfolio-sandy.vercel.app&quot; data-og-source-url=&quot;https://mac-os-portfolio-sandy.vercel.app/&quot; data-og-url=&quot;https://mac-os-portfolio-sandy.vercel.app/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://mac-os-portfolio-sandy.vercel.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mac-os-portfolio-sandy.vercel.app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Seokachu Portfolio&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;This Portfolio is designed for desktop/tabled screens only.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mac-os-portfolio-sandy.vercel.app&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;IDE는 안티그래비티 사용했다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;레퍼런스 찾기&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.21.13.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfqTz1/dJMcacbeslX/3e59nHaSU2rgk1KKQPeyk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfqTz1/dJMcacbeslX/3e59nHaSU2rgk1KKQPeyk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfqTz1/dJMcacbeslX/3e59nHaSU2rgk1KKQPeyk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfqTz1%2FdJMcacbeslX%2F3e59nHaSU2rgk1KKQPeyk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2344&quot; height=&quot;1184&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.21.13.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브에 검색해서 나온 리스트들을 추렸다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;유튜브에서 본 그대로 최대한 비슷하게 만들고자 노력했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;디자인과 CSS는 사진으로만 보고 셀프로 만들어야 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.21.37.png&quot; data-origin-width=&quot;2406&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVIulX/dJMcafy2L2H/CnaAKwUAsGn1DajK0gTzj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVIulX/dJMcafy2L2H/CnaAKwUAsGn1DajK0gTzj0/img.png&quot; data-alt=&quot;최종 참고 레퍼런스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVIulX/dJMcafy2L2H/CnaAKwUAsGn1DajK0gTzj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVIulX%2FdJMcafy2L2H%2FCnaAKwUAsGn1DajK0gTzj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2406&quot; height=&quot;634&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.21.37.png&quot; data-origin-width=&quot;2406&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최종 참고 레퍼런스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;영상 보면서 어떻게 개발하는지 흐름 파악부터 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;영상에는 Vite를 사용했으나 Next로 설치했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;나중을 생각해서 쫌쫌따리 업그레이드 하면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Next 풀스택으로 구축해보고 싶었기 때문&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.22.43.png&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLaHuW/dJMcafluFJW/Y0F1tZd5rni9fJGlPYoMHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLaHuW/dJMcafluFJW/Y0F1tZd5rni9fJGlPYoMHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLaHuW/dJMcafluFJW/Y0F1tZd5rni9fJGlPYoMHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLaHuW%2FdJMcafluFJW%2FY0F1tZd5rni9fJGlPYoMHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1340&quot; height=&quot;850&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.22.43.png&quot; data-origin-width=&quot;1340&quot; data-origin-height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;디자인은 Figma에 템플릿 검색해서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아이콘 최대한 비슷한거 찾아서 저장했고,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;배경화면은 내가 쓰고 있는 배경화면 가지고 왔다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;GSAP &lt;/span&gt;애니메이션&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gsap.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://gsap.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dc9hok/dJMcafFKIYk/EzDklq7fp17w9fE1z2nrh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dc9hok/dJMcafFKIYk/EzDklq7fp17w9fE1z2nrh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dc9hok/dJMcafFKIYk/EzDklq7fp17w9fE1z2nrh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdc9hok%2FdJMcafFKIYk%2FEzDklq7fp17w9fE1z2nrh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1362&quot; height=&quot;726&quot; data-origin-width=&quot;1362&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;GSAP 애니메이션은 유튜브에서 추천하는대로 사용했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;GSAP애니메이션은 이번 기회에 처음 사용했는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;문서안에 Demo를 보니 내가 사용해보고 싶은&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;애니메이션 이펙트가 많아서 좋았다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejW7Tq/dJMcajnOJFu/IltUoGOS3WjMR18XAZvHb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejW7Tq/dJMcajnOJFu/IltUoGOS3WjMR18XAZvHb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejW7Tq/dJMcajnOJFu/IltUoGOS3WjMR18XAZvHb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejW7Tq%2FdJMcajnOJFu%2FIltUoGOS3WjMR18XAZvHb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1092&quot; height=&quot;682&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Mar-10-2026 15-41-46.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biFxIe/dJMcagxUGNB/wxCS4VvNrfw4AQOc6iINGk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biFxIe/dJMcagxUGNB/wxCS4VvNrfw4AQOc6iINGk/img.gif&quot; data-alt=&quot;GSAP 사용 적용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biFxIe/dJMcagxUGNB/wxCS4VvNrfw4AQOc6iINGk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/biFxIe/dJMcagxUGNB/wxCS4VvNrfw4AQOc6iINGk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;392&quot; data-filename=&quot;Mar-10-2026 15-41-46.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GSAP 사용 적용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;MacOS Dock Effect를 사용해서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트에 적용해 본 예시이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Mar-10-2026 15-39-41.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ro2Ry/dJMcaiJffIo/Qm6OzrxwFYLW4ZD37v9R7K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ro2Ry/dJMcaiJffIo/Qm6OzrxwFYLW4ZD37v9R7K/img.gif&quot; data-alt=&quot;GSAP 사용 적용2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ro2Ry/dJMcaiJffIo/Qm6OzrxwFYLW4ZD37v9R7K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ro2Ry/dJMcaiJffIo/Qm6OzrxwFYLW4ZD37v9R7K/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;392&quot; data-filename=&quot;Mar-10-2026 15-39-41.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GSAP 사용 적용2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;글꼴의 wght(두께) 축을 마우스호버하면 글자를 두껍게 변경한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;globals.css&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.37.51.png&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cdp61/dJMcaiWMuT5/imL3Hl7vLOBizCSxMlGxH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cdp61/dJMcaiWMuT5/imL3Hl7vLOBizCSxMlGxH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cdp61/dJMcaiWMuT5/imL3Hl7vLOBizCSxMlGxH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCdp61%2FdJMcaiWMuT5%2FimL3Hl7vLOBizCSxMlGxH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1806&quot; height=&quot;1372&quot; data-filename=&quot;스크린샷 2026-03-10 오후 3.37.51.png&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;1372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;`@apply` 속성 선언하고 공통 CSS 디자인 만들었는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;훨씬 편했고, SCSS처럼 비슷하게 사용가능해서 쉬웠다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;잘 알고있다고 있을 것이 아니라 꾸준히 공부해야함 &lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;느낀점&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-09 오전 5.48.45.png&quot; data-origin-width=&quot;2808&quot; data-origin-height=&quot;1760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bofB97/dJMcacCjpX4/jv6saTOnHvxKYyFyeybxjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bofB97/dJMcacCjpX4/jv6saTOnHvxKYyFyeybxjK/img.png&quot; data-alt=&quot;여차저차 완성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bofB97/dJMcacCjpX4/jv6saTOnHvxKYyFyeybxjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbofB97%2FdJMcacCjpX4%2Fjv6saTOnHvxKYyFyeybxjK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2808&quot; height=&quot;1760&quot; data-filename=&quot;스크린샷 2026-03-09 오전 5.48.45.png&quot; data-origin-width=&quot;2808&quot; data-origin-height=&quot;1760&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;여차저차 완성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바이브코딩으로 진행했기 때문에 트러블슈팅이라던가&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;구현하면서 어려웠던 점...? 사실대로 말하면 딱히 없음(...)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI를 돌리더라도 프롬프팅 내용을 몇번 삽질하다보니&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하다보니 프롬프팅 실력이 더 늘은 것 같고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이전보다 빠르게 만들 수 있다는 것이 체감되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내 머릿속에 있는 UI와 매칭하는지?에 대해 신경썼고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;예전 같았으면 일주일 넘게 걸렸던 페이지를&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;MVP까지 2일만에 만들 수 있다는 세상이 온 것 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결론은 오늘도 만들어보고 싶은 웹페이지 완성✨&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/회고</category>
      <category>gsap</category>
      <category>nextjs</category>
      <category>vibe-coding</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/397</guid>
      <comments>https://seokachu.tistory.com/397#entry397comment</comments>
      <pubDate>Tue, 10 Mar 2026 22:03:33 +0900</pubDate>
    </item>
    <item>
      <title>모바일 비율 계산 사진 한장 정리</title>
      <link>https://seokachu.tistory.com/392</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-09 오후 8.03.54.png&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWH8E9/dJMcahCVzXr/F5WURzAVQkypUaHOb5cgUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWH8E9/dJMcahCVzXr/F5WURzAVQkypUaHOb5cgUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWH8E9/dJMcahCVzXr/F5WURzAVQkypUaHOb5cgUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWH8E9%2FdJMcahCVzXr%2FF5WURzAVQkypUaHOb5cgUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;935&quot; height=&quot;479&quot; data-filename=&quot;스크린샷 2025-12-09 오후 8.03.54.png&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디자이너가 주는 피그마 디자인에 따라 비율은 달라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btacGB/dJMcafE7rJb/dsYoHpkp3RlH6MjNKlfJu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btacGB/dJMcafE7rJb/dsYoHpkp3RlH6MjNKlfJu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btacGB/dJMcafE7rJb/dsYoHpkp3RlH6MjNKlfJu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtacGB%2FdJMcafE7rJb%2FdsYoHpkp3RlH6MjNKlfJu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1678&quot; height=&quot;302&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>✏️  공부기록/CSS</category>
      <category>React</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/392</guid>
      <comments>https://seokachu.tistory.com/392#entry392comment</comments>
      <pubDate>Wed, 10 Dec 2025 20:48:08 +0900</pubDate>
    </item>
    <item>
      <title>React-Native 필수 태그 정리</title>
      <link>https://seokachu.tistory.com/391</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;필수 컴포넌트(태그) 한 번에 이해하기 &amp;ndash; 예제 코드로 끝내기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;import { StatusBar } from &quot;expo-status-bar&quot;;
import { Button, FlatList, Text, TextInput, TouchableOpacity, View, StyleSheet } from &quot;react-native&quot;;
import { SafeAreaView } from &quot;react-native-safe-area-context&quot;;

export default function ReactNativeTagsPage() {
  const onPressButton = () =&amp;gt; {
    alert(&quot;버튼을 누르셨군요!&quot;);
  };

  const onChangeText = (text: string) =&amp;gt; {
    console.log(text);
  };

  const onScroll = () =&amp;gt; {
    console.log(&quot;스크롤이 내려갔어요!&quot;);
  };

  return (
    &amp;lt;SafeAreaView style={{ flex: 1, backgroundColor: &quot;red&quot; }} edges={[&quot;top&quot;]}&amp;gt;
      &amp;lt;StatusBar style=&quot;light&quot; /&amp;gt;
      &amp;lt;Button title=&quot;등록하기&quot; onPress={onPressButton} /&amp;gt;
      &amp;lt;TouchableOpacity onPress={onPressButton}&amp;gt;
        &amp;lt;Text&amp;gt;안녕하세요~&amp;lt;/Text&amp;gt;
      &amp;lt;/TouchableOpacity&amp;gt;
      &amp;lt;TextInput
        onChangeText={onChangeText}
        secureTextEntry={true}
        style={styles.input}
      /&amp;gt;
      &amp;lt;View style={styles.boardList}&amp;gt;
        &amp;lt;FlatList
          data={[
            { number: &quot;1&quot;, title: &quot;게시글제목1&quot; },
            { number: &quot;2&quot;, title: &quot;게시글제목2&quot; },
            { number: &quot;3&quot;, title: &quot;게시글제목3&quot; },
            { number: &quot;4&quot;, title: &quot;게시글제목4&quot; },
            { number: &quot;5&quot;, title: &quot;게시글제목5&quot; },
            { number: &quot;6&quot;, title: &quot;게시글제목6&quot; },
            { number: &quot;7&quot;, title: &quot;게시글제목7&quot; },
            { number: &quot;8&quot;, title: &quot;게시글제목8&quot; },
            { number: &quot;9&quot;, title: &quot;게시글제목9&quot; },
            { number: &quot;10&quot;, title: &quot;게시글제목10&quot; },
          ]}
          renderItem={({ item }) =&amp;gt; (
            &amp;lt;Text&amp;gt;글번호:{item.number}, 글제목:{item.title}&amp;lt;/Text&amp;gt;
          )}
          onScroll={onScroll}
        /&amp;gt;
      &amp;lt;/View&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}

const styles = StyleSheet.create({
  input: {
    borderWidth: 2,
    borderColor: &quot;blue&quot;,
  },
  boardList: {
    height: 100,
    backgroundColor: &quot;yellow&quot;,
  },
});&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;이 코드 안에 &lt;span&gt;&lt;b&gt;기본적으로 꼭 알아야 할 컴포넌트들&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;화면 안전 영역: &lt;/span&gt;SafeAreaView&lt;/li&gt;
&lt;li&gt;&lt;span&gt;상태바: &lt;/span&gt;StatusBar&lt;/li&gt;
&lt;li&gt;&lt;span&gt;버튼 계열: &lt;/span&gt;Button&lt;span&gt;, &lt;/span&gt;TouchableOpacity&lt;/li&gt;
&lt;li&gt;텍스트: &lt;span&gt;Text&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;입력창: &lt;/span&gt;TextInput&lt;/li&gt;
&lt;li&gt;레이아웃 박스: &lt;span&gt;View&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;리스트: &lt;/span&gt;FlatList&lt;/li&gt;
&lt;li&gt;&lt;span&gt;스타일: &lt;/span&gt;StyleSheet&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. SafeAreaView &amp;ndash; 노치 영역 피해서 안전하게 보여주기&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;SafeAreaView style={{ flex: 1, backgroundColor: &quot;red&quot; }} edges={[&quot;top&quot;]}&amp;gt;
  {/* 화면 내용들 */}
&amp;lt;/SafeAreaView&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SafeAreaView란?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;아이폰처럼 &lt;/span&gt;&lt;b&gt;상단 노치, 하단 홈 인디케이터&lt;/b&gt;&lt;span&gt;가 있는 기기들에서&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;내용이 잘리지 않도록 &lt;/span&gt;&lt;b&gt;안전한 영역만 사용하도록 도와주는 컴포넌트&lt;/b&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;HTML로 치면 &lt;span&gt;div&lt;/span&gt; 비슷한 레이아웃 박스지만,&lt;/li&gt;
&lt;li&gt;&amp;ldquo;안전 영역(safe area)&amp;rdquo;를 자동으로 신경 써준다는 점이 다릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;style={{ flex: 1, backgroundColor: &quot;red&quot; }}&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;flex: 1&lt;/span&gt; : 남아 있는 화면 전체를 꽉 채우겠다는 뜻&lt;/li&gt;
&lt;li&gt;backgroundColor: &quot;red&quot;&lt;span&gt; : 배경색을 빨간색으로&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;edges={[&quot;top&quot;]}&lt;/b&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;[&quot;top&quot;]&lt;span&gt; &amp;rarr; 상단만&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;필요에 따라 &lt;span&gt;[&quot;top&quot;, &quot;bottom&quot;]&lt;/span&gt; 같은 식으로도 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;b&gt;실무에서 팁&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 전체를 하나 감싸는 최상단 레이아웃은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SafeAreaView&lt;/span&gt;를 쓰는 습관을 들이면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기기마다 이상하게 잘리는 문제를 많이 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. StatusBar &amp;ndash; 상단 상태바(시간, 배터리) 스타일 바꾸기&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;StatusBar style=&quot;light&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;StatusBar란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화면 맨 위에 있는 &lt;span&gt;&lt;b&gt;시간, 배터리, 안테나 아이콘&lt;/b&gt;&lt;/span&gt;이 있는 영역이 상태바(Status Bar)입니다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;StatusBar&lt;/span&gt; 컴포넌트로 이 부분의 &lt;span&gt;&lt;b&gt;텍스트 색상 / 스타일&lt;/b&gt;&lt;/span&gt;을 조정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;style=&quot;light&quot;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태바 아이콘&amp;middot;텍스트 색상을 밝은 스타일로 변경&lt;/li&gt;
&lt;li&gt;보통 &lt;span&gt;&lt;b&gt;배경이 어두울 때&lt;/b&gt;&lt;/span&gt; &lt;span&gt;light&lt;/span&gt;를 사용합니다.&lt;/li&gt;
&lt;li&gt;반대로 배경이 밝으면 &lt;span&gt;dark&lt;/span&gt;를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Button vs TouchableOpacity &amp;ndash; 버튼 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4-1. Button &amp;ndash; 기본 버튼 컴포넌트&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Button title=&quot;등록하기&quot; onPress={onPressButton} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;플랫폼(iOS/Android)에 맞게 기본 스타일이 적용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;title&lt;/span&gt;: 버튼에 표시할 텍스트&lt;/li&gt;
&lt;li&gt;&lt;span&gt;onPress&lt;/span&gt;: 버튼을 눌렀을 때 실행할 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const onPressButton = () =&amp;gt; {
  alert(&quot;버튼을 누르셨군요!&quot;);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 누르면 &lt;span&gt;&lt;b&gt;alert 팝업&lt;/b&gt;&lt;/span&gt;이 뜨도록 연결해놓은 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4-2. TouchableOpacity &amp;ndash; 자유롭게 꾸미는 클릭 영역&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;TouchableOpacity onPress={onPressButton}&amp;gt;
  &amp;lt;Text&amp;gt;안녕하세요~&amp;lt;/Text&amp;gt;
&amp;lt;/TouchableOpacity&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;TouchableOpacity&lt;/span&gt;는 말 그대로 &amp;ldquo;터치 가능한 영역&amp;rdquo;입니다.&lt;/li&gt;
&lt;li&gt;안에 어떤 것을 넣든지 상관없습니다. (&lt;span&gt;Text&lt;/span&gt;, &lt;span&gt;View&lt;/span&gt;, 아이콘 등)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;터치하면 &lt;/span&gt;&lt;b&gt;살짝 투명해지는 효과(opacity)&lt;/b&gt;&lt;span&gt; 가 들어갑니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;디자인을 자유롭게 하고 싶을 때 자주 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;onPress&lt;/span&gt;: 눌렀을 때 실행할 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서는 &lt;/span&gt;Button&lt;span&gt;과 같은 &lt;/span&gt;onPressButton&lt;span&gt;을 재사용해서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;눌렀을 때 똑같이 알림이 뜨도록 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. Text &amp;ndash; 화면에 글자를 보여주는 기본 컴포넌트&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Text&amp;gt;안녕하세요~&amp;lt;/Text&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;&amp;lt;Text&amp;gt;글번호:{item.number}, 글제목:{item.title}&amp;lt;/Text&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML의 &lt;span&gt;&amp;lt;p&amp;gt;&lt;/span&gt;, &lt;span&gt;&amp;lt;span&amp;gt;&lt;/span&gt; 같은 역할&lt;/li&gt;
&lt;li&gt;React Native에서 &lt;span&gt;&lt;b&gt;모든 텍스트는 반드시 &lt;/b&gt;&lt;b&gt;Text&lt;/b&gt;&lt;b&gt; 컴포넌트 안에&lt;/b&gt;&lt;/span&gt; 있어야 합니다.&lt;/li&gt;
&lt;li&gt;(그냥 문자열만 쓰면 에러)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하면 &lt;span&gt;style&lt;/span&gt;을 추가해서 크기, 색상, 두께 등을 조절할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. TextInput &amp;ndash; 사용자 입력 받기&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;TextInput
  onChangeText={onChangeText}
  secureTextEntry={true}
  style={styles.input}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TextInput이 하는 일&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;b&gt;사용자에게 텍스트를 입력받는 모든 곳에서 사용하는 컴포넌트&lt;/b&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;onChangeText&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;const onChangeText = (text: string) =&amp;gt; {
  console.log(text);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;span&gt;state&lt;/span&gt;에 넣거나, 콘솔에 찍거나 할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;지금은 단순히 &lt;span&gt;console.log(text)&lt;/span&gt;로 입력 내용을 개발자 도구에 출력하도록 되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;secureTextEntry={true}&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;span&gt;true&lt;/span&gt;로 설정하면 입력한 텍스트가 ●●●●처럼 보입니다.&lt;/li&gt;
&lt;li&gt;보통 &lt;span&gt;&lt;b&gt;비밀번호 입력창&lt;/b&gt;&lt;/span&gt;에서 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;style={styles.input}&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;span&gt;StyleSheet&lt;/span&gt;에서 정의한 스타일을 적용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;const styles = StyleSheet.create({
  input: {
    borderWidth: 2,
    borderColor: &quot;blue&quot;,
  },
  // ...
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;borderWidth: 2&lt;span&gt; &amp;rarr; 테두리 두께 2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;borderColor: &quot;blue&quot;&lt;span&gt; &amp;rarr; 테두리 색 파란색&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7. View &amp;ndash; 레이아웃 박스(컨테이너)&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;View style={styles.boardList}&amp;gt;
  &amp;lt;FlatList
    // ...
  /&amp;gt;
&amp;lt;/View&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML의 &lt;span&gt;&amp;lt;div&amp;gt;&lt;/span&gt;와 거의 같은 역할입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;레이아웃을 잡거나, 배경색을 주거나, 안에 다른 컴포넌트들을 감쌀 때&lt;/b&gt;&lt;span&gt; 사용합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;styles.boardList&lt;span&gt;는 이렇게 정의되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;boardList: {
  height: 100,
  backgroundColor: &quot;yellow&quot;,
},&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;height: 100&lt;/span&gt; &amp;rarr; 높이를 100px 정도로 고정&lt;/li&gt;
&lt;li&gt;backgroundColor: &quot;yellow&quot;&lt;span&gt; &amp;rarr; 노란색 배경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 &amp;ldquo;노란 박스 안에 리스트(FlatList)가 있는 구조&amp;rdquo;가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;8. FlatList &amp;ndash; 스크롤 가능한 리스트 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;&amp;lt;FlatList
  data={[
    { number: &quot;1&quot;, title: &quot;게시글제목1&quot; },
    { number: &quot;2&quot;, title: &quot;게시글제목2&quot; },
    { number: &quot;3&quot;, title: &quot;게시글제목3&quot; },
    { number: &quot;4&quot;, title: &quot;게시글제목4&quot; },
    { number: &quot;5&quot;, title: &quot;게시글제목5&quot; },
    { number: &quot;6&quot;, title: &quot;게시글제목6&quot; },
    { number: &quot;7&quot;, title: &quot;게시글제목7&quot; },
    { number: &quot;8&quot;, title: &quot;게시글제목8&quot; },
    { number: &quot;9&quot;, title: &quot;게시글제목9&quot; },
    { number: &quot;10&quot;, title: &quot;게시글제목10&quot; },
  ]}
  renderItem={({ item }) =&amp;gt; (
    &amp;lt;Text&amp;gt;글번호:{item.number}, 글제목:{item.title}&amp;lt;/Text&amp;gt;
  )}
  onScroll={onScroll}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;FlatList란? (무한스크롤 제공됨)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;긴 목록을 &lt;span&gt;&lt;b&gt;효율적으로 렌더링&lt;/b&gt;&lt;/span&gt;해주는 리스트 전용 컴포넌트입니다.&lt;/li&gt;
&lt;li&gt;스크롤이 가능한 리스트 화면을 만들 때 가장 많이 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요 props&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;data&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;/li&gt;
&lt;li&gt;여기서는 게시글 번호와 제목을 가진 객체 배열:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;data={[
  { number: &quot;1&quot;, title: &quot;게시글제목1&quot; },
  { number: &quot;2&quot;, title: &quot;게시글제목2&quot; },
  // ...
]}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;renderItem&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;renderItem={({ item }) =&amp;gt; (
  &amp;lt;Text&amp;gt;글번호:{item.number}, 글제목:{item.title}&amp;lt;/Text&amp;gt;
)}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;data&lt;/span&gt; 배열의 각 요소를 &lt;span&gt;&lt;b&gt;어떻게 화면에 보여줄지&lt;/b&gt;&lt;/span&gt;를 정의하는 함수입니다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;item&lt;/span&gt;에는 현재 렌더링 중인 데이터 객체가 들어옵니다.&lt;/li&gt;
&lt;li&gt;여기서는 단순히 &lt;span&gt;Text&lt;/span&gt;로 &amp;ldquo;글번호, 글제목&amp;rdquo;을 한 줄에 보여주게 되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;onScroll&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const onScroll = () =&amp;gt; {
  console.log(&quot;스크롤이 내려갔어요!&quot;);
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;span&gt;&quot;스크롤이 내려갔어요!&quot;&lt;/span&gt; 문자열만 찍습니다.&lt;/li&gt;
&lt;li&gt;추후에는 &lt;span&gt;&lt;b&gt;무한 스크롤, 특정 지점 도달 감지&lt;/b&gt;&lt;/span&gt; 등을 할 때 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;9. StyleSheet &amp;ndash; 스타일 모아 관리하기&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;const styles = StyleSheet.create({
  input: {
    borderWidth: 2,
    borderColor: &quot;blue&quot;,
  },
  boardList: {
    height: 100,
    backgroundColor: &quot;yellow&quot;,
  },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;StyleSheet를 쓰는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트 안에 &lt;span&gt;style={{ ... }}&lt;/span&gt;를 직접 써도 되지만,&lt;/li&gt;
&lt;li&gt;여러 곳에서 재사용하려면 코드가 지저분해집니다.&lt;/li&gt;
&lt;li&gt;StyleSheet.create&lt;span&gt;를 사용하면&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스타일을 한 곳에 모아서 이름으로 관리&lt;/b&gt;&lt;span&gt;할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;TextInput style={styles.input} /&amp;gt;
&amp;lt;View style={styles.boardList} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 쓰면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 스타일을 바꾸고 싶을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;StyleSheet&lt;/span&gt; 부분만 수정하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;10. 정리: 이 예제에서 배운 필수 컴포넌트들&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 한 파일에서 React Native 기본기를 훑을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;SafeAreaView&lt;/b&gt;&lt;/span&gt; : 기기의 안전 영역 안에서 화면을 보여주기&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;StatusBar&lt;/b&gt;&lt;/span&gt; : 상단 상태바 스타일(light/dark) 설정&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Button&lt;/b&gt;&lt;/span&gt; : 기본 버튼, 간단한 클릭 이벤트 처리&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;TouchableOpacity&lt;/b&gt;&lt;/span&gt; : 디자인 자유도가 높은 터치 가능한 영역&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Text&lt;/b&gt;&lt;/span&gt; : 화면에 글자를 보여줄 때 반드시 사용하는 컴포넌트&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;TextInput&lt;/b&gt;&lt;/span&gt; : 사용자 입력 받기 (비밀번호 모드, onChangeText 등)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;View&lt;/b&gt;&lt;/span&gt; : 레이아웃을 나누고 박스를 만드는 기본 컨테이너&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;FlatList&lt;/b&gt;&lt;/span&gt; : 스크롤 가능한 리스트 화면 (data, renderItem, onScroll)&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;StyleSheet&lt;/b&gt;&lt;/span&gt; : 스타일을 깔끔하게 모아서 관리하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-06 오후 4.39.01.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tQ5CT/dJMcadHeH49/K4iIGgcT0KBv1wiKPkIcDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tQ5CT/dJMcadHeH49/K4iIGgcT0KBv1wiKPkIcDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tQ5CT/dJMcadHeH49/K4iIGgcT0KBv1wiKPkIcDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtQ5CT%2FdJMcadHeH49%2FK4iIGgcT0KBv1wiKPkIcDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;1086&quot; data-filename=&quot;스크린샷 2025-12-06 오후 4.39.01.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;1086&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>✏️  공부기록/React &amp;amp; Next.js</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/391</guid>
      <comments>https://seokachu.tistory.com/391#entry391comment</comments>
      <pubDate>Sat, 6 Dec 2025 16:42:04 +0900</pubDate>
    </item>
    <item>
      <title>크롬 Performance 패널로 웹 성능 테스트하는 법</title>
      <link>https://seokachu.tistory.com/390</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;크롬 Performance 패널로 웹 성능 테스트하는 법 (Next.js 기준 완전 정리)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 성능을 제대로 측정하려면 &lt;span&gt;&lt;b&gt;Chrome DevTools의 Performance 탭&lt;/b&gt;&lt;/span&gt;을 올바르게 사용하는 것이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &amp;ldquo;처음 접근하는 사람도 이해할 수 있는&amp;rdquo; 방식으로 다시 정리한 실전 가이드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  1. 성능 측정은 &amp;ldquo;최초 진입 시&amp;rdquo;만 정확하다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤로가기나 페이지 이동 후 보는 성능은 &lt;span&gt;&lt;b&gt;캐시 영향&lt;/b&gt;&lt;/span&gt; 때문에 정확하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 &lt;/span&gt;&lt;b&gt;해당 페이지로 직접 접근 &amp;rarr; Performance 녹화 &amp;rarr; 새로고침(F5)&lt;/b&gt;&lt;span&gt; 방식으로 측정해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  2. 테스트 환경 설정 (반드시 해야 함)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  맥북처럼 고성능 장비에서는 실제 성능 문제가 보이지 않을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래 두 가지를 꼭 설정합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-17 오후 7.17.41.png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCfZDX/dJMcaaDFCwH/pyXdGVDw3AS1kKI7yvsqak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCfZDX/dJMcaaDFCwH/pyXdGVDw3AS1kKI7yvsqak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCfZDX/dJMcaaDFCwH/pyXdGVDw3AS1kKI7yvsqak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCfZDX%2FdJMcaaDFCwH%2FpyXdGVDw3AS1kKI7yvsqak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;1248&quot; data-filename=&quot;스크린샷 2025-11-17 오후 7.17.41.png&quot; data-origin-width=&quot;918&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;CPU Throttle&lt;/b&gt;&lt;/span&gt; &amp;rarr; 4x slow down&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;Network&lt;/b&gt;&lt;/span&gt; &amp;rarr; Fast 4G&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &lt;span&gt;&lt;b&gt;일반적인 모바일 사용자 환경&lt;/b&gt;&lt;/span&gt;과 비슷해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  3. 타임라인에서 색깔별 의미 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Performance 녹화를 시작하면 여러 색의 그래프가 나오는데, 의미는 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;색&lt;/b&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/p&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&gt;&lt;span&gt;  노란색&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;JavaScript 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;  보라색&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;스타일 계산, 레이아웃, 페인트 작업&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;⚪ 회색&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;네트워크 대기/다운로드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;  빨간색&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;CPU 100% &amp;rarr; 작업이 블로킹됨(성능 문제!)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;  &lt;/span&gt;&lt;b&gt;빨간색이 길게 표시되면 성능 병목이 있다는 강력한 신호입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clynwz/dJMcag4XuZJ/4pQz3xrO9SWOrWHVSQ0KB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clynwz/dJMcag4XuZJ/4pQz3xrO9SWOrWHVSQ0KB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clynwz/dJMcag4XuZJ/4pQz3xrO9SWOrWHVSQ0KB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclynwz%2FdJMcag4XuZJ%2F4pQz3xrO9SWOrWHVSQ0KB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2438&quot; height=&quot;1412&quot; data-origin-width=&quot;2438&quot; data-origin-height=&quot;1412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  4. 중요한 지표: LCP(Largest Contentful Paint)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;페이지에서 &lt;/span&gt;&lt;b&gt;가장 의미 있는 요소가 화면에 나타나는 시점&lt;/b&gt;&lt;span&gt;을 LCP라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예: 메인 이미지, 큰 텍스트블록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Performance 화면에서 예를 들어 &lt;span&gt;&lt;b&gt;2.43초에 LCP&lt;/b&gt;&lt;/span&gt;면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 2.43초 만에 주요 화면을 보게 된다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  5. 병목 구간 분석 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;▶ 노란색(JS)이 길다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 자바스크립트가 너무 많음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 번들 사이즈 과다 / 초기 JS 로직 무거움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;▶ 보라색(Layout)이 길다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DOM 구조 복잡&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이미지 크기 문제 / 리플로우 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;▶ 빨간색이 나온다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; CPU가 너무 바빠서 입력이 밀릴 가능성 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 클릭 반응이 늦는 문제와 연결됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 구간이 있으면 앞부분의 &lt;span&gt;&lt;b&gt;초기 렌더링을 최적화해야 한다&lt;/b&gt;&lt;/span&gt;는 의미입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  6. 가장 효과 좋은 개선 포인트: 이미지 최적화&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 LCP를 거의 좌우합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;✔ 개선 체크리스트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WebP 사용&lt;/li&gt;
&lt;li&gt;너무 큰 이미지 불러오지 않기&lt;/li&gt;
&lt;li&gt;Next.js Image 사용 시에도 &lt;span&gt;&lt;b&gt;preload 필요할 수 있음&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;LCP 요소는 반드시 preload하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지만 잘 해도 &lt;/span&gt;&lt;b&gt;LCP가 크게 개선됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;⚡ 7. JS 줄이기 &amp;rarr; 다이나믹 임포트 사용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 화면에서 필요 없는 JS를 모두 지연시키는 게 성능 개선의 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const KakaoLogin = dynamic(() =&amp;gt; import('./KakaoLogin'), { ssr: false });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 버튼 눌렀을 때만 필요한 모듈이라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;굳이 홈 화면 로딩 때 받아올 필요가 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;퍼스트 로드 JS 기준&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;150~200 KB:&lt;/b&gt;&lt;span&gt; 괜찮음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;200~300 KB:&lt;/b&gt;&lt;span&gt; 주황불&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;300 KB 초과:&lt;/b&gt;&lt;/span&gt; 무조건 다이어트해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  8. 클릭이 늦게 반응할 때 분석하는 법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Performance &amp;rarr; Record&lt;/li&gt;
&lt;li&gt;버튼 클릭 순간을 기준으로 타임라인 분석&lt;/li&gt;
&lt;li&gt;해당 시점 JS 실행(노란색)이 길면 &amp;rarr; 입력 지연 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 찾아내서 JS 로직을 분리하거나 다이나믹 임포트로 줄여야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  9. 리포트 작성 팁&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개선 전/후 비교 스냅샷 2~3개만 있으면 충분합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LCP 변화&lt;/li&gt;
&lt;li&gt;빨간색 CPU block 감소&lt;/li&gt;
&lt;li&gt;JS 실행 시간(노란색) 변화&lt;/li&gt;
&lt;li&gt;초기 JS 번들 사이즈 감소(first load JS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 네 가지가 줄어들면 리포트로서 매우 좋은 결과입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;b&gt;✅ 결론&lt;/b&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;성능 테스트는 &amp;ldquo;새로고침 기준으로 CPU/네트워크 쓰로틀을 걸어 LCP + JS 실행시간 + CPU 블로킹&amp;rdquo;을 분석하고, 이미지 최적화와 다이나믹 임포트만 잘 해도 체감 성능이 크게 향상된다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/Article</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/390</guid>
      <comments>https://seokachu.tistory.com/390#entry390comment</comments>
      <pubDate>Fri, 14 Nov 2025 03:44:03 +0900</pubDate>
    </item>
    <item>
      <title>바이브코딩으로 감정일기장 만들어봄 with Cursor</title>
      <link>https://seokachu.tistory.com/387</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;1732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mcIgD/dJMcaaXWw1B/wkAKotVRPmLgEgRiFCM6NK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mcIgD/dJMcaaXWw1B/wkAKotVRPmLgEgRiFCM6NK/img.png&quot; data-alt=&quot;완성본이긴한데, 많이 부족해보임;;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mcIgD/dJMcaaXWw1B/wkAKotVRPmLgEgRiFCM6NK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmcIgD%2FdJMcaaXWw1B%2FwkAKotVRPmLgEgRiFCM6NK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1692&quot; height=&quot;1732&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;1732&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;완성본이긴한데, 많이 부족해보임;;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;요즘 바이브코딩이 화두가 되면서 문득 궁금해졌다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사람들은 왜 이렇게 바이브코딩에 열광할까?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;나 역시 개발할 때나 공부할 때 AI를 자주 활용하지만,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;생각대로 동작하지 않는 경우도 많아서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결국 참고만 하고 직접 구현하는 데 급급하곤 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;솔직히 말하면, 나는 AI를 크게 믿지 않았다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여러 번 기대와 다르게 흘러간 경험들이 있었기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OEF2a/dJMcagjytVI/w1CGpRLNImKEXSO7xc8lHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OEF2a/dJMcagjytVI/w1CGpRLNImKEXSO7xc8lHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OEF2a/dJMcagjytVI/w1CGpRLNImKEXSO7xc8lHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOEF2a%2FdJMcagjytVI%2Fw1CGpRLNImKEXSO7xc8lHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1062&quot; height=&quot;464&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그러다가 내가 가장 좋아하는 프론트엔드 1타 강사님&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바이브코딩 강의를 오픈한다는 소식..!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;게다가 피그마 디자인을 100% 구현해준다고..?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실제로 강의 결제하기전에 세미나 들으러 갔는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실시간으로 돌리는거 보고 와 이게 된다고? 였다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1450&quot; data-origin-height=&quot;1342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VVDTp/dJMcaa4H7ej/gIzMSBTgKgj2C222OYgpt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VVDTp/dJMcaa4H7ej/gIzMSBTgKgj2C222OYgpt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VVDTp/dJMcaa4H7ej/gIzMSBTgKgj2C222OYgpt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVVDTp%2FdJMcaa4H7ej%2FgIzMSBTgKgj2C222OYgpt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1450&quot; height=&quot;1342&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1450&quot; data-origin-height=&quot;1342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckw1Zv/dJMcahvZTgc/H7SGWsikK8rJzq9GAtxsG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckw1Zv/dJMcahvZTgc/H7SGWsikK8rJzq9GAtxsG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckw1Zv/dJMcahvZTgc/H7SGWsikK8rJzq9GAtxsG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckw1Zv%2FdJMcahvZTgc%2FH7SGWsikK8rJzq9GAtxsG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1434&quot; height=&quot;1378&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1378&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;팬심 + 교양 느낌으로 결제해서 보려고 했었는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;후기 이벤트 참여해서 무료로 들을 수 있게 되었다!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;선생님 감사합니다 (ㅠㅠ)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 여기서 멈추지 못하고 챌린지 과정으로 바꿨다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;+ 결국 결제했다는 뜻 ㅎㅅㅎ;;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래야 실시간으로 쌤과 소통할 수 있고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;억지로라도 강의를 완강하려면 이게 낫기 때문~&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래서, 바이브코딩 결제한거 후회하냐고?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MHLlf/dJMcaa4H7eh/QFZnKX3NFTKGQjBHbM6syK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MHLlf/dJMcaa4H7eh/QFZnKX3NFTKGQjBHbM6syK/img.png&quot; data-alt=&quot;오늘 강의 다들음 히힛&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MHLlf/dJMcaa4H7eh/QFZnKX3NFTKGQjBHbM6syK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMHLlf%2FdJMcaa4H7eh%2FQFZnKX3NFTKGQjBHbM6syK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1616&quot; height=&quot;470&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1616&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오늘 강의 다들음 히힛&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;강의한줄평 : 아...돈만 있었으면 더 날아다녔다. 아쉽다.&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아쉽다 = 미쳤다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;나도 AI를 꽤 많이 써오면서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 실력은 늘었다고 생각했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;왜냐하면 이미 나는 병아리 시절부터&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI에게 물어보며 코딩했고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;대가리 박으면서 하다보면 자동으로 깨닫게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트 실력도 같이 자라게 되는것을 ㅎㅅㅎ...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이건 AI를 조련하는것에 가깝다...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;강의를 들으면 들을수록 느낀것은&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이렇게까지 알려줘야한다고?&lt;/b&gt; 하는 부분이었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결국 AI도 유치원생에게 한글 가르치듯&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;정확하고 자세하게 알려주면&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;금쪽이처럼 갑자기 핑이 튀는 가능성에서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내 의도대로 나올 확률이 확 올라간다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사실은 이건 내가 이미 AI쓰면서 느끼던 부분이기도 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;머릿속 생각을 타자로 치기 귀찮아서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;대충 프롬프트 던지면 AI가 느낌대로 만들어줄 때가 많았으니까... &lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1780&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLPpvu/dJMcagqj3uk/ywhzav69UAcar20AGAC4FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLPpvu/dJMcagqj3uk/ywhzav69UAcar20AGAC4FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLPpvu/dJMcagqj3uk/ywhzav69UAcar20AGAC4FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLPpvu%2FdJMcagqj3uk%2Fywhzav69UAcar20AGAC4FK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1780&quot; height=&quot;1248&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1780&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이번 강의를 들으면서 깨달은 핵심은 이거다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI에게 너무 자유도를 주지 않고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내가 관리자처럼 규칙을 부여하고&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;엄격하게 체크해주기만 하면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;바이브코딩은 진짜 미친 효율을 낸다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k22KP/dJMcabJjKnI/74kblQDcVFjEOr86DhnsCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k22KP/dJMcabJjKnI/74kblQDcVFjEOr86DhnsCk/img.png&quot; data-alt=&quot;진짜 &amp;quot;구현&amp;quot; 두글자만 쓰고 던짐 ㅋㅋ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k22KP/dJMcabJjKnI/74kblQDcVFjEOr86DhnsCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk22KP%2FdJMcabJjKnI%2F74kblQDcVFjEOr86DhnsCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1312&quot; height=&quot;376&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;진짜 &quot;구현&quot; 두글자만 쓰고 던짐 ㅋㅋ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 아오 프롬프트 짜기 귀찮아 였는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;특히 병렬 처리할 때? 이때가 그냥 사기 그자체...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;병렬처리 해주는 것 부터 입벌리면서 봤다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI에게 일시키고 밥먹으러 다녀오면 됨...ㄷ&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;들으면 들을수록 내가 그동안&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;혼자 씨름하고 공부하면서 만들었던&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트들을 바이브코딩으로 하면?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;한 달? 아니ㅋㅋ 일주일이면 뚝딱 만들어지겠다..싶었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;퍼블리셔 시절 공통 CSS 만들고,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트마다 파운데이션 직접 구축하던 시절 생각하면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;지금은 AI로 30분이면 뚝딱 나오니까...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이래서 AI가 개발자를 대체한다는 위기감이 나오는구나? 싶었다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사실 실감 안났는데 직접 돌려보니&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아 이래서 다들 그렇게 생각하겠구나? 싶었다&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 내 생각은 조금 달랐다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이번에 느낀 점은 나 진짜 대체되겠다...가 아니라&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;와 이거 더 연구해서 제대로 써먹어야겠다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;너무 편한데? 개꿀인데?  &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라는 마음이 더 생김 ..ㅋㅋㅋ&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;1570&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmZWv/dJMcahCLxdh/qaiUwGDQfuV0chPiMxfpkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmZWv/dJMcahCLxdh/qaiUwGDQfuV0chPiMxfpkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmZWv/dJMcahCLxdh/qaiUwGDQfuV0chPiMxfpkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxmZWv%2FdJMcahCLxdh%2FqaiUwGDQfuV0chPiMxfpkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2594&quot; height=&quot;1570&quot; data-origin-width=&quot;2594&quot; data-origin-height=&quot;1570&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2452&quot; data-origin-height=&quot;1604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF5FTP/dJMcabP5gKZ/k0dn1ULVavHH0ydbVJG3e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF5FTP/dJMcabP5gKZ/k0dn1ULVavHH0ydbVJG3e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF5FTP/dJMcabP5gKZ/k0dn1ULVavHH0ydbVJG3e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF5FTP%2FdJMcabP5gKZ%2Fk0dn1ULVavHH0ydbVJG3e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2452&quot; height=&quot;1604&quot; data-origin-width=&quot;2452&quot; data-origin-height=&quot;1604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;로그인 &amp;amp; 회원가입은 디자인 없이&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI에게 프롬프트만 던지고 디자인 완성한 것&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;생각보다 꽤괜~ (꽤 괜찮음)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 결론ㅋㅋ&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과물이 100% 똑같이 나오진 않았다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;잠시 핑계를 대자면...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Cursor AI 20불짜리를 결제해서 썼는데&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공통 컴포넌트 만들다가 &lt;/span&gt;&lt;b&gt;벌써 토큰 소모 끝났다고 뜸.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;추가 결제하려 보니 &lt;span&gt;&lt;b&gt;10만원 더 결제하라고 함 (ㅠㅠ)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;가격보고 바로 창 닫아버림... 젠장!!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2L6lb/dJMcahbHdcs/wuESpR4CB6Ar1Q9A2sp0o1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2L6lb/dJMcahbHdcs/wuESpR4CB6Ar1Q9A2sp0o1/img.png&quot; data-alt=&quot;더 정확하게 알아들을 수 있도록 금쪽이에게 꼼꼼하게 설명해주기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2L6lb/dJMcahbHdcs/wuESpR4CB6Ar1Q9A2sp0o1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2L6lb%2FdJMcahbHdcs%2FwuESpR4CB6Ar1Q9A2sp0o1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1754&quot; height=&quot;472&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;더 정확하게 알아들을 수 있도록 금쪽이에게 꼼꼼하게 설명해주기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 어쩔 수 없이 오토 모드로 돌렸다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아무래도 더 성능 좋은 모델을 썼다면&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;완전 똑같이 나왔을 것 같은데,,아쉬웠다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;오토모드로 변경한 뒤로&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내가 아무리 콕 집어서 설명해도&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;AI가 말을 안 듣는 느낌이었음 ㅠㅠ&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래도 한 달만 결제해서 빠르게 끝내려던 계획은 성공했고,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;지금은 Cursor를 쓰지 않더라도&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;앞으로 구현하거나 공부할 때&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;프롬프트를 더 디테일하게 작성해야겠다는 생각이&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;매우 매우 강하게 자리 잡았다....&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1838&quot; data-origin-height=&quot;1554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nByBA/dJMcag4VBAK/6igpLwn3r4ehcgrOaHWto1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nByBA/dJMcag4VBAK/6igpLwn3r4ehcgrOaHWto1/img.png&quot; data-alt=&quot;오늘이 마지막날.... 결론은 20불;; 턱없이 부족함;;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nByBA/dJMcag4VBAK/6igpLwn3r4ehcgrOaHWto1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnByBA%2FdJMcag4VBAK%2F6igpLwn3r4ehcgrOaHWto1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1838&quot; height=&quot;1554&quot; data-origin-width=&quot;1838&quot; data-origin-height=&quot;1554&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오늘이 마지막날.... 결론은 20불;; 턱없이 부족함;;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;한 달 20불로 정말 좋은 경험을 했고, 배운 것도 많다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 Cursor 사용 기간이 내일이면 끝나는데 ㅠㅅㅠ&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;나는 재결제하지 않을 예정이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;사실은 쓰다보니 느끼게 됨...ㅎㅅㅎ;;; 너무 비용적으로 부담임...&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;지금 나에게는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;조그만 프로젝트 하나 만들기에도 턱없이 부족한 비용이었음...&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더 마음 편하게 쓰려면? 그냥 커서 max 버전 결제해야함 (대략 28만원)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;돈 더 많이 벌어야함^ㅅ^ 히힛&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qTSMS/dJMcaaKpk28/cTJu5bYUKKZoJoWj0Tps70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qTSMS/dJMcaaKpk28/cTJu5bYUKKZoJoWj0Tps70/img.png&quot; data-alt=&quot;너무 비싸요 흑흑&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qTSMS/dJMcaaKpk28/cTJu5bYUKKZoJoWj0Tps70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqTSMS%2FdJMcaaKpk28%2FcTJu5bYUKKZoJoWj0Tps70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1980&quot; height=&quot;770&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;너무 비싸요 흑흑&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다시 결제하게 된다면? 아마 바로 &lt;span&gt;&lt;b&gt;Pro+모드&lt;/b&gt;&lt;/span&gt;로 갈 것 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;솔직히 20불짜리는 거의 체험판 느낌이었다 ^_ㅠ&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;20불 플랜도 내가 직접 짜면서 중간중간 도움받기에는 충분하지만,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;진짜 제대로 활용하려면 차라리 돈 더 주고 &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빡세게 부려먹는 게 맞다&lt;/b&gt;&lt;span&gt;는 생각이 들었다ㅋㅋ&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Nov-13-2025 20-39-08.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vhTVk/dJMb99Lu59t/LKmasycTNKvia3wHPEysjk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vhTVk/dJMb99Lu59t/LKmasycTNKvia3wHPEysjk/img.gif&quot; data-alt=&quot;다 채워서 뿌듯...프롬프트는 노션에 정리해뒀으니 앞으로 잘 써먹어야지  &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vhTVk/dJMb99Lu59t/LKmasycTNKvia3wHPEysjk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/vhTVk/dJMb99Lu59t/LKmasycTNKvia3wHPEysjk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;530&quot; data-filename=&quot;Nov-13-2025 20-39-08.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;다 채워서 뿌듯...프롬프트는 노션에 정리해뒀으니 앞으로 잘 써먹어야지  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 지금은 VSCode + CLI 조합이&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내 기준에서 훨씬 현명한 20불 절약 방식&lt;span&gt;이라고 느껴진다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;CLI 조합으로 최대한 직접 분석하고 뜯어보면서&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기본기를 다지는 쪽이 지금 단계에서는 더 중요하기도 하고...!!?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;아직은 배우는 시기라서, &lt;span&gt;AI에게 전부 맡기는 것보다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 구조를 직접 파악하고 이해하는 경험&lt;/b&gt;&lt;span&gt;이&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;훨씬 큰 자산이라고 생각드는 결론이었다...!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;결론 : 다음 프로젝트 딱대  더 기대되는구먼...?!&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/회고</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/387</guid>
      <comments>https://seokachu.tistory.com/387#entry387comment</comments>
      <pubDate>Thu, 13 Nov 2025 20:42:18 +0900</pubDate>
    </item>
    <item>
      <title>[팀프로젝트-Vidding] 세션 상태 관리 개선</title>
      <link>https://seokachu.tistory.com/386</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;855&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot; data-alt=&quot;이거 왜이럼...?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7sWlC%2FdJMcaiaByTP%2F5qHZKORntKeHju6fYJkDM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;855&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;855&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이거 왜이럼...?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;MVP에서 유저 피드백을 받던 날.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;무언가 이상했다. 피드백 내용이 전부 이렇게 시작했다.&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #2c2828; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&amp;ldquo;마이페이지를 들어가면 내 정보가 사라져요&amp;rdquo;&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;라는 내용이었다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로그인은 되어 있는데, 화면에서는 유저정보가 없는 것처럼 보이는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이상한 상태였다.&amp;nbsp;&lt;/span&gt;처음엔 단순한 버그라고 생각했다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 점점 드는 생각은 아..이거...어디서 익숙한 트러블슈팅인데...&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;세션과 상태관리 구조 자체를 다시 이해해야 하는 문제구나&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;라는 것을 깨닫게 되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 글은 그 여정을 정리한 기록이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 어떤 문제가 있었는지?&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;브라우저 탭을 이동했다가 돌아오면&amp;hellip; 내 정보가 사라진다 ...&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;SCR-20250804-cauw.png&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5lKb2/dJMcain8LDA/zFgI49IIcgeU1gcoqS2YS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5lKb2/dJMcain8LDA/zFgI49IIcgeU1gcoqS2YS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5lKb2/dJMcain8LDA/zFgI49IIcgeU1gcoqS2YS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5lKb2%2FdJMcain8LDA%2FzFgI49IIcgeU1gcoqS2YS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;786&quot; data-filename=&quot;SCR-20250804-cauw.png&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;원래는 이렇게 보여야 하는데&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;855&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7sWlC/dJMcaiaByTP/5qHZKORntKeHju6fYJkDM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7sWlC%2FdJMcaiaByTP%2F5qHZKORntKeHju6fYJkDM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;855&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;855&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 순간부터 이렇게 보임...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Aug-05-2025 23-07-25.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nNbE2/dJMcagqj9F4/PfcwxLc2GFhU8ytPOpl7Q1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nNbE2/dJMcagqj9F4/PfcwxLc2GFhU8ytPOpl7Q1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nNbE2/dJMcagqj9F4/PfcwxLc2GFhU8ytPOpl7Q1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/nNbE2/dJMcagqj9F4/PfcwxLc2GFhU8ytPOpl7Q1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;598&quot; data-filename=&quot;Aug-05-2025 23-07-25.gif&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 탭을 왔다갔다 하면 원래는&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;로그인 한 상태니까 유저 정보가 그대로 보여야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 잠깐 다른 탭 (ex: 위에 있는 사진처럼 네이버탭)에서&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;작업하고 있다가 다시 돌아오면 유저 정보가 사라지고 없었다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;게다가 이 문제는 간헐적으로 발생했던 터라&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;내가 미처 파악을 못했던 상황이었다.;;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;다른 탭에서 오래 머무르다 오면&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;내 정보가 사라지는 문제가 더 자주 생겼다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 인지는 했지만.... 힘들었다...&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;왜냐하면 항상 재현되지 않았기 때문 ㅠ&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;아주 가끔&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;터짐 ㅠㅅㅠ&lt;/li&gt;
&lt;li&gt;브라우저, 네트워크 상태, 탭 이동 타이밍에 따라 다르게 나타남&lt;/li&gt;
&lt;li&gt;QA에서도 재현이 안됨...나는 또 잘됨 ㅠ&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 버그를 고치는 것 보다는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;대체 이게 언제, 어떤 조건에서 터지는지 먼저 이해하는 과정&lt;/b&gt;이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;훨씬 힘들었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 그래서 원인이 뭐였는데?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들에게도 SOS를 보내고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 액션을 했을 때 문제가 생기는지 하나씩 로그를 찍어가며 확인했다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;결론은 한문장으로 요약할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Supabase Auth의 상태 변화 속도와, 내가 들고 있는 클라이언트 상태가 맞지 않는다&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;그러니까 그냥... 결론은 타이밍 이슈였다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인을 하면 내가 커스텀한 role(buyer/seller)이 DB에서 로드되기 전에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Supabase의 기본 role인 &lt;span&gt;&quot;authenticated&quot;&lt;/span&gt;가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더 늦게 도착하면서 기존 role을 덮어씌우는 상황&lt;/b&gt;&lt;span&gt;이 생긴 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 만료 후 다시 상태가 로드될 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 타이밍 차이가 커지면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저 정보가 없어진 것처럼 보이는 문제가 발생했다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;845&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwT14/dJMcaaKppAA/NkVgCRedskkk3YbR5IH9m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwT14/dJMcaaKppAA/NkVgCRedskkk3YbR5IH9m0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwT14/dJMcaaKppAA/NkVgCRedskkk3YbR5IH9m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwT14%2FdJMcaaKppAA%2FNkVgCRedskkk3YbR5IH9m0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1030&quot; height=&quot;845&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;845&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 그래서 어떻게 해결함?&lt;/b&gt;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 페이지에 다시 돌아왔을 때 세션을 다시 확인하도록 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 탭을 다시 클릭했을 때 Supabase의 세션을 즉시 재확인했다.&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;visibilitychange&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;/&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;focus&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이벤트를 감지해서 &lt;/span&gt;&lt;b&gt;사용자가 페이지로 돌아오는 순간&lt;/b&gt;&lt;span&gt;,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Supabase에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;getSession()&lt;/span&gt;을 다시 호출하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 결과와 내가 들고 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;currentUser&lt;/span&gt;가 다르면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;클라이언트 상태를 복구&lt;/b&gt;&lt;/span&gt;하는 것으로 접근했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 통해, 사실은 로그인 한 상태인데, 화면만 로그아웃처럼 보이는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애매한 상황을 많이 줄일 수 있었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(+ 너무 자주 호출되지 않도록 3초 쿨다운도 걸어줌)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하 엄청 크리티컬 했던 이슈사항이어서 MVP때 시간이 없어서 급하게 처리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 사용자 정보는 보여야했기에 현재로썬 이 방법이 최선이었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) 소셜로그인 타이밍 이슈? 조금 기다렸다가 다시 가져오기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;role&lt;span&gt;이 없거나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;'authenticated'&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 불완전한 상태면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 화면에 렌더링하지 않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;500ms 정도 기다렸다가,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;users&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;테이블에서 다시 프로필을 조회하게 했다.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 한 번 더 확인하는 코드를 추가했고,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간헐적으로 생기던 이상한 상태들이 많이 없어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) UI 쪽에서도 불완전한 상태를 보이지 않도록 하기&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예전에는 이렇게만 체크했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763054067289&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (!user) return &amp;lt;Skeleton /&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재는 로그인 여부만 보지 않고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 유저가 화면에 필요한 최소한의 정보(role)가 있는지 체크했다.&lt;/p&gt;
&lt;pre id=&quot;code_1763054080681&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// user 객체만 있다고 끝이 아니다
if (!user || !user.role || !['buyer', 'seller'].includes(user.role)) {
  return &amp;lt;ComponentSkeleton /&amp;gt;;
}&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;&lt;span&gt;user&lt;/span&gt;는 있는데&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;role&lt;/span&gt;이 없거나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;role&lt;span&gt;이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;'authenticated'&lt;span&gt;처럼 애매하면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skeleton으로 자연스럽게 감춰버렸다.&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;사용자 입장에서는 UI에 그대로 노출되지 않고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 로딩 중인 화면처럼 자연스럽게 보이게 됐다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 바뀐점들&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;세션 유지 안정성&lt;/b&gt;&lt;/span&gt;: 60% &amp;rarr; 95%&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로그인 후 정상 상태 도달 비율&lt;/b&gt;&lt;span&gt;: 75% &amp;rarr; 98%&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;새로고침하니까 되네요 현상&lt;/b&gt;&lt;span&gt;: 30% &amp;rarr; 5%&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;체감상으로는, 어쩌다 한 번씩 이상하게 꼬이는 현상이 거의 사라졌고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제가 생기더라도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;사용자 입장에서는 그냥 잠깐 로딩처럼 보이는 수준&lt;/b&gt;&lt;span&gt;으로 완화되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다도, 탭 잠깐 옮겼다가 돌아왔더니 로그아웃된 것처럼 보이는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 특유의 답답함을 없앴다는 점이 크다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 이 과정에서 내가 배운 것들&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 로그인 여부보다 중요한 건 &amp;ldquo;상태의 완전성&amp;rdquo;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1763054376164&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const isLoggedIn = !!user;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그냥 단순하게 로그인 했냐 안했냐? 로만 판단했는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;화면을 그릴 수 있을 만큼 유저 정보가 완전히 준비됐는가?&lt;/b&gt;를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깨닫게 되었다...&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) &lt;/b&gt;&lt;b&gt;비동기 로직은 항상 먼저/나중이 바뀔 수 있음&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Race Condition, 토큰 만료, 포커스 변경, 네트워크 지연 같은 건&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;강의에서만 보던 문제였는데&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나도 실제 서비스에서 이 문제들을 맞닥뜨릴 수 있구나....&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 이 내용을 무시하면 사용자에게 바로 불편으로 돌아오는구나...&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;를 꽤 현실적으로 느끼게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 요즘은 코드를 짤 때&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 이벤트가 먼저 올 수도 있고, 저게 먼저 올 수도 있다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가능성을 두고 코드를 작성해야지!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;라는 것을 항상 의식하려고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) 애매한 상태는 결국 사용자에게는 전부 에러처럼 보인다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 일을 겪으면서 개발자 입장에서는 잠깐 불안정한데? 라고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대수롭지 않게 생각했지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 입장에서는 왜 내정보 없음? 에러났네 라고 받아들인다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 사용자 입장에서도 고려하여 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Skeleton 같은 안전한 화면으로 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;감싸는 것의 중요성을 확실히 깨달았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 앞으로 더 개선하고 싶은 것들&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;오프라인 대응&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;여러 탭/기기 간 실시간 동기화&lt;/b&gt;&lt;br /&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불필요한 로딩 최소화&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미 유저 정보가 있다면,탭&lt;span&gt;&amp;nbsp;&lt;/span&gt;복귀 시 스켈레톤을 재실행하지 않도록 개선하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 Supabase가 무료라서 매우 느리구나...ㅋㅋ 정도로만 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 파고들수록 문제의 핵심은 성능이 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 세션과 상태를 너무 단순하게 바라보고 있었다는 점&lt;span&gt;이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 경험을 통해 이런 문제를 해결해 나가는 과정이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결국 서비스 전체의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;안정성과 신뢰도를 얼마나 높이는지 체감했다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 유저 피드백을 받는 동안 &amp;ldquo;로그아웃이 안 돼요&amp;rdquo;라는 이야기만 계속 들어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 마음고생을 많이 했다 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로도 비슷한 문제가 생기겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 경험을 통해 &lt;/span&gt;타이밍 이슈를 전제로 구조를 설계하는 법&lt;span&gt;을 배웠고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 훨씬 안정적으로 대응할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/트러블슈팅</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/386</guid>
      <comments>https://seokachu.tistory.com/386#entry386comment</comments>
      <pubDate>Mon, 25 Aug 2025 12:39:24 +0900</pubDate>
    </item>
    <item>
      <title>STOMP.js 라이브러리</title>
      <link>https://seokachu.tistory.com/383</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 라이브러리는 웹 브라우저와 node.js 애플리케이션을 위한 WebSocket 클라이언트를 통한 STOMP를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1751212883532&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - stomp-js/stompjs: Javascript and Typescript Stomp client for Web browsers and node.js apps&quot; data-og-description=&quot;Javascript and Typescript Stomp client for Web browsers and node.js apps - stomp-js/stompjs&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/stomp-js/stompjs?tab=readme-ov-file&quot; data-og-url=&quot;https://github.com/stomp-js/stompjs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e8SaI/hyZf8Kf2j2/EgW94aPnDCsnwacg8qRYsK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/n64Qy/hyZgaVBiYm/OyObodNEpOSakB7di6u6D0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/stomp-js/stompjs?tab=readme-ov-file&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/stomp-js/stompjs?tab=readme-ov-file&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e8SaI/hyZf8Kf2j2/EgW94aPnDCsnwacg8qRYsK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/n64Qy/hyZgaVBiYm/OyObodNEpOSakB7di6u6D0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - stomp-js/stompjs: Javascript and Typescript Stomp client for Web browsers and node.js apps&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Javascript and Typescript Stomp client for Web browsers and node.js apps - stomp-js/stompjs&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;가이드,&amp;nbsp;FAQ&amp;nbsp;및&amp;nbsp;API&amp;nbsp;문서&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1751212925465&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;StompJs Family&quot; data-og-description=&quot;Javascript/Typescript client for STOMP protocol. Specialized versions for RxJS/Angular.&quot; data-og-host=&quot;stomp-js.github.io&quot; data-og-source-url=&quot;https://stomp-js.github.io/&quot; data-og-url=&quot;https://stomp-js.github.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://stomp-js.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stomp-js.github.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;StompJs Family&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Javascript/Typescript client for STOMP protocol. Specialized versions for RxJS/Angular.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stomp-js.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1751213539185&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Using StompJs&quot; data-og-description=&quot;You can find samples at https://github.com/stomp-js/samples/.&quot; data-og-host=&quot;stomp-js.github.io&quot; data-og-source-url=&quot;https://stomp-js.github.io/guide/stompjs/using-stompjs-v5.html&quot; data-og-url=&quot;https://stomp-js.github.io/guide/stompjs/using-stompjs-v5.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://stomp-js.github.io/guide/stompjs/using-stompjs-v5.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stomp-js.github.io/guide/stompjs/using-stompjs-v5.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Using StompJs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;You can find samples at https://github.com/stomp-js/samples/.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stomp-js.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Docs&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1751212933224&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;stompjs@7.1.0, rx-stomp@2.0.1&quot; data-og-description=&quot;Classes Client Info Source File Description STOMP Client Class. Part of @stomp/stompjs. Index Properties Public appendMissingNULLonIncoming Public beforeConnect Public brokerURL Public connectHeaders Public connectionTimeout Public debug Public discardWebs&quot; data-og-host=&quot;stomp-js.github.io&quot; data-og-source-url=&quot;https://stomp-js.github.io/api-docs/latest/classes/Client.html&quot; data-og-url=&quot;https://stomp-js.github.io/api-docs/latest/classes/Client.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://stomp-js.github.io/api-docs/latest/classes/Client.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stomp-js.github.io/api-docs/latest/classes/Client.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;stompjs@7.1.0, rx-stomp@2.0.1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Classes Client Info Source File Description STOMP Client Class. Part of @stomp/stompjs. Index Properties Public appendMissingNULLonIncoming Public beforeConnect Public brokerURL Public connectHeaders Public connectionTimeout Public debug Public discardWebs&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stomp-js.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;라이브러리 &lt;/b&gt;&lt;b&gt;설명 &lt;/b&gt;&lt;b&gt;관계&lt;/b&gt;&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&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/stomp-js/stompjs&quot;&gt;stompjs&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;STOMP 클라이언트의 &lt;span&gt;&lt;b&gt;기본 구현체&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;가장 핵심이 되는 저수준 라이브러리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/stomp-js/rx-stomp&quot;&gt;rx-stomp&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;stompjs&lt;/span&gt;&lt;span&gt;를 &lt;/span&gt;&lt;b&gt;RxJS 스타일로 래핑(wrap)&lt;/b&gt;&lt;span&gt; 한 상위 라이브러리&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;내부적으로 &lt;/span&gt;@stomp/stompjs&lt;span&gt;에 &lt;/span&gt;&lt;span&gt;&lt;b&gt;의존&lt;/b&gt;&lt;/span&gt;&lt;span&gt;함&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/stomp-js/samples&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/stomp-js/samples&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1751217630557&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - stomp-js/samples: Samples for stompjs and rx-stomp&quot; data-og-description=&quot;Samples for stompjs and rx-stomp. Contribute to stomp-js/samples development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/stomp-js/samples&quot; data-og-url=&quot;https://github.com/stomp-js/samples&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dHDGBQ/hyZf0yGuxS/y2AYNoDYjNdkWPCdgPjvg0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b5xyCx/hyZbzbJSlN/yIcA4814BnWTJS43qGLJWK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/stomp-js/samples&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/stomp-js/samples&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dHDGBQ/hyZf0yGuxS/y2AYNoDYjNdkWPCdgPjvg0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/b5xyCx/hyZbzbJSlN/yIcA4814BnWTJS43qGLJWK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - stomp-js/samples: Samples for stompjs and rx-stomp&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Samples for stompjs and rx-stomp. Contribute to stomp-js/samples development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;STOMP 클라이언트: 주요 기능 및 설정 가이드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STOMP 클라이언트 클래스는 STOMP 브로커와의 통신을 효율적으로 관리하기 위한 광범위한 기능과 설정 옵션을 제공합니다. 이 가이드에서는 STOMP 클라이언트의 핵심 속성(설정), 주요 메서드(기능), 접근자 및 유용한 콜백 함수들을 자세히 설명합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 주요 속성 (설정)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STOMP 클라이언트는 브로커와의 연결, 재연결, 메시지 처리 방식 등을 &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;연결 관련&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;brokerURL: STOMP 브로커에 연결할 URL을 설정합니다. 일반적으로 ws:// 또는 wss:// 프로토콜을 사용합니다. webSocketFactory와 함께 사용될 수 있으나, 둘 다 설정된 경우 webSocketFactory가 우선적으로 사용됩니다.&lt;/li&gt;
&lt;li&gt;webSocketFactory: WebSocket 또는 SockJS와 같은 유사 객체를 반환하는 함수를 정의할 수 있습니다. 이는 웹소켓을 기본적으로 지원하지 않는 환경에서 유용합니다.&lt;/li&gt;
&lt;li&gt;connectHeaders: STOMP 브로커에 연결할 때 사용되는 헤더입니다. login, passcode, host와 같은 중요한 키를 포함할 수 있습니다.&lt;/li&gt;
&lt;li&gt;disconnectHeaders: 연결 해제 시 사용되는 헤더입니다.&lt;/li&gt;
&lt;li&gt;stompVersions: STOMP 핸드셰이크 중에 시도할 STOMP 버전을 지정합니다. 기본적으로 1.2, 1.1, 1.0 버전이 시도됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재연결 및 타임아웃&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;connectionTimeout: 지정된 시간(밀리초) 내에 STOMP 연결이 설정되지 않으면 재연결을 시도합니다. 기본값은 0으로, 자동 재연결을 비활성화합니다.&lt;/li&gt;
&lt;li&gt;reconnectDelay: 자동 재연결 시 지연 시간(밀리초)입니다. 기본값은 5000밀리초(5초)이며, 0으로 설정하면 비활성화됩니다.&lt;/li&gt;
&lt;li&gt;maxReconnectDelay: 재연결 간 최대 대기 시간(밀리초)입니다. 기본값은 15분(15 * 60 * 1000밀리초)이며, reconnectTimeMode가 LINEAR가 아닐 때(예: EXPONENTIAL) 관련이 있습니다. 0으로 설정하면 대기 시간에 제한이 없습니다.&lt;/li&gt;
&lt;li&gt;reconnectTimeMode: 재연결 대기 시간 모드를 선형(기본값) 또는 지수 방식으로 설정합니다. 지수 방식일 경우 reconnectDelay가 2배씩 증가하며, maxReconnectDelay에 도달하면 더 이상 증가하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하트비트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;heartbeatIncoming: 들어오는 하트비트 간격(밀리초)입니다. 0으로 설정하면 비활성화됩니다.&lt;/li&gt;
&lt;li&gt;heartbeatOutgoing: 나가는 하트비트 간격(밀리초)입니다. 0으로 설정하면 비활성화됩니다.&lt;/li&gt;
&lt;li&gt;heartbeatStrategy: 나가는 하트비트 전략을 설정합니다. 웹 워커(Worker) 또는 인터벌(Interval) 전략을 사용할 수 있으며, 웹 워커를 사용할 수 없는 환경에서는 항상 인터벌을 사용합니다. 웹 워커는 백그라운드 탭에서 연결 끊김이 발생할 때 유용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버깅 및 로깅&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;debug: 디버그 메시지를 콘솔에 로깅하는 함수를 설정할 수 있습니다. 기본적으로 메시지는 버려집니다. 출력은 매우 자세하며 민감한 정보를 포함할 수 있으므로 주의해야 합니다.&lt;/li&gt;
&lt;li&gt;logRawCommunication: 브로커와의 실제 원시 통신을 로깅할지 여부를 설정합니다. 설정하지 않으면 파싱된 프레임의 헤더를 로깅합니다. 이 설정은 다음 브로커 재연결부터 적용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임 및 메시지 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;appendMissingNULLonIncoming: ReactNative의 버그로 인해 들어오는 WebSocket 메시지가 손상되는 경우 NULL을 추가하여 문제를 해결하려 시도하는 플래그입니다. 브로커가 큰 메시지를 여러 WebSocket 메시지로 분할하는 경우 데이터 손실 및 비정상적인 연결 종료를 유발할 수 있는 임시 방편입니다.&lt;/li&gt;
&lt;li&gt;splitLargeFrames: 큰 텍스트 패킷을 maxWebSocketChunkSize로 분할하여 전송하는 비표준 동작을 활성화합니다. 주로 Java Spring 브로커에서 지원되며, 기본값은 false입니다. 진정한 STOMP/WebSocket 규격 준수 브로커에서는 필요하지 않습니다.&lt;/li&gt;
&lt;li&gt;maxWebSocketChunkSize: splitLargeFrames가 true일 때 청크의 최대 크기를 정의합니다.&lt;/li&gt;
&lt;li&gt;forceBinaryWSFrames: WebSocket 프레임 유형을 강제로 바이너리로 설정합니다. 기본값은 false이며, 페이로드 유형에 따라 자동으로 결정됩니다.&lt;/li&gt;
&lt;li&gt;discardWebsocketOnCommFailure: 들어오는 하트비트 실패 시 즉시 소켓을 폐기하도록 지시하는 실험적 플래그입니다. 이는 브라우저에서 WebSocket 종료가 지연될 때 재연결 시간을 단축하는 데 도움이 될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 주요 메서드 (기능)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;연결 관리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;activate(): 브로커와의 연결을 시작합니다. 연결이 끊어지면 reconnectDelay 설정에 따라 재연결을 시도합니다. reconnectTimeMode가 EXPONENTIAL로 설정된 경우 대기 시간을 지수적으로 증가시킵니다.&lt;/li&gt;
&lt;li&gt;deactivate(): 연결을 끊고 자동 재연결 루프를 중지합니다. 이 호출은 비동기적이며, force: true 옵션을 사용하여 즉시 연결을 해제할 수 있습니다.&lt;/li&gt;
&lt;li&gt;forceDisconnect(): 현재 활성 연결이 있는 경우 기본 WebSocket을 직접 닫아 강제로 연결을 끊습니다. 이는 일반적인 DISCONNECT 절차와 다르며, 강제 연결 해제 후에도 자동 재연결이 시도될 수 있으므로, 재연결을 중지하려면 deactivate()를 호출해야 합니다.&lt;/li&gt;
&lt;li&gt;configure(conf: StompConfig): 클라이언트의 구성을 업데이트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 전송 및 수신&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;publish(params: IPublishParams): 지정된 목적지(destination)로 메시지를 보냅니다. body는 문자열이어야 하지만, binaryBody를 사용하여 Uint8Array 형태의 이진 메시지를 보낼 수 있습니다. content-length 헤더는 자동으로 추가되지만, skipContentLengthHeader를 사용하여 생략할 수 있습니다.&lt;/li&gt;
&lt;li&gt;subscribe(destination: string, callback: messageCallbackType, headers: StompHeaders): STOMP 브로커의 특정 위치를 구독합니다. 메시지 수신 시 콜백이 호출됩니다. 구독 ID가 헤더에 제공되지 않으면 라이브러리에서 고유 ID를 생성합니다.&lt;/li&gt;
&lt;li&gt;unsubscribe(id: string, headers: StompHeaders): 구독을 해지합니다. client.subscribe()가 반환한 StompSubscription 객체에서 직접 unsubscribe()를 호출하는 것이 선호됩니다.&lt;/li&gt;
&lt;li&gt;ack(messageId: string, subscriptionId: string, headers: StompHeaders): 메시지를 ACK(승인)합니다. IMessage 객체에서 직접 message.ack()를 호출하는 것이 선호됩니다.&lt;/li&gt;
&lt;li&gt;nack(messageId: string, subscriptionId: string, headers: StompHeaders): 메시지를 NACK(거부)합니다. IMessage 객체에서 직접 message.nack()를 호출하는 것이 선호됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;begin(transactionId?: string): 트랜잭션을 시작하며, commit 및 abort 메서드를 가진 ITransaction 객체를 반환합니다. transactionId는 선택 사항이며, 제공되지 않으면 라이브러리에서 내부적으로 생성합니다.&lt;/li&gt;
&lt;li&gt;commit(transactionId: string): 트랜잭션을 커밋합니다. ITransaction 객체에서 직접 tx.commit()을 호출하는 것이 선호됩니다.&lt;/li&gt;
&lt;li&gt;abort(transactionId: string): 트랜잭션을 중단합니다. ITransaction 객체에서 직접 tx.abort()를 호출하는 것이 선호됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수신 확인 (Receipt)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;watchForReceipt(receiptId: string, callback: frameCallbackType): STOMP 브로커로부터 특정 작업 완료에 대한 RECEIPT 프레임을 수신할 때 콜백을 호출하도록 설정합니다. receipt 헤더를 실제 요청과 함께 보내어 승인을 요청할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 접근자 (Accessors)&lt;/b&gt;&lt;/h4&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&gt;webSocket: 현재 사용 중인 기본 WebSocket 인스턴스입니다 (읽기 전용).&lt;/li&gt;
&lt;li&gt;connected: STOMP 브로커에 활성 연결이 있는지 여부를 나타내는 true/false 값입니다.&lt;/li&gt;
&lt;li&gt;connectedVersion: 서버와 협상된 STOMP 프로토콜의 버전입니다 (읽기 전용).&lt;/li&gt;
&lt;li&gt;active: 클라이언트가 활성 상태(연결되었거나 재연결 중)인지 여부를 나타냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 콜백 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 이벤트 발생 시 호출되는 콜백 함수를 제공하여 클라이언트 상태 변화 및 메시지/프레임 수신에 대응할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;beforeConnect: STOMP 브로커에 연결하기 전에 호출됩니다. 비동기 콜백을 지원하여 자격 증명 등을 비동기적으로 가져올 수 있습니다.&lt;/li&gt;
&lt;li&gt;onConnect: STOMP 브로커에 성공적으로 연결될 때마다 호출됩니다. 실제 IFrame이 매개변수로 전달됩니다.&lt;/li&gt;
&lt;li&gt;onDisconnect: STOMP 브로커에서 성공적으로 연결 해제될 때마다 호출됩니다. 에러로 인한 연결 해제 시에는 호출되지 않습니다.&lt;/li&gt;
&lt;li&gt;onStompError: STOMP 브로커로부터 ERROR 프레임을 수신할 때 호출됩니다. 규격 준수 브로커는 이 유형의 프레임 후 연결을 닫습니다.&lt;/li&gt;
&lt;li&gt;onWebSocketClose: 기본 WebSocket이 닫힐 때 호출됩니다. onDisconnect보다 브로커의 연결 해제를 감시하는 데 더 적절할 수 있습니다.&lt;/li&gt;
&lt;li&gt;onWebSocketError: 기본 WebSocket에서 오류가 발생할 때 호출됩니다.&lt;/li&gt;
&lt;li&gt;onUnhandledMessage: 처리되지 않은 메시지가 수신될 때 호출됩니다. RabbitMQ 임시 큐로 전송된 메시지나 구독 해지 요청 처리 중 서버에서 전송된 메시지에 유용합니다.&lt;/li&gt;
&lt;li&gt;onUnhandledReceipt: STOMP 브로커로부터 처리되지 않은 RECEIPT 프레임을 수신할 때 호출됩니다. Client#watchForReceipt를 사용하는 것이 권장됩니다.&lt;/li&gt;
&lt;li&gt;onUnhandledFrame: 알 수 없는 유형의 IFrame이 STOMP 브로커로부터 수신될 때 호출됩니다.&lt;/li&gt;
&lt;li&gt;onChangeState: 클라이언트의 활성화 상태가 변경될 때 호출됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 포괄적인 기능과 설정을 통해 @stomp/stompjs 라이브러리의 STOMP 클라이언트 클래스는 STOMP 기반 애플리케이션에서 유연하고 강력한 메시징 기능을 구현할 수 있도록 지원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Dev Log/Tools</category>
      <author>서카츄</author>
      <guid isPermaLink="true">https://seokachu.tistory.com/383</guid>
      <comments>https://seokachu.tistory.com/383#entry383comment</comments>
      <pubDate>Mon, 30 Jun 2025 01:03:40 +0900</pubDate>
    </item>
  </channel>
</rss>