<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>OI7MI</title>
    <link>https://yong-mi.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 10 Aug 2026 16:45:05 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>OI7MI</managingEditor>
    <image>
      <title>OI7MI</title>
      <url>https://tistory1.daumcdn.net/tistory/7034602/attach/cdd6d7323eb34d21895b33d9e05a4f0d</url>
      <link>https://yong-mi.tistory.com</link>
    </image>
    <item>
      <title>Java - Mac M2 환경 설치 정리</title>
      <link>https://yong-mi.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전에 다녔던 학원에서 나만 맥북이라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java와 Eclipse 설치, 환경변수 때문에 꽤 애먹었던 기억이 있는데,&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;내 노트북은 맥북 에어 M2라서 Windows와 설치 파일이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mac M2는 ARM 계열 칩이기 때문에 반드시 &lt;b&gt;AArch64&lt;/b&gt; 버전을 선택해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Java 25 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 Oracle 공식 페이지에서 다운로드한다.&lt;/p&gt;
&lt;figure id=&quot;og_1771565608429&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;Download the Latest Java LTS Free&quot; data-og-description=&quot;Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.&quot; data-og-host=&quot;www.oracle.com&quot; data-og-source-url=&quot;https://www.oracle.com/java/technologies/downloads/#jdk25-mac&quot; data-og-url=&quot;https://www.oracle.com/java/technologies/downloads/#jdk25-mac&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/sO4n2/dJMb9lL8bzS/LZbBZFklKMHUKJtA7N8VfK/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/m40OA/dJMb8YpR2Um/RWniBJkNWATpcLeg5GlPu0/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/downloads/#jdk25-mac&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.oracle.com/java/technologies/downloads/#jdk25-mac&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/sO4n2/dJMb9lL8bzS/LZbBZFklKMHUKJtA7N8VfK/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/m40OA/dJMb8YpR2Um/RWniBJkNWATpcLeg5GlPu0/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&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;Download the Latest Java LTS Free&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.33.39.png&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvoL42/dJMcafMn72s/Nyzr1z4QPs8UIVY3dKb0qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvoL42/dJMcafMn72s/Nyzr1z4QPs8UIVY3dKb0qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvoL42/dJMcafMn72s/Nyzr1z4QPs8UIVY3dKb0qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvoL42%2FdJMcafMn72s%2FNyzr1z4QPs8UIVY3dKb0qk%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;2410&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.33.39.png&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;110&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;macOS 탭에서 &lt;b&gt;ARM64 DMG Installer&lt;/b&gt; (jdk-25_macos-aarch64_bin.dmg) 를 받아서 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x64 버전을 받으면 설치 시 오류가 나니 파일명에 &lt;b&gt;aarch64&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;설치 후 터미널에서 아래 명령어로 정상 설치 여부를 확인한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1771565980776&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -version&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Eclipse 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 Eclipse 공식 페이지에서 다운로드한다.&lt;/p&gt;
&lt;figure id=&quot;og_1771565657287&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;Eclipse IDE 2025-12 R Packages | Eclipse Packages&quot; data-og-description=&quot;548 MB 358,614 DOWNLOADS Tools for developers working with Java and Web applications, including a Java IDE, tools for JavaScript, TypeScript, JavaServer Pages and Faces, Yaml, Markdown, Web Services, JPA and Data Tools, Maven and Gradle, Git, and more. Cli&quot; data-og-host=&quot;www.eclipse.org&quot; data-og-source-url=&quot;https://www.eclipse.org/downloads/packages/&quot; data-og-url=&quot;https://www.eclipse.org/downloads/packages/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.eclipse.org/downloads/packages/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.eclipse.org/downloads/packages/&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;Eclipse IDE 2025-12 R Packages | Eclipse Packages&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;548 MB 358,614 DOWNLOADS Tools for developers working with Java and Web applications, including a Java IDE, tools for JavaScript, TypeScript, JavaServer Pages and Faces, Yaml, Markdown, Web Services, JPA and Data Tools, Maven and Gradle, Git, and more. Cli&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.eclipse.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.34.23.png&quot; data-origin-width=&quot;1726&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RK3fX/dJMcabXuAgJ/xsaQS0kykFUbys7rlqWYyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RK3fX/dJMcabXuAgJ/xsaQS0kykFUbys7rlqWYyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RK3fX/dJMcabXuAgJ/xsaQS0kykFUbys7rlqWYyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRK3fX%2FdJMcabXuAgJ%2FxsaQS0kykFUbys7rlqWYyK%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;1726&quot; height=&quot;302&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.34.23.png&quot; data-origin-width=&quot;1726&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Eclipse IDE for Enterprise Java and Web Developers&lt;/b&gt; 항목에서 &lt;b&gt;macOS AArch64&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.36.41.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4gcOB/dJMcah4ub6H/QORlWFfcjJt1M6eZKdrV5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4gcOB/dJMcah4ub6H/QORlWFfcjJt1M6eZKdrV5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4gcOB/dJMcah4ub6H/QORlWFfcjJt1M6eZKdrV5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4gcOB%2FdJMcah4ub6H%2FQORlWFfcjJt1M6eZKdrV5k%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;2940&quot; height=&quot;1848&quot; data-filename=&quot;스크린샷 2026-02-20 오후 2.36.41.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1848&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>교육/컴퓨터과학과(방송통신대학교)</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/25</guid>
      <comments>https://yong-mi.tistory.com/25#entry25comment</comments>
      <pubDate>Fri, 20 Feb 2026 14:59:18 +0900</pubDate>
    </item>
    <item>
      <title>2026 방송대 컴퓨터과학과 입학기.</title>
      <link>https://yong-mi.tistory.com/24</link>
      <description>&lt;blockquote data-end=&quot;96&quot; data-start=&quot;78&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;우당탕당 입학 기록&lt;/span&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;합격자 발표일 2026.01.22&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;등록금 납부 기간 2026.01.22 ~ 2026.01.27&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n6tVt/dJMcadU40qD/GMbLKFYKe9MPnPwLiMRsO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n6tVt/dJMcadU40qD/GMbLKFYKe9MPnPwLiMRsO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n6tVt/dJMcadU40qD/GMbLKFYKe9MPnPwLiMRsO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn6tVt%2FdJMcadU40qD%2FGMbLKFYKe9MPnPwLiMRsO1%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;1344&quot; height=&quot;368&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1344&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZPWB0/dJMcadgvawb/rQsKFfmmgxBWvWnD7oqyAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZPWB0/dJMcadgvawb/rQsKFfmmgxBWvWnD7oqyAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZPWB0/dJMcadgvawb/rQsKFfmmgxBWvWnD7oqyAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZPWB0%2FdJMcadgvawb%2FrQsKFfmmgxBWvWnD7oqyAk%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;1176&quot; height=&quot;388&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;드디어 기다리던 합격 발표 날.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;설레는 마음으로 검색창에 '한국방송통신대학교'를 검색해 들어간 사이트에서 이름과 주민등록번호를 입력했다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;197&quot; data-start=&quot;98&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그런데 화면에 뜬 결과는 뜻밖에도 '불합격' ???????????&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;순간 심장이 덜컥 내려앉으며 오만가지 생각이 다 들었다. '설마 서류에 문제가 있었나?' 싶어 한참을 당황했는데&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;알고 보니 내가 들어갔던 곳은 엉뚱한 사이트(?) 엉뚱한 경로(?) 였다 ㅎㅎ.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사이트를 잘못 들어갔는데 왜 내 정보로 조회가 됐던 건지 지금 생각해도 미스터리하지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입학 전 가슴 철렁했던 짧은 해프닝으로 웃어넘기기로 했다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;진짜 합격을 확인했으니, 이제 산 넘어 산이었던 등록금과 학자금 대출 문제를 해결할 차례다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;763&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;763&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;763&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;835&quot; data-start=&quot;763&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;figure id=&quot;og_1769408646784&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;한국장학재단&quot; data-og-description=&quot;x 서비스 이용자 등록/로그인이 필요한 서비스 입니다. 한국장학재단 각종 서비스를 이용하기 위해서는 로그인 후 이용이 가능합니다. 로그인을 원하지 않는 경우 '돌아가기' 버튼을 눌러주세요&quot; data-og-host=&quot;www.kosaf.go.kr&quot; data-og-source-url=&quot;https://www.kosaf.go.kr/ko/main.do&quot; data-og-url=&quot;https://www.kosaf.go.kr/ko/main.do&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cqEbYK/dJMb8QegCnG/M5NnKmoauUrWhASXsFUOT1/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800,https://scrap.kakaocdn.net/dn/bCO5kI/dJMb89x7Yrs/NCZ5qLQG4oxRkxl9npnrWk/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800,https://scrap.kakaocdn.net/dn/bfOzPr/dJMb9gxfMXi/vK3tAFH48rDQehJk5cGqW0/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800&quot;&gt;&lt;a href=&quot;https://www.kosaf.go.kr/ko/main.do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kosaf.go.kr/ko/main.do&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cqEbYK/dJMb8QegCnG/M5NnKmoauUrWhASXsFUOT1/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800,https://scrap.kakaocdn.net/dn/bCO5kI/dJMb89x7Yrs/NCZ5qLQG4oxRkxl9npnrWk/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800,https://scrap.kakaocdn.net/dn/bfOzPr/dJMb9gxfMXi/vK3tAFH48rDQehJk5cGqW0/img.jpg?width=1180&amp;amp;height=800&amp;amp;face=0_0_1180_800');&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;한국장학재단&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;x 서비스 이용자 등록/로그인이 필요한 서비스 입니다. 한국장학재단 각종 서비스를 이용하기 위해서는 로그인 후 이용이 가능합니다. 로그인을 원하지 않는 경우 '돌아가기' 버튼을 눌러주세요&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.kosaf.go.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-26 오후 3.25.57.png&quot; data-origin-width=&quot;2920&quot; data-origin-height=&quot;1320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GpAXv/dJMcadHyxXs/G6WpXEDkLEEOYYuKok4Ikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GpAXv/dJMcadHyxXs/G6WpXEDkLEEOYYuKok4Ikk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GpAXv/dJMcadHyxXs/G6WpXEDkLEEOYYuKok4Ikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGpAXv%2FdJMcadHyxXs%2FG6WpXEDkLEEOYYuKok4Ikk%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;2920&quot; height=&quot;1320&quot; data-filename=&quot;스크린샷 2026-01-26 오후 3.25.57.png&quot; data-origin-width=&quot;2920&quot; data-origin-height=&quot;1320&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 style=&quot;text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;학자금 대출&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;학자금 대출은 위 사이트에서 신청할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;방송통신대학교는 자비로 등록금을 납부할 수도 있지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;학자금 지원구간에 해당한다면,&amp;nbsp;&lt;b data-path-to-node=&quot;5,1,0&quot; data-index-in-node=&quot;23&quot;&gt;우선 학자금 대출로 등록금을 납부하고 사후에 국가장학금으로 상환받는 방식&lt;/b&gt;을 추천한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;절차가 간편할 뿐만 아니라 초기 비용 부담을 줄이는 효율적인 방법이기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;98&quot; data-end=&quot;197&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;98&quot; data-end=&quot;197&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;2930&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq9uFG/dJMcaiWoUJQ/nuMvXLDQFfrcpePcLG0hR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq9uFG/dJMcaiWoUJQ/nuMvXLDQFfrcpePcLG0hR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq9uFG/dJMcaiWoUJQ/nuMvXLDQFfrcpePcLG0hR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq9uFG%2FdJMcaiWoUJQ%2FnuMvXLDQFfrcpePcLG0hR0%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;2930&quot; height=&quot;1600&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2930&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나는 우선 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;자비로 등록금을 먼저 납부&lt;/span&gt;했고, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;이후 학자금 대출을 신청&lt;/span&gt;했다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만 예상치 못하게 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;승인 거절&lt;/span&gt;&lt;/b&gt; 문구를 확인하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;원인을 파악해 보니 '&lt;u&gt;여신거래 안심차단 서비스&lt;/u&gt;'가 설정되어 있어 대출 진행이 막혀 있었던 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;199&quot; data-end=&quot;307&quot; data-ke-size=&quot;size14&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;1206&quot; data-origin-height=&quot;2171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8qbLL/dJMcaaqzbNr/j3rZNCYofdk9iEM4JmQwbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8qbLL/dJMcaaqzbNr/j3rZNCYofdk9iEM4JmQwbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8qbLL/dJMcaaqzbNr/j3rZNCYofdk9iEM4JmQwbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8qbLL%2FdJMcaaqzbNr%2Fj3rZNCYofdk9iEM4JmQwbK%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;450&quot; height=&quot;810&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;2171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;309&quot; data-end=&quot;331&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;309&quot; data-end=&quot;331&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;309&quot; data-end=&quot;331&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;해야 할 일은 세 가지였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;309&quot; data-end=&quot;331&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b data-path-to-node=&quot;9,0,1,0,0&quot; data-index-in-node=&quot;0&quot;&gt;Step 1:&lt;/b&gt;&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;신한은행 방문 후 '여신거래 안심차단 서비스' 해지&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,1,0,0&quot;&gt;Step 2:&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;학자금 대출 진행&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b data-path-to-node=&quot;9,0,1,1,0&quot; data-index-in-node=&quot;0&quot;&gt;Step 3:&lt;/b&gt;&amp;nbsp;학교 학생과에 연락하여 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;'기등록 처리' 요청&lt;/span&gt; (이미 자비로 납부한 경우 필수)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;서비스 해지 후 다시 신청을 시도했으나&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;'STP2(기신청 상태) 단계에서 유형 선택 불가'라는 오류 메시지가 반복되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다음으로 안 넘어갔다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&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;IMG_4148.jpg&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;2335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Umka9/dJMcafZHfw1/XRKgEpWciIDyLybjnlouR0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Umka9/dJMcafZHfw1/XRKgEpWciIDyLybjnlouR0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Umka9/dJMcafZHfw1/XRKgEpWciIDyLybjnlouR0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUmka9%2FdJMcafZHfw1%2FXRKgEpWciIDyLybjnlouR0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;871&quot; data-filename=&quot;IMG_4148.jpg&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;2335&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;시스템 오류로 답답한 마음에 결국 한국장학재단 고객센터로 전화를 걸었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;상담원분께서 내 내역을 조회하시더니 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;등록금 납부 기한이 바로 내일까지인데 알고 계셨냐며 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;최대한 빨리 처리 도와드릴 테니 너무 걱정하지 말라고 다정하게 말씀해 주셨다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;마감이 코앞이라 조급했던 마음이 그 따뜻한 한마디에 사르르 녹는 기분이었다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;추운 겨울이었지만 덕분에 마음만은 무척 따뜻해졌다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;역시 해결이 안 될 때는 혼자 끙끙 앓기보다 전화 상담을 하는 것이 가장 빠르고 정확하다는 걸 다시 한번 체감했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;전화 상담 후 두 시간도 채 지나지 않아 '학자금 대출 심사 승인' 안내 카톡이 왔다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;495&quot; data-end=&quot;594&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;곧바로 대출 실행을 눌러 무사히 등록을 마칠 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-start=&quot;763&quot; data-end=&quot;835&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;763&quot; data-end=&quot;835&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;763&quot; data-end=&quot;835&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;1206&quot; data-origin-height=&quot;2337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1kzmv/dJMcaihPCjN/yGKKCABNs4lB0MJAWgOc11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1kzmv/dJMcaihPCjN/yGKKCABNs4lB0MJAWgOc11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1kzmv/dJMcaihPCjN/yGKKCABNs4lB0MJAWgOc11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1kzmv%2FdJMcaihPCjN%2FyGKKCABNs4lB0MJAWgOc11%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;450&quot; height=&quot;872&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;2337&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;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;예전 대학생 때 학자금 대출을 신청하려면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;가구원 동의 절차&lt;/span&gt;부터 참 복잡해서 고생했던 기억이 난다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그래서 이번에도 긴장하며 준비했는데 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;별도 절차 없이 바로 넘어가서 조금 놀랐다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;자퇴한 지 꽤 오랜 시간이 흘렀음에도 기존 정보가 유효한 것인지 신기하기도 하고 다행이다 싶었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;등록을 마치고 나니 앞으로의 학교생활이 더 궁금해져서 여러 커뮤니티도 찾아보았다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다행히 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;카카오톡 오픈채팅방&lt;/span&gt;이 활성화되어 있어 수강 과목을 선택하는 데 정말 큰 도움을 받았다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;또한 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;방송대 카페&lt;/span&gt;에는 중고 교재 거래나 실질적인 공부 정보가 많아서 앞으로도 자주 이용하게 될 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;5&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;선택경비는 따로 신청하지 않았고, 가장 중요한 교재는 카페 등을 통해 새 책 대신 중고로 알뜰하게 구매할 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;우여곡절 끝에 마친 등록인 만큼, 열심히 해야겠다는 생각과 함께 기분 좋은 떨림이 가득하다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이번 학기 화이팅.&lt;/span&gt;&lt;/p&gt;</description>
      <category>교육/컴퓨터과학과(방송통신대학교)</category>
      <category>방송대</category>
      <category>방송통신대학교</category>
      <category>방송통신대학교입학</category>
      <category>방통대</category>
      <category>학자금대출</category>
      <category>학자금대출가구원동의</category>
      <category>학자금대출거절</category>
      <category>학자금대출승인</category>
      <category>학자금생활비대출</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/24</guid>
      <comments>https://yong-mi.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 26 Jan 2026 16:38:29 +0900</pubDate>
    </item>
    <item>
      <title>[React] TMDB API: 한 번의 요청으로 영화 상세정보와 유튜브 예고편 가져오기</title>
      <link>https://yong-mi.tistory.com/23</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-filename=&quot;blob&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxrpkk/dJMcaaRAk2i/Sg9D5p5oE7r0K8dGkdH351/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxrpkk/dJMcaaRAk2i/Sg9D5p5oE7r0K8dGkdH351/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxrpkk/dJMcaaRAk2i/Sg9D5p5oE7r0K8dGkdH351/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcxrpkk%2FdJMcaaRAk2i%2FSg9D5p5oE7r0K8dGkdH351%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;2032&quot; height=&quot;1000&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1000&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;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 문제 상황: &quot;데이터가 부족하다?&quot;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;기존에 사용하던 영화 상세 정보 API 호출 방식으로는 영화의 줄거리나 평점 정보는 가져올 수 있었지만&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;204&quot; data-start=&quot;152&quot; data-ke-size=&quot;size16&quot;&gt;영화의 핵심 콘텐츠라고 할 수 있는 &amp;lsquo;예고편 영상&amp;rsquo; 데이터가 포함되어 있지 않았다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;204&quot; data-start=&quot;152&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;281&quot; data-start=&quot;206&quot; data-ke-size=&quot;size16&quot;&gt;이를 어떻게 해결할 수 있을지 고민하던 중,&lt;br /&gt;TMDB에서 제공하는 append_to_response 기능을 사용하기로 했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;313&quot; data-start=&quot;283&quot; data-ke-size=&quot;size16&quot;&gt;기존에 사용하던 API 호출 방식은 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1768669533023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const url = `https://api.themoviedb.org/3/movie/${id}?language=ko-KR`;&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;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;여기에 유튜브 예고편 영상을 함께 가져오기 위해&lt;br /&gt;아래와 같이 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;append_to_response=videos&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;pre id=&quot;code_1768669542277&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const url = `https://api.themoviedb.org/3/movie/${id}?language=ko-KR&amp;amp;append_to_response=videos`;&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;blockquote data-path-to-node=&quot;8&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. 예외 처리: &quot;데이터가 항상 Trailer인 것은 아니다&quot;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 분석해보니&lt;br /&gt;한국어(ko-KR) 설정 시 예고편이 항상 Trailer 타입으로만 제공되지 않는다는 것을 알게 되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;817&quot; data-start=&quot;708&quot; data-ke-size=&quot;size16&quot;&gt;경우에 따라 Featurette(제작기)나 Teaser로 들어오는 경우도 있었고,&lt;br /&gt;이대로라면 예고편이 있음에도 불구하고 사용자에게 아무것도 보여주지 못하는 상황이 발생할 수 있었다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;878&quot; data-start=&quot;819&quot; data-ke-size=&quot;size16&quot;&gt;그래서 사용자에게 &amp;lsquo;뭐라도&amp;rsquo; 보여주기 위해 아래와 같은 영상 타입 우선순위 로직을 구현했다.&lt;/p&gt;
