<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>React on Korobopolly's Dev Blog</title><link>https://korobopolly.github.io/tags/react/</link><description>Recent content in React on Korobopolly's Dev Blog</description><generator>Hugo</generator><language>ko</language><lastBuildDate>Mon, 16 Feb 2026 13:21:00 +0900</lastBuildDate><atom:link href="https://korobopolly.github.io/tags/react/index.xml" rel="self" type="application/rss+xml"/><item><title>React E2E 테스트 - Playwright 설정, Locator, 네트워크 모킹, CI 통합</title><link>https://korobopolly.github.io/posts/react-e2e-testing/</link><pubDate>Mon, 16 Feb 2026 13:21:00 +0900</pubDate><guid>https://korobopolly.github.io/posts/react-e2e-testing/</guid><description>&lt;p&gt;E2E 테스트는 실제 사용자 관점에서 애플리케이션을 검증합니다. 이번 글에서는 Playwright를 활용한 React 애플리케이션 E2E 테스트 작성법을 알아봅니다.&lt;/p&gt;
&lt;h2 id="e2e-테스트란"&gt;E2E 테스트란&lt;/h2&gt;
&lt;h3 id="테스트-피라미드"&gt;테스트 피라미드&lt;/h3&gt;
&lt;p&gt;소프트웨어 테스트는 세 가지 레벨로 나뉩니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /\
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / \ E2E 테스트 (적음, 느림, 비용 높음)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /____\
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / \ 통합 테스트 (중간)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /________\
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / \ 단위 테스트 (많음, 빠름, 비용 낮음)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /____________\
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;단위 테스트 (Unit Test):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;개별 함수, 컴포넌트 테스트&lt;/li&gt;
&lt;li&gt;빠르고 격리된 환경&lt;/li&gt;
&lt;li&gt;예: &lt;code&gt;sum(1, 2) === 3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;통합 테스트 (Integration Test):&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>React 상태 관리 - Context API, Provider 패턴, Redux vs Zustand 비교</title><link>https://korobopolly.github.io/posts/react-state-management/</link><pubDate>Mon, 16 Feb 2026 13:20:00 +0900</pubDate><guid>https://korobopolly.github.io/posts/react-state-management/</guid><description>&lt;p&gt;Props drilling 문제를 겪어보신 적 있나요? 컴포넌트가 깊어질수록 상태를 여러 단계에 걸쳐 전달해야 하는 문제가 발생합니다. 이번 글에서는 전역 상태 관리 아키텍처 패턴과 실전 Context 조합 전략, 그리고 프로젝트 규모에 맞는 상태 관리 솔루션 선택 방법을 알아봅니다.&lt;/p&gt;
&lt;h2 id="상태-관리의-필요성"&gt;상태 관리의 필요성&lt;/h2&gt;
&lt;h3 id="props-drilling-문제"&gt;Props Drilling 문제&lt;/h3&gt;
&lt;p&gt;중간 컴포넌트들이 실제로 사용하지 않는 props를 단순히 아래로 전달만 하는 상황입니다.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;// Props Drilling 예시
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; App() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [user, setUser] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState(&lt;span style="color:#fab387"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;Layout&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;user&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{user} &lt;span style="color:#89b4fa"&gt;setUser&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{setUser} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; Layout({ user, setUser }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;Header&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;user&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{user} &lt;span style="color:#89b4fa"&gt;setUser&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{setUser} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;Main&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;user&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{user} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#cba6f7"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; Header({ user, setUser }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;UserMenu&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;user&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{user} &lt;span style="color:#89b4fa"&gt;setUser&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{setUser} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; UserMenu({ user, setUser }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// 실제로 사용하는 곳은 여기
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; user &lt;span style="color:#89dceb;font-weight:bold"&gt;?&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;onClick&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{() =&amp;gt; setUser(&lt;span style="color:#fab387"&gt;null&lt;/span&gt;)}&amp;gt;로그아웃&amp;lt;/&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) &lt;span style="color:#89dceb;font-weight:bold"&gt;:&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;onClick&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{() =&amp;gt; setUser({ name&lt;span style="color:#89dceb;font-weight:bold"&gt;:&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#39;홍길동&amp;#39;&lt;/span&gt; })}&amp;gt;로그인&amp;lt;/&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;중간 컴포넌트들은 &lt;code&gt;user&lt;/code&gt;와 &lt;code&gt;setUser&lt;/code&gt;를 직접 사용하지 않지만 전달만 하고 있습니다. 이것이 Props Drilling 문제입니다.&lt;/p&gt;</description></item><item><title>React Hooks 심화 - useEffect, useMemo, useReducer, 커스텀 Hook</title><link>https://korobopolly.github.io/posts/react-hooks/</link><pubDate>Mon, 16 Feb 2026 13:15:00 +0900</pubDate><guid>https://korobopolly.github.io/posts/react-hooks/</guid><description>&lt;h2 id="react-hooks란"&gt;React Hooks란?&lt;/h2&gt;
&lt;p&gt;Hooks는 함수형 컴포넌트에서 상태 관리, 사이드 이펙트 처리, 성능 최적화 등을 가능하게 하는 함수입니다. React 16.8에서 도입되어 현재 React 개발의 핵심이 되었습니다.&lt;/p&gt;
&lt;h3 id="hooks-규칙"&gt;Hooks 규칙&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;최상위에서만 호출&lt;/strong&gt;: 조건문, 반복문, 중첩 함수 내에서 호출 금지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React 함수 내에서만 호출&lt;/strong&gt;: 일반 JavaScript 함수에서 호출 금지&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-tsx" data-lang="tsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;// 잘못된 사용
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; BadExample() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;if&lt;/span&gt; (someCondition) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [value, setValue] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState(&lt;span style="color:#a6e3a1"&gt;&amp;#34;&amp;#34;&lt;/span&gt;); &lt;span style="color:#6c7086;font-style:italic"&gt;// 조건문 안에서 호출 금지
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;// 올바른 사용
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; GoodExample() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [value, setValue] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState(&lt;span style="color:#a6e3a1"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;if&lt;/span&gt; (someCondition) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// Hook이 아닌 로직은 조건문 안에서 사용 가능
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="useeffect---사이드-이펙트-처리"&gt;useEffect - 사이드 이펙트 처리&lt;/h2&gt;
&lt;h3 id="기본-사용법"&gt;기본 사용법&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-tsx" data-lang="tsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#cba6f7"&gt;import&lt;/span&gt; { useState, useEffect } &lt;span style="color:#cba6f7"&gt;from&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; UserProfile({ userId }&lt;span style="color:#89dceb;font-weight:bold"&gt;:&lt;/span&gt; { userId: &lt;span style="color:#f38ba8"&gt;number&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [user, setUser] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState&amp;lt;&lt;span style="color:#cba6f7"&gt;User&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;|&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;null&lt;/span&gt;&amp;gt;(&lt;span style="color:#fab387"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [loading, setLoading] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState(&lt;span style="color:#fab387"&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; useEffect(() &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// 사이드 이펙트 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; setLoading(&lt;span style="color:#fab387"&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fetch(&lt;span style="color:#a6e3a1"&gt;`/api/users/&lt;/span&gt;&lt;span style="color:#a6e3a1"&gt;${&lt;/span&gt;userId&lt;span style="color:#a6e3a1"&gt;}&lt;/span&gt;&lt;span style="color:#a6e3a1"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .then((res) &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; res.json())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .then((data) &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; setUser(data);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; setLoading(&lt;span style="color:#fab387"&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [userId]); &lt;span style="color:#6c7086;font-style:italic"&gt;// userId가 변경될 때만 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;if&lt;/span&gt; (loading) &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;&lt;span style="color:#f38ba8"&gt;로딩&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;중&lt;/span&gt;...&amp;lt;/&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;if&lt;/span&gt; (&lt;span style="color:#89dceb;font-weight:bold"&gt;!&lt;/span&gt;user) &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;&lt;span style="color:#f38ba8"&gt;사용자를&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;찾을&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;수&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;없습니다&lt;/span&gt;.&amp;lt;/&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;h2&lt;/span&gt;&amp;gt;{user.name}&amp;lt;/&lt;span style="color:#cba6f7"&gt;h2&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;{user.email}&amp;lt;/&lt;span style="color:#cba6f7"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#cba6f7"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="의존성-배열-패턴"&gt;의존성 배열 패턴&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-tsx" data-lang="tsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;function&lt;/span&gt; EffectPatterns() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;const&lt;/span&gt; [count, setCount] &lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt; useState(&lt;span style="color:#fab387"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// 1. 마운트 시 1회만 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; useEffect(() &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&lt;span style="color:#a6e3a1"&gt;&amp;#34;컴포넌트 마운트&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// 2. 특정 값 변경 시 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; useEffect(() &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&lt;span style="color:#a6e3a1"&gt;&amp;#34;count 변경:&amp;#34;&lt;/span&gt;, count);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [count]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#6c7086;font-style:italic"&gt;// 3. 매 렌더링마다 실행 (의존성 배열 생략)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; useEffect(() &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console.log(&lt;span style="color:#a6e3a1"&gt;&amp;#34;렌더링됨&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#cba6f7"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt; &lt;span style="color:#89b4fa"&gt;onClick&lt;/span&gt;&lt;span style="color:#89dceb;font-weight:bold"&gt;=&lt;/span&gt;{() &lt;span style="color:#89dceb;font-weight:bold"&gt;=&amp;gt;&lt;/span&gt; setCount(count &lt;span style="color:#89dceb;font-weight:bold"&gt;+&lt;/span&gt; &lt;span style="color:#fab387"&gt;1&lt;/span&gt;)}&amp;gt;{count}&amp;lt;/&lt;span style="color:#cba6f7"&gt;button&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="클린업-함수"&gt;클린업 함수&lt;/h3&gt;
&lt;p&gt;컴포넌트 언마운트 시 또는 이펙트 재실행 전에 정리 작업을 수행합니다.&lt;/p&gt;</description></item><item><title>React 시작하기 - JSX, 컴포넌트, Props, State, 이벤트 처리</title><link>https://korobopolly.github.io/posts/react-introduction/</link><pubDate>Mon, 16 Feb 2026 13:14:00 +0900</pubDate><guid>https://korobopolly.github.io/posts/react-introduction/</guid><description>&lt;h2 id="react란"&gt;React란?&lt;/h2&gt;
&lt;p&gt;React는 Meta(구 Facebook)에서 개발한 UI 라이브러리입니다. &lt;strong&gt;컴포넌트 기반 아키텍처&lt;/strong&gt;로 복잡한 UI를 독립적이고 재사용 가능한 조각으로 나누어 개발할 수 있습니다.&lt;/p&gt;
&lt;h3 id="react의-핵심-특징"&gt;React의 핵심 특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;컴포넌트 기반&lt;/strong&gt;: UI를 독립적인 컴포넌트로 분리하여 관리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;선언적 UI&lt;/strong&gt;: 상태에 따라 UI가 자동으로 업데이트&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virtual DOM&lt;/strong&gt;: 효율적인 렌더링으로 성능 최적화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단방향 데이터 흐름&lt;/strong&gt;: 예측 가능한 데이터 관리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;풍부한 생태계&lt;/strong&gt;: Next.js, React Native 등 확장 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="프로젝트-생성"&gt;프로젝트 생성&lt;/h2&gt;
&lt;h3 id="vite로-react-프로젝트-생성"&gt;Vite로 React 프로젝트 생성&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;# Vite로 React + TypeScript 프로젝트 생성&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm create vite@latest my-react-app -- --template react-ts
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;# 프로젝트 디렉토리로 이동&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#89dceb"&gt;cd&lt;/span&gt; my-react-app
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;# 의존성 설치&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#6c7086;font-style:italic"&gt;# 개발 서버 시작&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="프로젝트-구조"&gt;프로젝트 구조&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;my-react-app/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── public/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── vite.svg
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── src/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── assets/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── App.tsx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── App.css
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ ├── main.tsx
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ └── index.css
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── package.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├── tsconfig.json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└── vite.config.ts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;핵심 파일 설명&lt;/strong&gt;:&lt;/p&gt;</description></item></channel></rss>