&lt;pre id=&quot;code_1768669690289&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 영상 타입 우선순위 로직

const video =
  results.find((v) =&amp;gt; v.type === &quot;Trailer&quot;) || // 1순위: 공식 예고편
  results.find((v) =&amp;gt; v.type === &quot;Teaser&quot;) ||  // 2순위: 티저
  results.find((v) =&amp;gt; v.type === &quot;Featurette&quot;) || // 3순위: 특별 영상
  results[0]; // 4순위: 그 외 첫 번째 영상&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;blockquote data-path-to-node=&quot;11&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3. 보안 및 사용자 경험&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1332&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;유튜브 링크를 열 때는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;window.open&lt;/span&gt;을 사용해 새 탭에서 열리도록 설정했다.&lt;br /&gt;이를 통해 사용자가 서비스 페이지를 이탈하지 않으면서도 영상을 감상할 수 있도록 UX를 고려했다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1332&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1332&quot; data-start=&quot;1219&quot; data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드다.&lt;/p&gt;
&lt;pre id=&quot;code_1768669745491&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const showYouTube = () =&amp;gt; {
  if (!movie || !movie.videos || movie.videos.results.length === 0) {
    alert(&quot;제공되는 YouTube 예고편이 없습니다.&quot;);
    return;
  }
  
  const results = movie.videos.results;
  const video =
    results.find((v) =&amp;gt; v.type === &quot;Trailer&quot;) || // 1순위: 공식 예고편
    results.find((v) =&amp;gt; v.type === &quot;Teaser&quot;) || // 2순위: 티저
    results.find((v) =&amp;gt; v.type === &quot;Featurette&quot;) || // 3순위: 특별 영상
    results[0]; // 4순위: 그 외 첫 번째 영상

  if (video &amp;amp;&amp;amp; video.site === &quot;YouTube&quot;) {
    window.open(`https://www.youtube.com/watch?v=${video.key}`, &quot;_blank&quot;);
  } else {
    alert(&quot;YouTube 영상을 찾을 수 없습니다.&quot;);
  }
}
    
    
&amp;lt;button onClick={showYouTube}&amp;gt;예고편 보기&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-18 오전 2.19.36.png&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2r8e/dJMcabbSFum/dB8JzksCfHHHZ0fbWsZog1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2r8e/dJMcabbSFum/dB8JzksCfHHHZ0fbWsZog1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2r8e/dJMcabbSFum/dB8JzksCfHHHZ0fbWsZog1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2r8e%2FdJMcabbSFum%2FdB8JzksCfHHHZ0fbWsZog1%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;789&quot; height=&quot;544&quot; data-filename=&quot;스크린샷 2026-01-18 오전 2.19.36.png&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;544&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;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&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 style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;마무리&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;API 데이터를 다룰 때 단순히 매뉴얼만 따라가는 것이 아니라,&lt;br /&gt;실제 응답 데이터(results)의 구조를 console.log로 직접 확인하며&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;</description>
      <category>프론트엔드/React</category>
      <category>API</category>
      <category>Movie</category>
      <category>React</category>
      <category>영화api</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/23</guid>
      <comments>https://yong-mi.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 18 Jan 2026 02:21:31 +0900</pubDate>
    </item>
    <item>
      <title>[React] 별점(Star Rating) 라이브러리로 구현하기</title>
      <link>https://yong-mi.tistory.com/22</link>
      <description>&lt;p data-end=&quot;336&quot; data-start=&quot;297&quot; data-ke-size=&quot;size16&quot;&gt;숫자로만 표시되던 평점을 별점 UI로 표현하고 싶어 관련 라이브러리를 찾아보았다.&lt;br /&gt;그 과정에서 아주 간편하게 별점 UI를 구현할 수 있는 라이브러리를 발견해 프로젝트에 적용해보았다.&lt;/p&gt;
&lt;p data-end=&quot;254&quot; data-start=&quot;185&quot; data-ke-size=&quot;size16&quot;&gt;특히 소수점(반쪽 별)까지 자동으로 처리해줘서 별도의 로직 없이도 자연스러운 평점 표시가 가능해 사용성이 좋았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-15 오후 8.08.48.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqA7Nx/dJMcafZDciZ/rKOWxUqNgYpnlkCBQmKsH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqA7Nx/dJMcafZDciZ/rKOWxUqNgYpnlkCBQmKsH1/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqA7Nx/dJMcafZDciZ/rKOWxUqNgYpnlkCBQmKsH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqA7Nx%2FdJMcafZDciZ%2FrKOWxUqNgYpnlkCBQmKsH1%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;2940&quot; height=&quot;634&quot; data-filename=&quot;스크린샷 2026-01-15 오후 8.08.48.png&quot; data-origin-width=&quot;2940&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 data-end=&quot;254&quot; data-start=&quot;185&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;254&quot; data-start=&quot;185&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;blockquote data-end=&quot;355&quot; data-start=&quot;343&quot; data-ke-style=&quot;style2&quot;&gt;사용한 라이브러리&lt;/blockquote&gt;
&lt;blockquote data-end=&quot;388&quot; data-start=&quot;357&quot; data-ke-style=&quot;style3&quot;&gt;react-simple-star-rating&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;442&quot; data-start=&quot;390&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;403&quot; data-start=&quot;390&quot;&gt;가볍고 설정이 단순함&lt;/li&gt;
&lt;li data-end=&quot;415&quot; data-start=&quot;404&quot;&gt;소수점 별점 지원&lt;/li&gt;
&lt;li data-end=&quot;442&quot; data-start=&quot;416&quot;&gt;클릭 가능한 별점 / 표시용 별점 모두 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;460&quot; data-start=&quot;449&quot; data-ke-style=&quot;style2&quot;&gt;라이브러리 설치&lt;/blockquote&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;npm install react-simple-star-rating&lt;/blockquote&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;530&quot; data-start=&quot;517&quot; data-ke-style=&quot;style2&quot;&gt;별점 컴포넌트 생성&lt;/blockquote&gt;
&lt;p data-end=&quot;607&quot; data-start=&quot;532&quot; data-ke-size=&quot;size16&quot;&gt;영화 API(TMDB)는 10점 만점 평점을 반환하기 때문에, 별점 UI(5점 만점)에 맞게 2로 나눠서 변환했다&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;pre id=&quot;code_1768471189516&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Rating } from &quot;react-simple-star-rating&quot;; 

// 별점 컴포넌트 
const StarRating = ({ rating }) =&amp;gt; { 
	return ( 
    	&amp;lt;Rating 
            initialValue={rating / 2} 	// 10점 만점을 5점으로 변환 
            readonly={true} 			// 클릭 비활성화 (표시 전용) 
            size={20} 					// 별 크기 
            fillColor=&quot;gold&quot; 			// 채워진 별 색 
            emptyColor=&quot;gray&quot; 			// 빈 별 색 
            allowFraction={true} 		// 소수점(반쪽 별) 허용 
         /&amp;gt; 
     ); 
}; 

export default StarRating;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-end=&quot;1294&quot; data-start=&quot;1270&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다른 컴포넌트에서 사용하기&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;내가 사용한 TMDB API 데이터(vote_average)는 소수점이 매우 길게 나온다 (예: 7.834)&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;5&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;5,0,0&quot;&gt;방식 A: movie.vote_average 그대로 넣을 때&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라이브러리에 7.834라는 숫자가 그대로 전달&lt;/li&gt;
&lt;li&gt;라이브러리는 내부 로직에 따라 이걸 7.8로 그릴 수도 있고, 그냥 8.0에 가깝게 꽉 채워버릴 수도 있다&amp;nbsp;&lt;s&gt;(반올림 기준이 모호함)&lt;/s&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;방식 B: Number(vote_average.toFixed(1))를 쓸 때&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7.834가 강제로 7.8로 딱 잘린다&lt;/li&gt;
&lt;li&gt;라이브러리에 정확히 7.8이라는 숫자만 전달되므로 내가 의도한 눈금만큼만 별이 칠해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1768471269578&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import StarRating from &quot;./StarRating&quot;; 

&amp;lt;h4&amp;gt; 
	&amp;lt;StarRating rating={Number(vote_average.toFixed(1))} /&amp;gt; 
&amp;lt;/h4&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1491&quot; data-start=&quot;1483&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1638&quot; data-start=&quot;1493&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1536&quot; data-start=&quot;1493&quot;&gt;TMDB의 &lt;b&gt;10점 만점 평점 &amp;rarr; 5점 만점 별점으로 자연스럽게 변환&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1575&quot; data-start=&quot;1537&quot;&gt;7.8 / 8.3 같은 &lt;b&gt;소수점 평점도 반쪽 별로 자동 표시&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1638&quot; data-start=&quot;1576&quot;&gt;읽기 전용(readonly)으로 설정하여&lt;br /&gt;  사용자 입력이 아닌 &lt;b&gt;정보 표시용 UI&lt;/b&gt;로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-end=&quot;1643&quot; data-start=&quot;1640&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1650&quot; data-start=&quot;1645&quot; data-ke-style=&quot;style2&quot;&gt;정리&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1776&quot; data-start=&quot;1652&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1675&quot; data-start=&quot;1652&quot;&gt;⭐ 별점 UI를 직접 구현할 필요 없음&lt;/li&gt;
&lt;li data-end=&quot;1717&quot; data-start=&quot;1676&quot;&gt;⭐ react-simple-star-rating 하나로 빠르게 해결&lt;/li&gt;
&lt;li data-end=&quot;1738&quot; data-start=&quot;1718&quot;&gt;⭐ 소수점 처리까지 자동으로 지원&lt;/li&gt;
&lt;li data-end=&quot;1776&quot; data-start=&quot;1739&quot;&gt;⭐ 영화 사이트처럼 &amp;ldquo;평점 표시&amp;rdquo;가 필요한 프로젝트에 매우 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1841&quot; data-start=&quot;1778&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1841&quot; data-start=&quot;1780&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;영화 평점 UI는 복잡할 것 같지만 라이브러리를 활용하면 코드 몇 줄로 깔끔하게 해결할 수 있다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>프론트엔드/React</category>
      <category>별점라이브러리</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/22</guid>
      <comments>https://yong-mi.tistory.com/22#entry22comment</comments>
      <pubDate>Thu, 15 Jan 2026 20:10:17 +0900</pubDate>
    </item>
    <item>
      <title>[React] 리액트 &amp;lt;Link&amp;gt;와 HTML &amp;lt;a&amp;gt;의 차이점 (feat. CSS가 안 먹히는 이유)</title>
      <link>https://yong-mi.tistory.com/21</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-end=&quot;134&quot; data-start=&quot;93&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;215&quot; data-start=&quot;170&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;p data-end=&quot;215&quot; data-start=&quot;172&quot; data-ke-size=&quot;size16&quot;&gt;React 에서 &amp;lt;Link&amp;gt;를 쓰는데, CSS에서는 왜 a로 스타일을 잡아야 하는가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;313&quot; data-start=&quot;281&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&amp;lt;Link&amp;gt;는 결국 &amp;lt;a&amp;gt; 태그로 변한다&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;338&quot; data-start=&quot;315&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;pre id=&quot;code_1768468474906&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link to={`/movie/${id}`}&amp;gt; 
	&amp;lt;img src={coverImage} alt={title} title={title} /&amp;gt; 
&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;481&quot; data-start=&quot;440&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;481&quot; data-start=&quot;440&quot; data-ke-size=&quot;size16&quot;&gt;브라우저가 실제로 이해하는 것은 &amp;lt;Link&amp;gt;가 아님 ❌&lt;/p&gt;
&lt;p data-end=&quot;557&quot; data-start=&quot;483&quot; data-ke-size=&quot;size16&quot;&gt;리액트는 빌드 및 렌더링 과정에서 &amp;lt;Link&amp;gt; 컴포넌트를 표준 HTML 태그인 &amp;lt;a&amp;gt;로 변환해서 브라우저에 전달한다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;622&quot; data-start=&quot;559&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;584&quot; data-start=&quot;559&quot;&gt;브라우저는 &amp;lt;Link&amp;gt;라는 태그를 모름&lt;/li&gt;
&lt;li data-end=&quot;622&quot; data-start=&quot;585&quot;&gt;브라우저가 이해할 수 있는 것은 오직 HTML 표준 태그&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;676&quot; data-start=&quot;624&quot; data-ke-size=&quot;size16&quot;&gt;  그래서 개발자 도구로 보면 &amp;lt;Link&amp;gt;는 항상 &amp;lt;a&amp;gt; 태그로 렌더링되어 있다&lt;/p&gt;
&lt;p data-end=&quot;676&quot; data-start=&quot;624&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-end=&quot;723&quot; data-start=&quot;683&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;그런데 왜 그냥 &amp;lt;a&amp;gt;를 안 쓰고 &amp;lt;Link&amp;gt;를 쓸까?&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-end=&quot;784&quot; data-start=&quot;765&quot; data-ke-style=&quot;style2&quot;&gt;&amp;lt;a&amp;gt; 태그의 동작 방식&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1768468567069&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;/movie/1&quot;&amp;gt;이동&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;907&quot; data-start=&quot;825&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;849&quot; data-start=&quot;825&quot;&gt;클릭 시 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;페이지 전체를 새로 요청&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;871&quot; data-start=&quot;850&quot;&gt;브라우저가 새 HTML을 다시 받음&lt;/li&gt;
&lt;li data-end=&quot;882&quot; data-start=&quot;872&quot;&gt;화면이 깜빡이고&lt;/li&gt;
&lt;li data-end=&quot;907&quot; data-start=&quot;883&quot;&gt;리액트 상태(state)가 전부 초기화됨&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;931&quot; data-start=&quot;909&quot; data-ke-style=&quot;style2&quot;&gt;&amp;lt;Link&amp;gt; 태그의 동작 방식&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1768468579218&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link to=&quot;/movie/1&quot;&amp;gt;이동&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1042&quot; data-start=&quot;975&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;992&quot; data-start=&quot;975&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;페이지 새로고침 없음&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1002&quot; data-start=&quot;993&quot;&gt;주소창만 변경&lt;/li&gt;
&lt;li data-end=&quot;1021&quot; data-start=&quot;1003&quot;&gt;필요한 컴포넌트만 교체 렌더링&lt;/li&gt;
&lt;li data-end=&quot;1042&quot; data-start=&quot;1022&quot;&gt;상태 유지 + 부드러운 화면 전환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1164&quot; data-start=&quot;1106&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;페이지 이동 방식이 완전히 다르기 때문!&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-end=&quot;1202&quot; data-start=&quot;1171&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;CSS에서 a로 스타일을 잡아야 하는 이유&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-end=&quot;1228&quot; data-start=&quot;1204&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1768468701733&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* ✅ 정상 동작 */ 
.movie_card a { display: block;} 

/* ❌ 동작 안 함 */ 
.movie_card Link { display: block; }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1462&quot; data-start=&quot;1379&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1406&quot; data-start=&quot;1379&quot;&gt;CSS는 HTML 태그와 클래스만 인식&lt;/li&gt;
&lt;li data-end=&quot;1432&quot; data-start=&quot;1407&quot;&gt;Link는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;리액트 컴포넌트 이름&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1462&quot; data-start=&quot;1433&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;브라우저 입장에서는 이미 &amp;lt;a&amp;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-end=&quot;1821&quot; data-start=&quot;1818&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1832&quot; data-start=&quot;1823&quot; data-ke-style=&quot;style2&quot;&gt;한 줄 요약&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1971&quot; data-start=&quot;1834&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1881&quot; data-start=&quot;1834&quot;&gt;리액트의 &amp;lt;Link&amp;gt;는 브라우저에서 &amp;lt;a&amp;gt;로 렌더링된다&lt;/li&gt;
&lt;li data-end=&quot;1923&quot; data-start=&quot;1882&quot;&gt;CSS에서는 반드시 a 태그로 선택해야 한다&lt;/li&gt;
&lt;li data-end=&quot;1971&quot; data-start=&quot;1924&quot;&gt;새로고침 없는 SPA 이동을 가능하게 해주는 리액트 전용 링크&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>프론트엔드/React</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/21</guid>
      <comments>https://yong-mi.tistory.com/21#entry21comment</comments>
      <pubDate>Thu, 15 Jan 2026 18:22:03 +0900</pubDate>
    </item>
    <item>
      <title>[React] SPA 페이지 이동: react-router-dom (Link, useParams)</title>
      <link>https://yong-mi.tistory.com/20</link>
      <description>&lt;blockquote data-path-to-node=&quot;2&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;리액트 라우터(React Router) : 페이지 이동 구현&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;리액트는 &lt;b data-index-in-node=&quot;5&quot; data-path-to-node=&quot;7&quot;&gt;SPA(Single Page Application)&lt;/b&gt; 구조를 사용한다. 즉, 페이지를 이동하더라도 매번 서버로부터 새로운 HTML 파일을 받아오는 것이 아니라, &lt;b data-index-in-node=&quot;95&quot; data-path-to-node=&quot;7&quot;&gt;하나의 HTML 문서 위에서 URL 변경에 따라 렌더링되는 컴포넌트만 교체&lt;/b&gt;한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;이때 &lt;u&gt;URL 경로(path)에 따라 어떤 컴포넌트를 렌더링할지 매핑해 주는 라이브러리가 react-router-dom&lt;/u&gt; 이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;이를 통해 브라우저 주소창의 변경을 감지하고, 새로고침 없이도 페이지 이동이 가능한 것처럼 동작&lt;/span&gt;하게 만들 수 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style2&quot;&gt;1. 라이브러리 설치&lt;/blockquote&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQwAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install react-router-dom
&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style2&quot;&gt;2. 기본 구조&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 Router로 전체를 감싸고, 그 안에 Routes와 Route를 배치한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;Routes&lt;/b&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;현재 URL과 일치하는 단 하나의 Route만 렌더링하기 위해 사용&lt;/span&gt;&amp;nbsp;(v5의 Switch에서 이름이 변경되었음)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;Route&lt;/b&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;특정 경로(path)와 그에 맞게 보여줄 컴포넌트(element)를 연결&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;10&quot; data-ke-style=&quot;style2&quot;&gt;3. 코드 적용&lt;/blockquote&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQwQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;import { BrowserRouter as Router, Routes, Route } from &quot;react-router-dom&quot;;

function App() {
  return (
    &amp;lt;Router&amp;gt;
      &amp;lt;Routes&amp;gt;
        {/* /movie 경로면 Detail 컴포넌트 렌더링 */}
        &amp;lt;Route path=&quot;/movie&quot; element={&amp;lt;Detail /&amp;gt;} /&amp;gt;
        
        {/* / (기본 경로)면 Home 컴포넌트 렌더링 */}
        &amp;lt;Route path=&quot;/&quot; element={&amp;lt;Home /&amp;gt;} /&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/Router&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style2&quot;&gt;  요약하자면 결국 컴포넌트들은 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;17&quot;&gt;현재 브라우저의 URL을 주시&lt;/b&gt;하고 있다가, 주소가 바뀌면 미리 약속된 컴포넌트로 화면을 갈아 끼우는 역할을 한다. 사용자 입장에서는 페이지가 이동하는 것처럼 느껴지지만, 실제로는 하나의 문서 내에서 효율적으로 컴포넌트만 교체되는 것이다.&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-path-to-node=&quot;3&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&amp;lt;Link&amp;gt; 컴포넌트 : 새로고침 없는 페이지 이동&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;앞서 리액트가 SPA(Single Page Application)라고 설명했다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하지만 우리가 평소에 쓰는 &amp;lt;a&amp;gt; 태그를 그대로 사용하면 리액트의 가장 큰 장점 중 하나가 무력화된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;5&quot; data-ke-style=&quot;style2&quot;&gt;1. 왜 &amp;lt;a&amp;gt; 태그를 쓰면 안 될까?&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;보통 HTML에서 사용하는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;lt;a href=&quot;...&quot;&amp;gt;&lt;/span&gt;&lt;/b&gt;는 클릭 시 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b data-index-in-node=&quot;36&quot; data-path-to-node=&quot;6&quot;&gt;브라우저 전체를 새로고침한다&lt;/b&gt;&lt;/span&gt;. 즉, 서버로부터 아예 새로운 문서를 처음부터 다시 받아오는 것. 이렇게 되면 &lt;u&gt;리액트 앱이 들고 있던 데이터(state)가 초기화되고, 화면이 깜빡거리며 SPA의 속도 이점을 누릴 수 없게 된다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style2&quot;&gt;2. &amp;lt;Link&amp;gt; 컴포넌트의 역할&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;react-router-dom에서 제공하는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;8&quot;&gt;&amp;lt;Link&amp;gt;&lt;/b&gt; 컴포넌트는 브라우저의 새로고침을 막아준다&lt;/span&gt;.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;대신 &lt;b data-index-in-node=&quot;59&quot; data-path-to-node=&quot;8&quot;&gt;브라우저의 주소창만 바꾸고, 리액트가 바뀐 주소에 맞는 컴포넌트만 가로채서 다시 그릴 수 있도록&lt;/b&gt; 도와준다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;9&quot; data-ke-style=&quot;style2&quot;&gt;3. 코드&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;먼저 라이브러리에서 Link를 불러온 뒤, to 속성에 이동할 경로를 적어준다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQ7QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { Link } from &quot;react-router-dom&quot;;

function Movie({ title, id }) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;
        {/* 클릭 시 /movie 경로로 이동하지만, 새로고침은 발생하지 않음 */}
        &amp;lt;Link to=&quot;/movie&quot;&amp;gt;{title}&amp;lt;/Link&amp;gt;
      &amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-path-to-node=&quot;2&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;useParams : 어떤 데이터를 클릭했는지 알아내는 법&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;페이지가 하나뿐인 상세 페이지(Detail) 컴포넌트가 어떻게 수많은 데이터 중 &lt;b data-index-in-node=&quot;44&quot; data-path-to-node=&quot;3&quot;&gt;내가 클릭한 정보만&lt;/b&gt; 가져올 수 있을까?&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;그 비밀은 URL에 담긴 id 값에 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style2&quot;&gt;1. 주소에 &quot;변수&quot; 자리를 만들기 (App.js)&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;먼저 라우터를 설정할 때, id가 들어갈 자리를 비워줘야 한다. 이때 사용하는 것이 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;콜론(:)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQ_AE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// :id는 &quot;이 자리에 값이 들어올 건데, 그 값을 id라고 부를게&quot;라는 약속.

&amp;lt;Route path=&quot;/movie/:id&quot; element={&amp;lt;Detail /&amp;gt;} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style2&quot;&gt;2. 링크에 실제 ID 값 넣어주기 (Movie.js)&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;사용자가 제목을 클릭하면 실제 그 영화의 id를 주소창에 넣어줘야 한다. 백틱을 사용해 주소를 동적으로 만든다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQ_QE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// id가 123이라면 주소는 /movie/123이 된다.

&amp;lt;Link to={`/movie/${id}`}&amp;gt;{title}&amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;10&quot; data-ke-style=&quot;style2&quot;&gt;3. 주소창의 ID 값 추출하기 (Detail.js)&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;이제 상세 페이지에서 주소창에 찍힌 123이라는 값을 읽어와야 한다. 이때 사용하는 Hook이 바로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;useParams&lt;/span&gt; 다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwin4duzk4iSAxUAAAAAHQAAAAAQ_gE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useParams } from &quot;react-router-dom&quot;;

function Detail() {
  const { id } = useParams(); // 주소창의 :id 값을 가져옴
  console.log(id); // &quot;123&quot; 출력
  
  return &amp;lt;h1&amp;gt;Movie ID: {id}&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;blockquote data-path-to-node=&quot;14&quot; data-ke-style=&quot;style3&quot;&gt;❗️const { id } = useParams() 처럼 객체로 감싸는 이유는? useParams가 값을 &quot;객체&quot; 형태로 반환하기 때문이다.&lt;br /&gt;❗️객체로 주는 이유는? 주소창에는 변수가 하나만 있을 수도 있지만, 여러 개가 있을 수도 있기 때문이다.&lt;/blockquote&gt;
&lt;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style2&quot;&gt;비교해보기&lt;/blockquote&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;20&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;20,0,0&quot;&gt;전체로 받기&lt;/b&gt;: const params = useParams() &amp;rarr; params는 { id: &quot;123&quot; } 이라는 덩어리가 된다. 그래서 꺼내 쓸 때 params.id라고 복잡하게 써야 함!&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;구조 분해 할당&lt;/b&gt;: const { id } = useParams() &amp;rarr; 객체 안의 id라는 키(key)를 가진 &lt;b data-index-in-node=&quot;66&quot; data-path-to-node=&quot;20,1,0&quot;&gt;값만 뽑아서&lt;/b&gt; 바로 id라는 변수에 담아줌!&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21&quot;&gt;즉, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;const { id } = useParams()는 &quot;useParams가 준 객체 안에서 'id'만 꺼낼게!&lt;/span&gt;&quot;라는 뜻.&lt;/b&gt;&lt;/p&gt;</description>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/20</guid>
      <comments>https://yong-mi.tistory.com/20#entry20comment</comments>
      <pubDate>Wed, 14 Jan 2026 03:31:08 +0900</pubDate>
    </item>
    <item>
      <title>[React] API 호출 .then() 대신 async-await 처리</title>
      <link>https://yong-mi.tistory.com/19</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;리액트에서 외부 데이터를 가져올 때 보통 fetch를 사용한다&lt;br /&gt;예전에는 .then()을 활용한 체이닝 방식이 많이 쓰였지만&lt;br /&gt;요즘은 가독성과 유지보수 측면에서 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;async/await&lt;/b&gt;&lt;/span&gt; 방식이 사실상 표준처럼 사용된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;then()&lt;/span&gt; vs &lt;span style=&quot;color: #f89009;&quot;&gt;async-await&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style2&quot;&gt;기존 방식&amp;rarr; .then() 체이닝&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;.then()을 계속 이어 붙이다 보면 코드가 점점 길어지고 비동기 흐름을 한눈에 파악하기 어려워진다&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiG1YWU9IWSAxUAAAAAHQAAAAAQmQE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  fetch(`https://yts.mx/api/v2/list_movies.json`)
    .then((response) =&amp;gt; response.json())
    .then((json) =&amp;gt; {
      setMovies(json.data.movies);
      setLoading(false);
    });
}, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;10&quot; data-ke-style=&quot;style2&quot;&gt;개선된 방식&amp;rarr; async-await&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;비동기 로직을 별도의 함수로 분리하여 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b data-index-in-node=&quot;21&quot; data-path-to-node=&quot;11&quot;&gt;동기 코드(위에서 아래로 실행되는 코드)처럼&lt;/b&gt;&lt;/span&gt; 보이게 만든다&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwiG1YWU9IWSAxUAAAAAHQAAAAAQmgE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;import { useEffect, useState } from &quot;react&quot;;

function App() {
  const [loading, setLoading] = useState(true);
  const [movies, setMovies] = useState([]);

  const getMovies = async () =&amp;gt; {
    try {
      const response = await fetch(
        `https://yts.mx/api/v2/list_movies.json?minimum_rating=9&amp;amp;sort_by=year`
      );
      
      // fetch는 HTTP 에러를 자동으로 throw하지 않기 때문에 직접 체크
      if (!response.ok) {
        throw new Error(&quot;서버 응답 오류&quot;);
      }
      
      const json = await response.json();
      setMovies(json.data.movies);
      
    } catch (error) {
      console.error(&quot;데이터 로딩 실패:&quot;, error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() =&amp;gt; {
    getMovies();
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {loading ? &amp;lt;h1&amp;gt;Loading...&amp;lt;/h1&amp;gt; : (
        &amp;lt;ul&amp;gt;
          {movies.map((movie) =&amp;gt; (
            &amp;lt;li key={movie.id}&amp;gt;{movie.title}&amp;lt;/li&amp;gt;
          ))}
        &amp;lt;/ul&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 비동기인데 왜 await로 기다릴까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-end=&quot;1825&quot; data-start=&quot;1776&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1825&quot; data-start=&quot;1778&quot; data-ke-size=&quot;size16&quot;&gt;비동기를 공부하다 보면 이런 의문이 생긴다&lt;br /&gt;&amp;ldquo;비동기는 안 기다리는 거라면서 왜 await(기다리다)를 쓰는 걸까?&amp;rdquo;&lt;br /&gt;핵심은 '어디가 멈추느냐'의 차이다&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;17&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;17,0,0&quot;&gt;전체(브라우저)는 멈추지 않는다 (비동기)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getMovies 함수가 데이터를 가져오는 동안, 리액트의 다른 기능이나 브라우저의 스크롤, 클릭 이벤트는 &lt;b data-index-in-node=&quot;60&quot; data-path-to-node=&quot;17,0,1,0,0&quot;&gt;멈추지 않고 정상 작동한다&lt;/b&gt;. 이것이 비동기 처리의 본질인 'Non-blocking'이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;함수 내부에서는 순서가 필요하다 (await)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하지만 getMovies라는 &lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;17,1,1,0,0&quot;&gt;함수 내부&lt;/b&gt;에서는 이야기가 다르다. 서버에서 응답(response)이 와야 JSON으로 변환을 하고, 변환이 완료되어야 State를 업데이트할 수 있다.&lt;/li&gt;
&lt;li&gt;await는 &quot;비동기 작업이 완료될 때까지 '이 함수 안에서만' 잠깐 기다려줘&quot;라고 명령하는 것.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-path-to-node=&quot;18&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;18,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0&quot;&gt;  정리하자면:&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;비동기 처리는 사용자가 느끼는 웹사이트 전체의 흐름을 멈추지 않게 하기 위해 사용&lt;/span&gt;하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;await&lt;/span&gt;는 &lt;b data-index-in-node=&quot;66&quot; data-path-to-node=&quot;18,0&quot;&gt;개발자가 의도한 로직의 순서&lt;/b&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;함수 내부에서 보장받기 위해&lt;/span&gt; 사용한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;20&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&amp;nbsp;async-await 사용 시 주의할 점&lt;/b&gt;&amp;nbsp;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;async 함수는 항상 Promise를 반환한다&lt;br /&gt;그래서 useEffect의 첫 번째 인자로 직접 async () =&amp;gt; {}를 넣을 수 없다.&lt;br /&gt;(별도 함수를 만들어 호출해야 함)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768235648039&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ❌ 잘못된 예
useEffect(async () =&amp;gt; {
  ...
}, []);


//   대신 비동기 함수를 선언한 뒤 호출
useEffect(() =&amp;gt; {
  getMovies();
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;초기값 설정&lt;br /&gt;movies.map을 사용한다면 초기 상태값을 useState([])처럼 빈 배열로 설정해야 된다&lt;br /&gt;데이터가 오기 전 undefined 에러를 방지할 수 있음 (즉 초기 상태값은 반드시 맞는 타입으로 설정한다)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768235738930&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [movies, setMovies] = useState([]);&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;에러 처리&amp;nbsp;&lt;br /&gt;.catch() 대신 &amp;rarr; try...catch문이 의미파악과 디버깅에 훨씬 유리할뿐만 아니라 예외 처리가 훨씬 직관적이다&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-path-to-node=&quot;23&quot; data-ke-style=&quot;style2&quot;&gt;정리&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;async/await는 비동기 코드를 &lt;b&gt;동기 코드처럼 작성할 수 있게 해주는 자바스크립트의 강력한 문법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;이제 복잡한 .then() 체이닝 대신 가독성 좋은 async/await 패턴에 익숙해지면 React에서의 데이터 처리 흐름이 훨씬 명확해진다.&lt;/p&gt;</description>
      <category>프론트엔드/React</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/19</guid>
      <comments>https://yong-mi.tistory.com/19#entry19comment</comments>
      <pubDate>Tue, 13 Jan 2026 02:01:17 +0900</pubDate>
    </item>
    <item>
      <title>[React] useState 상태 업데이트와 배열에서 특정 항목 삭제하기</title>
      <link>https://yong-mi.tistory.com/18</link>
      <description>&lt;blockquote data-path-to-node=&quot;2&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;useState 상태 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;업데이트&lt;/b&gt;&lt;/span&gt;의 두 가지&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style2&quot;&gt;1. 단순 값 전달 (Direct Update)&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;상태를 특정 값으로 완전히 대체하고 싶을 때&lt;/span&gt; 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767865487933&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTodo(&quot;&quot;);

// 단순 값 전달 
// 입력이 끝난 후 input 상태를 빈 문자열로 초기화&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;6&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;6,1,0&quot;&gt;동작 원리:&lt;/b&gt; 이전 상태값과 관계없이, 인자로 전달된 새로운 값을 즉시 상태로 반영&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0&quot;&gt;주요 용도:&lt;/b&gt; 입력 필드 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;초기화&lt;/b&gt;&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;6,2,1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;모달창 열기/닫기 (Boolean 값 변경)&lt;/li&gt;
&lt;li&gt;데이터 로딩 상태(Loading/Success/Error) 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style2&quot;&gt;2. 함수형 업데이트 (Functional Update)&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;이전 상태를 기반으로 새로운 상태를 생성&lt;/span&gt;할 때 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767865640165&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTodos((prev) =&amp;gt; [todo, ...prev]);

// 함수형 업데이트
// 최신 상태인 prev 배열을 가져와서 새 항목을 결합&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,1,0&quot;&gt;동작 원리:&lt;/b&gt; set 함수의 인자로 콜백 함수를 전달. 이때 리액트는 콜백 함수의 &lt;b&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;첫 번째 인자로 가장 최신의 상태값(State)&lt;/span&gt;&lt;/b&gt;을 주입&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;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;9,2,1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기존 배열에 새로운 항목을 추가할 때 (To-do 리스트 등)&lt;/li&gt;
&lt;li&gt;이전 숫자 값에 특정 연산을 수행할 때 (Counter 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,3,0&quot;&gt;사용 이유:&lt;/b&gt; 비동기 업데이트 상황에서도 데이터가 꼬이지 않도록 최신 상태값을 안전하게 참조하기 위해 사용&lt;/li&gt;
&lt;/ol&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjHi8XO3faRAxUAAAAAHQAAAAAQ5AU&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;13&quot; data-ke-style=&quot;style2&quot;&gt;✅ 요약 비교&lt;/blockquote&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;14&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0,0&quot;&gt;단순 값 전달&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,1,0&quot;&gt;set(value)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,2,0&quot;&gt;이전 상태를 참조하지 않고 값을 변경&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,2,0,0&quot;&gt;함수형 업데이트&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,1,0&quot;&gt;set((prev) =&amp;gt; newValue)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,2,0&quot;&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;hr data-path-to-node=&quot;15&quot; data-ke-style=&quot;style1&quot; /&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;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;배열에서 특정 항목 삭제하기&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;5&quot; data-ke-style=&quot;style2&quot;&gt;상태가 배열일 때, 특정 항목만 제외한&amp;nbsp;새로운 배열을 만들어 업데이트하는 패턴을 사용하는데 &lt;br /&gt;&lt;b data-index-in-node=&quot;45&quot; data-path-to-node=&quot;5&quot;&gt;filter&lt;/b&gt; 메서드를 활용해 깔끔하게 구현할 수 있다&lt;/blockquote&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjHi8XO3faRAxUAAAAAHQAAAAAQxwY&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;const deleteBtn = (index) =&amp;gt; {
  // 최신 상태(prev)를 복사하거나 직접 수정하지 않고 조건에 맞는 항목만 골라서 새로운 배열로 업데이트
  
  setTodos((prev) =&amp;gt; prev.filter((_, itemIndex) =&amp;gt; index !== itemIndex));
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5&quot;&gt;동작 원리:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;6&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;6,0,0&quot;&gt;filter &lt;/b&gt;: 클릭한 번호(index)와 일치하지 않는 항목들만 모아서 새로운 배열을 생성&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;_ (언더바)&lt;/b&gt;: filter의 첫 번째 인자인 '값'은 사용하지 않고, 두 번째 인자인 '인덱스'만 사용하겠다는 자바스크립트 관례&lt;/li&gt;
&lt;/ol&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7&quot;&gt;사용 이유:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리액트의 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;상태는 원본을 직접 수정하면 안 되기 때문에, filter처럼 새로운 배열을 반환하는 메서드를 사용해 안전하게 상태를 교체&lt;/span&gt;함&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;전체 코드&lt;/blockquote&gt;
&lt;pre id=&quot;code_1767898534160&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

function App() {
  const [todo, setTodo] = useState(&quot;&quot;); // 입력창(input) 텍스트 수정 함수
  const [todos, setTodos] = useState([]); // 할 일 목록 배열(todos) 수정 함수
  const onChange = (e) =&amp;gt; setTodo(e.target.value);

  const onSubmit = (e) =&amp;gt; {
    e.preventDefault();
    if (todo === &quot;&quot;) {
      return;
    }
    setTodos((perv) =&amp;gt; [todo, ...perv]);
    setTodo(&quot;&quot;);
  };

  /** 
   * 삭제 버튼
   * setTodos를 사용하여 전체 목록 업데이트
   * filter를 사용하여 클릭한 index와 일치하지 않는 요소들만 남김
   */
  const deleteBtn = (index) =&amp;gt; {
    setTodos((prev) =&amp;gt; prev.filter((_, itemIndex) =&amp;gt; index !== itemIndex));
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;My To Dos {todos.length}&amp;lt;/h1&amp;gt;

      &amp;lt;form onSubmit={onSubmit}&amp;gt;
        &amp;lt;input
          type=&quot;text&quot;
          placeholder=&quot;Write your to do..&quot;
          onChange={onChange}
          value={todo}
        /&amp;gt;
        &amp;lt;button&amp;gt;Add To Do&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
      &amp;lt;hr /&amp;gt;
      &amp;lt;ul&amp;gt;
        {todos.map((item, index) =&amp;gt; (
          &amp;lt;li key={index}&amp;gt;
            {item} &amp;lt;button onClick={() =&amp;gt; deleteBtn(index)}&amp;gt;삭제&amp;lt;/button&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프론트엔드/React</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/18</guid>
      <comments>https://yong-mi.tistory.com/18#entry18comment</comments>
      <pubDate>Fri, 9 Jan 2026 03:56:41 +0900</pubDate>
    </item>
    <item>
      <title>[React] useEffect() 와 Cleanup 함수</title>
      <link>https://yong-mi.tistory.com/17</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;useEffect란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;blockquote data-path-to-node=&quot;4&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;실행 시점을 내 마음대로 결정하게 해주는 함수&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot; data-path-to-node=&quot;3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;리액트 컴포넌트는 state가 변할 때마다 전체 코드가 다시 실행(Re-render)되는 특징&lt;/span&gt;이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot; data-path-to-node=&quot;3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;하지만 서버에서 데이터를 받아오는&amp;nbsp;API 호출처럼&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot; data-path-to-node=&quot;3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;딱 한 번만 실행되어야 하거나, 특정 값이 변할 때만 실행되어야 하는 코드가 있다면?&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot; data-path-to-node=&quot;3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333;&quot;&gt;이걸 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;내 마음대로 제어할 수 있게 해주는 게 바로&amp;nbsp;&lt;b data-path-to-node=&quot;4&quot; data-index-in-node=&quot;171&quot;&gt;useEffect&lt;/b&gt;&lt;/span&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre id=&quot;code_1767783834961&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  // 1. 실행하고 싶은 코드 (첫 번째 인자)
}, [/* 2. 지켜볼 대상들 */]); // (두 번째 인자)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;첫 번째 인자:&amp;nbsp;실행하고 싶은 코드(함수)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;두 번째 인자:&amp;nbsp;리액트가 지켜볼 대상이 담긴 배열 (의존성 배열, [])&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;5&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;useEffect는 'Side Effect'를 위한 Hook이다&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리액트에서 Side effect(부작용, 영향)란 렌더링 결과물과는 직접적인 상관이 없지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컴포넌트 외부와 상호작용하는 작업들을 말한다&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;예시: 서버에서 데이터 받아오기(API), 수동으로 DOM 조작하기, 타이머 설정 등&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;특징: 이런 작업들은 렌더링이 다 끝난 뒤에 실행되어야 성능에 방해가 안 된다. 그래서 useEffect라는 Hook(훅)을 사용해서 &lt;span style=&quot;color: #ee2323;&quot;&gt;실행 시점을 관리&lt;/span&gt;하는 것.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;blockquote data-path-to-node=&quot;11&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;의존성 배열([])에 따른 마법&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;두 번째 인자인 배열을 어떻게 쓰느냐에 따라 실행 타이밍이 완전히 달라진다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;컴포넌트가 처음 나타날 때 딱 한 번만 실행&lt;/span&gt;하고&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: center;&quot;&gt;그 뒤로는 어떤 일이 생겨도 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;실행하고 싶지 않을 때 두 번째 인자에 빈 배열을 넣어서 사용&lt;/span&gt;하고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;배열 안에 특정 변수를 넣어주면, 리액트가 그 값을 감시하다가 값이 바뀔 때만 코드를 다시 실행&lt;/span&gt;해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&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 data-path-to-node=&quot;13&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;빈 배열일 때 []&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동작: &lt;span style=&quot;color: #ee2323;&quot;&gt;컴포넌트가 처음 화면에 나타날 때(Mount) 딱 한 번만 실행&lt;/span&gt;하고 다시는 안 함.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;용도: API 딱 한 번만 호출하고 싶을 때 사용. 리액트한테 &quot;지켜볼 게 아무것도 없으니까 처음 말고는 다시 실행하지 마&quot;라고 알려주는 것.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-path-to-node=&quot;15&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;특정 값이 있을 때 [keyword]&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;동작: &lt;span style=&quot;color: #ee2323;&quot;&gt;처음 나타날 때 + 값이 바뀔 때&lt;/span&gt;마다 실행.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;용도:&amp;nbsp;특정 데이터가 변할 때마다 반응해야 하는 로직에 사용.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;blockquote data-path-to-node=&quot;13&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;코드&lt;/span&gt;&lt;/blockquote&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjHi8XO3faRAxUAAAAAHQAAAAAQyAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useState, useEffect } from &quot;react&quot;;

function App() {
  const [counter, setCounter] = useState(0);
  const [keyword, setKeyword] = useState(&quot;&quot;);

  const onClick = () =&amp;gt; setCounter((prev) =&amp;gt; prev + 1);
  const onChange = (e) =&amp;gt; setKeyword(e.target.value);

  // 1. 처음 렌더링될 때 딱 한 번만 실행
  useEffect(() =&amp;gt; {
    console.log(&quot;나는 한번만 실행돼요.&quot;);
  }, []);

  // 2. keyword가 변화할 때만 실행
  useEffect(() =&amp;gt; {
    console.log(`나는 ${keyword} 가 변화할 때 실행돼요.`);
  }, [keyword]);

  // 3. counter가 변화할 때만 실행
  useEffect(() =&amp;gt; {
    console.log(`나는 ${counter} 가 변화할 때 실행돼요.`);
  }, [counter]);

  // 4. 둘 중 하나라도 변화하면 실행
  useEffect(() =&amp;gt; {
    console.log(`나는 ${counter}, ${keyword} 둘 다 변화할 때 실행돼요.`);
  }, [counter, keyword]);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input type=&quot;text&quot; placeholder=&quot;Search here...&quot; value={keyword} onChange={onChange} /&amp;gt;
      &amp;lt;h1&amp;gt;{counter}&amp;lt;/h1&amp;gt;
      &amp;lt;button onClick={onClick}&amp;gt;click me&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; color: #333333; text-align: left;&quot;&gt;useEffect &lt;/span&gt;정리&lt;/span&gt;&lt;/blockquote&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;17&quot; data-ke-align=&quot;alignCenter&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;의존성 배열&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;실행 타이밍&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0,0&quot;&gt;빈 배열 []&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,1,1,0&quot;&gt;컴포넌트가 처음 나타날 때(Mount) &lt;b data-index-in-node=&quot;22&quot; data-path-to-node=&quot;17,1,1,0&quot;&gt;딱 한 번&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,2,0,0&quot;&gt;값이 있는 배열 [a]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,2,1,0&quot;&gt;처음 나타날 때 + &lt;b data-index-in-node=&quot;11&quot; data-path-to-node=&quot;17,2,1,0&quot;&gt;a가 변할 때마다&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,3,0,0&quot;&gt;여러 개 있는 배열 [a, b]&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot; data-path-to-node=&quot;17,3,1,0&quot;&gt;처음 나타날 때 + &lt;b data-index-in-node=&quot;11&quot; data-path-to-node=&quot;17,3,1,0&quot;&gt;a 혹은 b가 변할 때마다&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: left;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;useEffect는 무분별한 코드 실행을 막아주는 방어막이자, 내가 원하는 시점을 정확히 조준하는 트리거다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;text-align: left;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;Cleanup&amp;nbsp;함수란?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;useEffect는 컴포넌트가 처음 나타날 때 코드를 실행할 수 있게 해주지만&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;반대로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b data-index-in-node=&quot;49&quot; data-path-to-node=&quot;3&quot;&gt;컴포넌트가 화면에서 사라질 때(Destroy/Unmount)&lt;/b&gt; 코드를 실행하는 방법&lt;/span&gt;도 제공한다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이걸 &lt;b data-index-in-node=&quot;104&quot; data-path-to-node=&quot;3&quot;&gt;Cleanup 함수&lt;/b&gt;라고 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;Cleanup 함수는&amp;nbsp;&lt;/span&gt;useEffect 안에서 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;5&quot;&gt;함수를 return&lt;/b&gt; 하면, 그 리턴된 함수는 컴포넌트가 파괴될 때 실행된다&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;아래 두 코드는 같다&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjHi8XO3faRAxUAAAAAHQAAAAAQ5AQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// 1
function Hello() {
  useEffect(() =&amp;gt; {
    console.log(&quot;created :)&quot;); // 컴포넌트가 나타날 때 실행
    
    return () =&amp;gt; console.log(&quot;destroyed :(&quot;); // 컴포넌트가 사라질 때 실행 (Cleanup)
  }, []);

  return &amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;;
}

// 2
function Hello() {
  function byFn(){
    console.log(&quot;destroyed&quot;);
  }
  function hiFn(){
    console.log(&quot;created&quot;);
    return byFn;
  }
  useEffect(hiFn, []);

  return &amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;blockquote data-path-to-node=&quot;7&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 작동 원리: 왜 return을 할까?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리액트의 이펙트 라이프사이클은 아래와 같이 흘러간다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;리렌더링/생성: 컴포넌트가 화면에 그려짐.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이펙트 실행: useEffect의 첫 번째 인자인 함수가 실행됨.클린업: 다음 이펙트가 실행되기 전이나, 컴포넌트가 파괴될 때 이전에 return 했던 함수를 실행해서 청소함.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;blockquote data-path-to-node=&quot;11&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 두 코드는 왜 결과가 같을까?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;두 코드는 작성 방식만 다를 뿐, 자바스크립트의 함수 리턴 원리를 이용한 같은 로직&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;첫 번째: 익명 함수를 바로 리턴함. (가장 흔히 쓰는 방식)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;두 번째: hiFn을 실행하면 byFn이라는 함수 자체를 결과값으로 리턴함.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;결국 리액트 입장에서는 어쨌든 나한테 함수 하나를 리턴해줬네? 그럼 나중에 파괴될 때 이거 실행해 줄게! 가 되는 것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;15&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;4. 언제 사용할까?&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;컴포넌트가 사라지는데 왜 코드를 실행해야 할까? &lt;span style=&quot;background-color: #f6e199;&quot;&gt;보통 '정리'가 필요할 때 쓴다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;타이머 제거: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;setTimeout이나 setInterval을 켰다면 사라질 때 꺼줘야 메모리 낭비가 없다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이벤트 리스너 해제:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;윈도우 스크롤 감지 같은 걸 등록했다면 사라질 때 지워줘야 한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;API 요청 취소: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터를 가져오다가 컴포넌트가 닫히면 더 이상 필요 없는 요청을 취소할 때 쓴다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style2&quot;&gt;Cleanup 정리&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;Cleanup 함수&lt;/b&gt;: useEffect 안에서 return 하는 함수.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;실행 시점&lt;/b&gt;: 컴포넌트가 파괴(Unmount)될 때, 혹은 다음 이펙트가 실행되기 직전에 실행됨.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,2,0&quot;&gt;의존성 배열이 []일 때&lt;/b&gt;: 컴포넌트가 아예 사라질 때 딱 한 번 실행됨.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>프론트엔드/React</category>
      <category>cleanup</category>
      <category>useEffect</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/17</guid>
      <comments>https://yong-mi.tistory.com/17#entry17comment</comments>
      <pubDate>Wed, 7 Jan 2026 20:10:51 +0900</pubDate>
    </item>
    <item>
      <title>[React] CSS Module 사용 이유와 사용 방법</title>
      <link>https://yong-mi.tistory.com/16</link>
      <description>&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;A 컴포넌트의 스타일이 이름이 같다는 이유로 B 컴포넌트까지 망가뜨리는 상황이다.&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;클래스 중복 문제를 해결하기&amp;nbsp;위해 등장한 것이 바로 &lt;/span&gt;&lt;b data-index-in-node=&quot;122&quot; data-path-to-node=&quot;3&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;CSS Module&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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-01-06 오후 7.52.29.png&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qHcWr/dJMcafFhXF9/f5vgKIYsT8GMzd3BpvLPw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qHcWr/dJMcafFhXF9/f5vgKIYsT8GMzd3BpvLPw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qHcWr/dJMcafFhXF9/f5vgKIYsT8GMzd3BpvLPw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqHcWr%2FdJMcafFhXF9%2Ff5vgKIYsT8GMzd3BpvLPw1%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;1047&quot; height=&quot;449&quot; data-filename=&quot;스크린샷 2026-01-06 오후 7.52.29.png&quot; data-origin-width=&quot;1047&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-01-06 오후 7.53.01.png&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEyxq3/dJMcac9z7wZ/0Hjad4WOf9PuCLMCAWwc8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEyxq3/dJMcac9z7wZ/0Hjad4WOf9PuCLMCAWwc8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEyxq3/dJMcac9z7wZ/0Hjad4WOf9PuCLMCAWwc8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEyxq3%2FdJMcac9z7wZ%2F0Hjad4WOf9PuCLMCAWwc8k%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;939&quot; height=&quot;233&quot; data-filename=&quot;스크린샷 2026-01-06 오후 7.53.01.png&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&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;blockquote data-path-to-node=&quot;6&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;컴포넌트 단위의 스타일 격리&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;일반 CSS는 파일이 달라도 클래스명이 같으면 전역적으로 적용되지만, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;CSS Module은 해당 컴포넌트 안에서만 유효&lt;/span&gt;&lt;/b&gt;하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;8&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;6,0,0&quot;&gt;사용법:&lt;/b&gt; .css 대신 .module.css 확장자로 생성&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;장점:&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;스타일을 '객체(Object)'로 다루는 방식&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;기존 CSS가 HTML에 클래스명을 &quot;문자열&quot;로 적어넣는 방식이었다면, CSS Module은 스타일을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b data-index-in-node=&quot;57&quot; data-path-to-node=&quot;8&quot;&gt;자바스크립트 객체&lt;/b&gt;&lt;/span&gt;로 취급한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;import:&lt;/b&gt; import styles from &quot;./Button.module.css&quot;&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;적용:&lt;/b&gt; className={styles.title}&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; 이제 스타일은 단순히 이름을 찾는 게 아니라, 특정 JSX 엘리먼트에 직접 주입하는 데이터가 된다. 오타가 나도 자바스크립트가 체크해주니 훨씬 안전함.&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;12&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;클래스 이름 중복 해결&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;스크린샷의 개발자 도구를 보면 CSS Module의 진가가 드러남!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;12,0,0&quot; data-index-in-node=&quot;0&quot;&gt;상황:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;App과 Button 두 파일 모두 똑같이 .title이라는 클래스명을 사용했다.&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;12,1,0&quot; data-index-in-node=&quot;0&quot;&gt;결과:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;리액트 빌드 시 App_title__YS7Xx, Button_title__1rPP- 처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;12,1,0&quot; data-index-in-node=&quot;54&quot;&gt;고유한 해시값&lt;/b&gt;이 붙는다.&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;12,2,0&quot; data-index-in-node=&quot;0&quot;&gt;효과:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;개발자는 클래스명이 겹칠까 봐 이름을 길게 지을 필요가 없다. .title이라고만 지어도 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;리액트가 중복되지 않게 관리&lt;/span&gt;&lt;/b&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 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-path-to-node=&quot;17&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;✅ 요약&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;19,0&quot; data-ke-size=&quot;size16&quot;&gt;CSS Module은 클래스명 충돌을 원천 차단하고, 스타일을 컴포넌트에 종속된 객체로 관리하게 함으로써 '독립적인 컴포넌트'를 완성해준다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-path-to-node=&quot;18,0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프론트엔드/React</category>
      <category>CSS</category>
      <category>module</category>
      <category>React</category>
      <author>OI7MI</author>
      <guid isPermaLink="true">https://yong-mi.tistory.com/16</guid>
      <comments>https://yong-mi.tistory.com/16#entry16comment</comments>
      <pubDate>Tue, 6 Jan 2026 20:21:43 +0900</pubDate>
    </item>
  </channel>
</rss>