<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>FE_Jay</title>
        <link>https://velog.io/</link>
        <description>백엔드 개발자에서 프론드엔드 개발자로</description>
        <lastBuildDate>Tue, 31 Dec 2024 14:25:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>FE_Jay</title>
            <url>https://velog.velcdn.com/images/injung_p/profile/6f74fb69-3c43-4588-94b0-bf03aea4cf6b/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. FE_Jay. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/injung_p" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[백엔드에서 프론트엔드로, 새로운 도전과 성장의 여정]]></title>
            <link>https://velog.io/@injung_p/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-%EC%B6%9C%EC%8B%A0-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%97%90%EC%84%9C-%ED%94%84%EB%A1%A0%EB%93%9C%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C-%EC%A0%84%ED%96%A5%ED%95%9C-%EA%B2%BD%ED%97%98</link>
            <guid>https://velog.io/@injung_p/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-%EC%B6%9C%EC%8B%A0-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%97%90%EC%84%9C-%ED%94%84%EB%A1%A0%EB%93%9C%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C-%EC%A0%84%ED%96%A5%ED%95%9C-%EA%B2%BD%ED%97%98</guid>
            <pubDate>Tue, 31 Dec 2024 14:25:18 GMT</pubDate>
            <description><![CDATA[<h2 id="2024년-개발자-회고록">2024년 개발자 회고록</h2>
<p>2024년은 제게 있어 개발자로서의 새로운 길을 열었던 한 해였습니다. 백엔드 개발자로 시작했던 제가 프론트엔드 개발로 전향하며 겪었던 어려움, 배움, 그리고 성장을 돌아보며 이 글을 통해 제 경험을 공유하고자 합니다. </p>
<hr>
<h2 id="백엔드에서-프론트엔드로-전향-익숙함을-떠나는-용기"><strong>백엔드에서 프론트엔드로 전향: 익숙함을 떠나는 용기</strong></h2>
<p>백엔드 개발자로서의 경력은 저에게 큰 자신감을 심어주었습니다. 데이터베이스 설계, 서버 로직 구현, API 개발 등 백엔드의 다양한 영역에서 경험을 쌓으며 안정적인 시스템을 구축하는 데 익숙해졌습니다. 하지만 어느 순간, 저는 사용자와 더 가까운 곳에서 더 나은 경험을 제공하는 일에 도전하고 싶다는 생각이 들었습니다. 그래서 프론트엔드라는 새로운 분야에 발을 들이기로 결심했습니다.</p>
<p>처음에는 두려움이 컸습니다. 백엔드와는 전혀 다른 사고방식과 기술 스택을 요구하는 프론트엔드는 낯설었고, HTML, CSS, JavaScript 같은 기초적인 기술조차 생소하게 느껴졌습니다. 하지만 익숙함에 안주하지 않고 새로운 도전을 선택한 제 자신이 자랑스러웠습니다.</p>
<hr>
<h2 id="프론트엔드-기초부터-다시-시작-성장의-가치를-발견하다"><strong>프론트엔드 기초부터 다시 시작: 성장의 가치를 발견하다</strong></h2>
<p>프론트엔드를 배우는 과정은 마치 새로운 언어를 배우는 것과 같았습니다. HTML과 CSS로 화면을 구성하고, JavaScript로 사용자와 상호작용하는 기능을 구현하면서 처음에는 좌절도 많았습니다. 특히 &quot;왜 이렇게 복잡한 걸까?&quot;라는 생각이 들 때도 있었죠.</p>
<p>하지만 기초를 탄탄히 다지며 점점 더 큰 그림이 보이기 시작했습니다. 브라우저가 어떻게 동작하는지 이해하고, DOM 조작과 이벤트 핸들링의 원리를 배우며 사용자 경험(UX)을 고려한 코드를 작성하기 시작했습니다. 이러한 과정에서 저는 단순히 기술을 배우는 것을 넘어, 사용자 중심의 사고방식을 갖추게 되었습니다.</p>
<p>특히 백엔드 경험이 프론트엔드를 배우는 데 큰 도움이 되었습니다. API를 설계했던 경험 덕분에 클라이언트-서버 간의 데이터 흐름을 쉽게 이해할 수 있었고, 이를 바탕으로 효율적인 프론트엔드-백엔드 협업 방식을 고민할 수 있었습니다.</p>
<hr>
<h2 id="백엔드와-프론트를-연결하며-얻은-통합적-사고"><strong>백엔드와 프론트를 연결하며 얻은 통합적 사고</strong></h2>
<p>백엔드와 프론트 모두를 경험하면서 저는 두 영역 간의 연결 고리를 더 깊이 이해하게 되었습니다. 예를 들어, 백엔드에서 데이터를 어떻게 설계하느냐에 따라 프론트에서 데이터를 처리하는 방식이 크게 달라질 수 있다는 점을 알게 되었고, 이를 통해 더 나은 API 설계를 고민하게 되었습니다.</p>
<p>또한 백엔드에서는 주로 성능 최적화와 안정성을 중시했다면, 프론트에서는 사용자 경험과 인터페이스 디자인에 더 많은 신경을 써야 했습니다. 이 두 가지 관점을 모두 고려하며 개발하는 것은 저를 더욱 균형 잡힌 개발자로 성장시켰습니다.</p>
<hr>
<h2 id="리액트를-배우며-더-가치-있는-개발자로-성장하다"><strong>리액트를 배우며 더 가치 있는 개발자로 성장하다</strong></h2>
<p>2024년 후반부에는 리액트를 본격적으로 학습하기 시작했습니다. 컴포넌트 기반 아키텍처와 상태 관리(State Management)는 처음에는 다소 복잡하게 느껴졌지만, 리액트를 통해 재사용 가능한 코드와 효율적인 UI 설계를 배울 수 있었습니다.</p>
<p>특히 리액트를 사용하면서 &quot;사용자가 진정으로 원하는 것은 무엇인가?&quot;라는 질문을 더 자주 던지게 되었습니다. 단순히 기능적인 구현에 그치지 않고, 사용자 입장에서 더 직관적이고 편리한 인터페이스를 제공하려는 노력이 제 코딩 철학에도 녹아들기 시작했습니다.</p>
<p>리액트를 학습하며 저는 단순히 기술적인 성장을 넘어 사용자 중심의 사고방식을 더욱 강화할 수 있었습니다. 이를 통해 제가 만드는 제품이 단순한 코드 덩어리가 아니라, 사람들에게 가치를 전달하는 도구라는 사실을 깨달았습니다.</p>
<hr>
<h2 id="마무리하며-도전은-나를-성장시킨다"><strong>마무리하며: 도전은 나를 성장시킨다</strong></h2>
<p>백엔드에서 프론트엔드로 전향한 2024년은 도전과 배움의 연속이었습니다. 익숙했던 영역에서 벗어나 낯선 분야에 도전하며 좌절도 많았지만, 그만큼 성장도 컸습니다. 이제는 백엔드와 프론트를 아우르는 통합적 사고를 가진 개발자로서 더 넓은 시야를 갖게 되었습니다.</p>
<p>앞으로도 저는 끊임없이 배우고 성장하며 더 나은 개발자가 되고자 합니다. 2025년에는 리액트를 넘어 다양한 프레임워크와 디자인 시스템에 도전해보고 싶습니다. 동시에 저처럼 새로운 분야에 도전하려는 분들에게 제 경험이 작은 용기가 되었으면 좋겠습니다.</p>
<p>&quot;도전은 어렵지만, 그 끝에는 반드시 성장이 기다리고 있다.&quot;<br>2024년 한 해 동안 배운 가장 큰 교훈입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Hook]]></title>
            <link>https://velog.io/@injung_p/React-Hook</link>
            <guid>https://velog.io/@injung_p/React-Hook</guid>
            <pubDate>Sun, 01 Dec 2024 13:53:07 GMT</pubDate>
            <description><![CDATA[<h2 id="react-hook의-기본-동작-원리">React Hook의 기본 동작 원리</h2>
<h3 id="기본-react-hook동작원리-코드">기본 react hook동작원리 코드</h3>
<h4 id="1-usestate는-클로저closure를-활용하여-상태를-관리합니다">1. useState는 클로저(Closure)를 활용하여 상태를 관리합니다.</h4>
<p><em><strong>ex )</strong></em></p>
<blockquote>
<pre><code>export const React = (() =&gt; {
  let hook = [];
  let index = 0;
  function useState(initialValue) {
    const state = hook[index] || initialValue;
    const currentIndex = index;
    const setState = newValue =&gt; {
      hook[currentIndex] = newValue;
    };
    index++;
    return [state, setState];
  }
  function render(component) {
    index = 0;
    const C = component();
    return C;
  }
  return {
    useState,
    render,
  };
})();</code></pre></blockquote>
<h4 id="2-클로저closure를-활용하여-만든-usestate-구현-코드">2. 클로저(Closure)를 활용하여 만든 useState 구현 코드</h4>
<ul>
<li><p>먼저 카운터 컴포넌트를 정의합니다.</p>
<blockquote>
<pre><code>function Counter() {
  const [count, setCount] = React.useState(0);
  return {
      click: () =&gt; setCount(count + 1),
      render: () =&gt; console.log(&#39;count:&#39;, count)
  };
}</code></pre></blockquote>
</li>
<li><p>컴포넌트를 렌더링합니다.</p>
<blockquote>
<pre><code>let App = React.render(Counter);</code></pre></blockquote>
</li>
<li><p>초기 상태를 출력합니다.</p>
<blockquote>
<pre><code>App.render(); // 출력: count: 0</code></pre></blockquote>
</li>
<li><p>클릭 이벤트를 시뮬레이션합니다.</p>
<blockquote>
<pre><code>App.click();</code></pre></blockquote>
</li>
<li><p>변경된 상태로 다시 렌더링합니다.</p>
<blockquote>
<pre><code class="language-App">App.render(); // 출력: count: 1</code></pre>
</blockquote>
</li>
</ul>
<h4 id="3-더-나아가-기본hook-원리에-todolist-넣기">3. 더 나아가 기본hook 원리에 todolist 넣기</h4>
<ul>
<li><p>할일 목록 컴포넌트</p>
<blockquote>
<pre><code>function TodoList() {
  const [todos, setTodos] = React.useState([]);
  const [inputText, setInputText] = React.useState(&#39;&#39;);
  return {
      addTodo: (text) =&gt; {
          setTodos([...todos, text]);
          setInputText(&#39;&#39;);
      },
      updateInput: (text) =&gt; {
          setInputText(text);
      },
      render: () =&gt; {
          console.log(&#39;Current todos:&#39;, todos);
          console.log(&#39;Input value:&#39;, inputText);
      }
  };
}</code></pre></blockquote>
</li>
<li><p>사용 예시</p>
<blockquote>
<pre><code>let TodoApp = React.render(TodoList);
TodoApp.render(); // 초기 상태 출력</code></pre></blockquote>
</li>
<li><p>입력값 업데이트</p>
<blockquote>
<pre><code>TodoApp.updateInput(&#39;새로운 할일&#39;);
TodoApp = React.render(TodoList);
TodoApp.render();</code></pre></blockquote>
</li>
<li><p>할일 추가</p>
<blockquote>
<pre><code>TodoApp.addTodo(&#39;새로운 할일&#39;);
TodoApp = React.render(TodoList);
TodoApp.render();</code></pre></blockquote>
</li>
</ul>
<hr>
<h2 id="상태관리-매커니즘">상태관리 매커니즘</h2>
<p><img src="https://velog.velcdn.com/images/injung_p/post/249d1122-cd9e-453a-904a-5762360899e0/image.png" alt=""></p>
<h3 id="fiber는-javascript-객체-형태로-구현된-단일-연결-리스트linked-list-구조입니다">Fiber는 JavaScript 객체 형태로 구현된 단일 연결 리스트(Linked List) 구조입니다.</h3>
<h4 id="작업단위">작업단위</h4>
<ul>
<li>Fiber는 작업의 최소 단위로 동작</li>
</ul>
<ol>
<li>각 Fiber 노드는 하나의 컴포넌트에 대응합니다.</li>
<li>작업을 작은 단위로 분할하여 중단과 재개가 가능합니다.</li>
<li>우선순위에 따라 작업을 스케줄링 가능합니다.</li>
</ol>
<p>이러한 구조를 통해 React는 렌더링 작업을 더 효율적으로 관리하고 사용자 경험을 개선할 수 있습니다.</p>
<h3 id="트리-구조">트리 구조</h3>
<p><img src="https://velog.velcdn.com/images/injung_p/post/0d8e64e2-2b80-4f35-8df6-2a3801d0b024/image.png" alt=""></p>
<ol>
<li>child : 자식 노드를 가리킵니다.</li>
<li>sibling : 같은 부모를 가진 형제 Node를 가리킵니다.</li>
<li>return : 부모 Node를 가리킵니다.(작업 완료 후 돌아갈 노드)</li>
</ol>
<hr>
<h2 id="자주사용되는-react-hook">자주사용되는 React Hook</h2>
<h3 id="1-usestate">1. useState</h3>
<ul>
<li>react에서 함수형 컴포넌트에서 상태를 관리할 수 있도록 해주는 React 내장 Hook입니다.<h4 id="동작방식">동작방식</h4>
</li>
<li>컴포넌트가 처음 랜더링이 될때 그때 초기값을 가져오고 해당 초기값을 기준으로 상태를 관리합니다.<ul>
<li>초기값을 가져오고 그 값을 상태관리한다고 했는데 값이 변경될 경우에는 setState 담당합니다.</li>
</ul>
</li>
<li><pre><code>const [상태관리 값, 변경된 것을 받아서 처리하는 상태관리 값] = useState(초기값)

</code></pre></li>
</ul>
<ul>
<li><pre><code>const [state, setState]=useState(initState)
</code></pre></li>
</ul>
<h4 id="참고사항">참고사항</h4>
<ul>
<li>모듈 스코프에서 val변수를 통해서 상태를 저장을 합니다.</li>
</ul>
<blockquote>
</blockquote>
<pre><code>const UseStateComponent = () =&gt; {
  const [count, setCount] = useState(0);
  const handleClick = () =&gt; {
    setCount(count + 1);
  };
  return &lt;button onClick={handleClick}&gt;Count : {count}&lt;/button&gt;;
};
export default UseStateComponent;</code></pre><h3 id="2-useeffect">2. useEffect</h3>
<ul>
<li><p>컴포넌트의 부수효과를 처리하기 위한 Hook입니다.</p>
<h4 id="동작원리">동작원리</h4>
</li>
<li><p>컴포넌트가 렌더링이 된 후에 실행됩니다. 해당 컴포넌트에서 useEffect가장 늦게 읽힌다.</p>
</li>
<li><pre><code>useEffect(()=&gt;{useEffect가 실행되면 동작할 부분},[의존성 배열])</code></pre></li>
<li><p>의존성 배열은 useEffect가 랜더링이 언제 일어날지를 알려주는 것입니다.</p>
</li>
<li><p>의존성 배열의 값이 변경될때마다 useEffect는 실행이 됩니다. </p>
</li>
<li><p>cleanup는 unMounting 일때 발생합니다.</p>
</li>
<li><p>cleanup 함수를 반환하여 정리 작업을 수행할 수 있습니다.</p>
<blockquote>
<pre><code>const UseEffectComponent = () =&gt; {
const [name, setName] = useState(&#39;korea&#39;);
const [count, setCount] = useState(0);
const [windowSize, setWindowSize] = useState({
  width: window.innerWidth,
  height: window.innerHeight,
});
console.log(&#39;코드가 읽힙니다.&#39;);
  useEffect(() =&gt; {
    // state와 setState동시에 사용하는 경우에는 의존성배열 사용된 어떠한 state값도 넣지말라 넣으면 무한 랜더링이 진행된다.
  setCount(count + 1);
}, [count]); // 의존성배열이 반값이라면 딱 첫 랜더링이후에 읽혀지는 것만 진행
// 의존성배열이 없다면 그것은 그냥 useState와 동일하게 동작합니다.
useEffect(() =&gt; {
  console.log(&#39;name effect&#39;);
}, [name]);
console.log(&#39;코드가 전부 읽혔습니다.&#39;);
return (
  &lt;div&gt;
    &lt;h2&gt;현재 윈도우 사이즈 :&lt;/h2&gt;
    &lt;p&gt;width :{windowSize.width}px&lt;/p&gt;
    &lt;p&gt;height :{windowSize.height}px&lt;/p&gt;
    &lt;p onClick={() =&gt; setName(&#39;KOREAKROEA&#39;)}&gt;버튼&lt;/p&gt;
  &lt;/div&gt;
);
};
export default UseEffectComponent;</code></pre></blockquote>
</li>
</ul>
<h3 id="3-useref">3. useRef</h3>
<ul>
<li>useState와 useEffect문제점 -&gt; 랜더링</li>
<li>useState 무분별함 : 연관성이 없는 아이도 랜더링에 참여한다.</li>
<li>useEffect 무분별함 : 무한루프, 실제로 변경되어야 할 값이 변경되지 않는 버그생성,*렌더링에 전혀 영향을 주지 않는다.</li>
<li>렌더링에 영향을 주지 않는 가변값을 저장하는 컨테이너입니다.<h4 id="동작방식-1">동작방식</h4>
</li>
<li>.current 현개 가변 값은? </li>
</ul>
<ol>
<li>.current 프로퍼티(속성)을 통해서 값을 저장하고 접근합니다.</li>
<li>값이 변경되어도 랜더링이 일어나지 않는다.</li>
<li>DOM에 직접적으로 접근한다.*<h4 id="단점">단점</h4>
</li>
</ol>
<ul>
<li>.current에 들어가있던 저장된 값은 랜더링을 하지 않는 이상 현재 저장된 값을 보여주지 못하고 처음 초기값으로 들어간 값만 보여준다.</li>
</ul>
<blockquote>
<pre><code>const UseRefComponent = () =&gt; {
  // const [count, setCount] = useState(0);
  const [render, setRender] = useState(0);
  const countRef = useRef(0);
  // const handleCountUpdate = () =&gt; {
  //   setCount(count + 1);
  // };
  const handleRenderUpdate = () =&gt; {
    setRender(render + 1);
  };
  // Ref는 아무리 수정해도 컴포넌트를 re-rendering을 시키지 않는다.
  const handleRefUpdate = () =&gt; {
    countRef.current = countRef.current + 1;
    console.log(&#39;Ref값 올라가유 : &#39;, countRef);
  };
  console.log(&#39;렌더링을 합니다 🎢&#39;);
  // console.log(&quot;Ref값 올라갈까유? : &quot;, countRef);
  return (
    &lt;div style={{ backgroundColor: &#39;lightblue&#39;, fontSize: &#39;20px&#39; }}&gt;
      &lt;p&gt;State : {render}&lt;/p&gt;
      &lt;p&gt;useRef : {countRef.current}&lt;/p&gt;
      {/* &lt;button onClick={handleCountUpdate}&gt;state값 올라갑니다&lt;/button&gt; */}
      &lt;button onClick={handleRenderUpdate}&gt;리 랜더링 되유 값이 이제 바껴유&lt;/button&gt;
      &lt;button onClick={handleRefUpdate}&gt;ref값 올라갑니다&lt;/button&gt;
    &lt;/div&gt;
  );
};
export default UseRefComponent;</code></pre></blockquote>
<h3 id="4-usecallback">4. useCallback</h3>
<ul>
<li>메모이제이션된 callback을 반환하는 Hook입니다.</li>
<li>callback 함수와 의존성 배열을 인자로 받습니다. 
해당 useCallback은 의존성배열 내의 값이 변경될때만 새로운 함수를 반환합니다. 
그렇지 않으면 이전의 메모이제이션된 함수를 반환합니다.<h4 id="장점">장점</h4>
</li>
</ul>
<ol>
<li>불필요한 리 렌더링을 방지합니다.</li>
<li>성능 최적화를 진행합니다.</li>
<li>동일성을 보장합니다.<h4 id="주의사항">주의사항</h4>
</li>
<li>모든 함수의 useCallback을 사용하면 오히려 성능이 떨어질 수 있습니다.
(캐싱되는것이 많이 때문)</li>
<li>의존성 배열의 올바른 관리가 필요합니다.
(무한적으로 랜더링이 될 수 있기 때문)<h4 id="사용부분">사용부분</h4>
</li>
<li>복잡한 상태 로직을 다룰 때 사용합니다.</li>
<li>다음 상태가 이전 상태의 의존적일때 사용됩니다.</li>
<li>여러 하위 값을 포함하는 객체를 상태로 다룰 때 사용됩니다.<h3 id="5-usememo">5. useMemo</h3>
</li>
</ol>
<ul>
<li>계산 비용이 높은 함수의 결과값을 메모이제이션하는 Hook입니다.</li>
<li>생성 함수와 의존성 배열을 인자로 받습니다.</li>
<li>의존성 배열의 값이 변경될때만 생성 함수를 재 실행합니다. 
그렇지 않으면 이전의 메오이제이션된 값을 반환합니다.<h4 id="장점-1">장점</h4>
</li>
</ul>
<ol>
<li>성능을 최적화 합니다.</li>
<li>불필요한 계산을 방지합니다.</li>
<li>랜더링 성능을 향상 시킵니다.<h4 id="주의사항-1">주의사항</h4>
</li>
<li>모든 계산의 useMemo를 사용하면 메모리 사용량이 증가할 수 있습니다.
(캐싱되는것이 많기 때문)</li>
<li>간단한 연산에는 사용하지 않는 것이 좋습니다.<h4 id="사용부분-1">사용부분</h4>
</li>
<li>복잡한 계산이 필요한 값을 랜더링 할 경우 사용합니다.</li>
<li>객체 참조의 안정성이 필요할 때 사용합니다.</li>
<li>부모 컴포넌트의 리렌더링으로 인한 불필요한 계산을 방지할 때 사용합니다.<h3 id="6-reactmemo">6. React.memo</h3>
</li>
</ol>
<ul>
<li>컴포넌트를 메모이제이션하는 고차 컴포넌트 입니다.</li>
<li>React.memo로 감싼 컴포넌트는 props가 변경되지 않으면 리렌더링되지 않게 합니다.
기본적으로 얕은 비교를 수행합니다. 
필요한 경우 사용자 정의 비교 함수를 제공합니다.<h4 id="장점-2">장점</h4>
</li>
</ul>
<ol>
<li>불필요한 리렌더링을 방지합니다.</li>
<li>성능을 최적화 합니다.</li>
<li>큰 컴포넌트 트리에서 효과적으로 사용됩니다.<h4 id="주의사항-2">주의사항</h4>
</li>
<li>모든 컴포넌트를 메모로 감싸는 것은 권장되지 않습니다.</li>
<li>함수나 객체를 props로 전달할때는 useCallback이나 useMemo와 함께 사용해야 효과적입니다.</li>
<li>컴포넌트가 자주 리렌더링되지 않게 하거나 렌더링이 따른 경우에는 메모가 필요하지 않습니다.<h3 id="7-usecontext">7. useContext</h3>
</li>
</ol>
<ul>
<li>React 컴포넌트 트리 전체에 걸쳐 데이터를 공유할 수 있게 하는 Hook입니다.</li>
<li>context 객체를 인자로 받아 해당 context의 현재 값을 반환합니다.
context의 값이 변경이 되면 컴포넌트가 리렌더링 됩니다.<h4 id="장점-3">장점</h4>
</li>
</ul>
<ol>
<li>컴포넌트 트리 전체를 걸쳐서 데이터를 쉽게 공유할 수 있습니다.</li>
<li>props drilling 문제를 해결합니다.<h4 id="주의사항-3">주의사항</h4>
</li>
<li>context를 사용하면 컴포넌트 재 사용성이 어려워집니다.</li>
<li>자주변경되는 값을 <code>context</code>로 관리하면 성능 문제가 발생합니다.</li>
<li>여러 <code>context</code>를 중첩해서 사용할 경우 컴포넌트 트리가 더욱더 복잡해 질 수 있습니다.<h4 id="사용방법">사용방법</h4>
</li>
<li>전역 상태관리가 필요할 때 사용됩니다.
( <em><strong>ex )</strong></em> 사용자 인증 정보, 테마 설정 시 )</li>
<li>중첩 구조에서 props drilling를 피하고자 할 때 사용됩니다.</li>
<li>여러 컴포넌트에서 공유해야하는 데이터가 있을 때 사용됩니다.<h3 id="8-usereducer">8. useReducer</h3>
</li>
</ol>
<ul>
<li>복잡한 상태 로직을 관리하는 데 사용되는 Hook입니다.</li>
<li>현재 상태와 엑션을 받아 새로운 상태를 반환하는 Reducer 함수와 초기상태를 인자로 받습니다.
userReducer 는 현재 상태와 dispatch 함수를 반환합니다.<h4 id="장점-4">장점</h4>
</li>
</ul>
<ol>
<li>복잡한 상태 변화를 예측 가능하게 만듭니다.</li>
<li>상태 업데이트로 로직을 분리할 수 있습니다.</li>
<li>테스트하기 쉬운 순수 함수로 상태 변화를 표현합니다.<h4 id="주의사항-4">주의사항</h4>
</li>
<li>간단한 상태 관리는 useState가 더 적합할 수 있습니다.</li>
<li>Reducer 함수가 더욱더 복잡할수록 구조화를 잘 구성해야 합니다.<h4 id="사용방법-1">사용방법</h4>
</li>
<li>복잡한 상태의 로직이 필요할 때 사용합니다.</li>
<li>다음 상태가 이전 상태에 의존할 때 사용합니다.</li>
<li>여러 하위 값을 포함하는 객체 상태를 다룰 때 사용합니다.<h3 id="9-customhook">9. customHook</h3>
Custom Hook은 React의 기본 Hook(useState, useEffect 등)을 조합하여 재사용 가능한 로직을 캡슐화한 함수입니다. 특정 기능을 여러 컴포넌트에서 반복적으로 사용할 때 유용합니다.<h4 id="장점-5">장점</h4>
</li>
<li>로직의 재사용성 증가 → 여러 컴포넌트에서 동일한 기능을 쉽게 사용 가능</li>
<li>컴포넌트의 가독성 향상 → UI와 비즈니스 로직을 분리하여 코드가 깔끔해짐</li>
<li>Side Effect 관리 용이 → useEffect 등을 활용한 API 호출, 이벤트 리스너 관리<h4 id="주의사항-5">주의사항</h4>
이름은 반드시 use로 시작해야 함 → React가 Hook으로 인식하도록</li>
<li>컴포넌트 또는 다른 Hook 내부에서 호출해야 함</li>
<li>React의 규칙을 준수해야 함 → 조건문이나 반복문 안에서 호출하지 않기<h4 id="사용방법-2">사용방법</h4>
</li>
</ol>
<ul>
<li><ol>
<li>Custom Hook 작성</li>
</ol>
</li>
</ul>
<blockquote>
</blockquote>
<pre><code>import { useState } from &quot;react&quot;;
export const useInput = (initialValue) =&gt; {
  const [value, setValue] = useState(initialValue);
  const handleChange = (event) =&gt; setValue(event.target.value);
  return [value, handleChange, setValue];
};</code></pre><blockquote>
</blockquote>
<ul>
<li><ol start="2">
<li>컴포넌트에서 사용</li>
</ol>
</li>
</ul>
<blockquote>
</blockquote>
<pre><code>import React from &quot;react&quot;;
import React from &quot;react&quot;;
import { useInput } from &quot;./useInput&quot;;
export const MyComponent = () =&gt; {
  const [name, handleNameChange] = useInput(&quot;&quot;);
  return (
    &lt;input 
      type=&quot;text&quot; 
      value={name} 
      onChange={handleNameChange} 
    /&gt;
  );
};</code></pre><blockquote>
</blockquote>
<ul>
<li><ol start="3">
<li>useFetch</li>
</ol>
</li>
</ul>
<blockquote>
</blockquote>
<pre><code>import { useFetch } from &quot;./customHook/useFetch&quot;;
const FETCH_URL = &quot;https://jsonplaceholder.typicode.com/posts&quot;;
const FETCH_URL_TODO = &quot;https://jsonplaceholder.typicode.com/todos&quot;;
const CustomHookFetch = () =&gt; {
  const { data, isLoading, error } = useFetch(FETCH_URL);
  if (isLoading)
    return (
      &lt;div style={{ display: &quot;flex&quot;, width: &quot;100%&quot;, height: &quot;100vh&quot;, justifyContent: &quot;center&quot;, alignItems: &quot;center&quot; }}&gt;
        Loading...
      &lt;/div&gt;
    );
  if (error) return &lt;div&gt;Error&lt;/div&gt;;
  return (
    &lt;div&gt;
      &lt;ul&gt;
        {data.map((post) =&gt; (
          &lt;li key={post.id}&gt;
            &lt;h3&gt;제목 : {post.title}&lt;/h3&gt;
            &lt;p&gt;내용 : {post.body}&lt;/p&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
};
export default CustomHookFetch;</code></pre><blockquote>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Branch 전략]]></title>
            <link>https://velog.io/@injung_p/Git-Branch-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@injung_p/Git-Branch-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Thu, 28 Nov 2024 14:43:42 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/injung_p/post/0500a9a5-2579-4ffe-938b-c310a2b0f4bc/image.png" alt="">
<img src="https://velog.velcdn.com/images/injung_p/post/6bfc7c2c-cf73-48c7-83ff-047a911f7240/image.png" alt=""></p>
<h2 id="git-flow">Git Flow</h2>
<h3 id="주요-브랜치">주요 브랜치</h3>
<ul>
<li>master : 제품 출시 브랜치</li>
<li>develop : 개발 브랜치</li>
<li>feature : 기능 개발 브랜치</li>
<li>release : 출시 준비 브랜치</li>
<li>hotfix : 긴급 버그 수정 브랜치<h3 id="장점">장점</h3>
</li>
</ul>
<ol>
<li><p>체계적인 버전 관리</p>
</li>
<li><p>대규모 프로젝트에 적합</p>
</li>
<li><p>안정적인 배포 관리</p>
</li>
<li><p>팀 규모가 작은팀인 경우 GitHub Flow나 Trunk-Based Development가 적합</p>
<ul>
<li>큰 팀 : Git Flow와 같은 구조화된 전략이 효과적<h4 id="팀-성숙도">팀 성숙도</h4>
</li>
</ul>
</li>
</ol>
<ul>
<li>성숙한 팀 : Git Flow와 같은 복잡한 전략 도입 가능</li>
<li>협업 경험이 적은 팀 : 단순한 Feature Branch 전략 추천<h3 id="배포-주기">배포 주기</h3>
</li>
<li>잦은 배포 : Trunk-Based Development나 GitHub Flow</li>
<li>정기 배포 : Git Flow나 Release Branch 전략<h3 id="프로젝트-복잡도">프로젝트 복잡도</h3>
</li>
<li>단순한 프로젝트 : Feature Branch나 Trunk-Based Development</li>
<li>복잡한 프로젝트 : Git Flow나 Release Branch 전략<h3 id="테스트-자동화-수준">테스트 자동화 수준</h3>
</li>
<li>자동화된 테스트가 잘 갖춰진 경우 : Trunk-Based Development 가능</li>
<li>수동 테스트가 많은 경우 : Feature Branch나 Git Flow 권장<h3 id="단점">단점</h3>
</li>
</ul>
<ol>
<li>복잡한 브랜치 구조</li>
<li>느린 배포 주기</li>
<li>브랜치 관리 오버헤드<h3 id="github-flow-구조">GitHub Flow 구조</h3>
</li>
</ol>
<ul>
<li>main : 항상 배포 가능한 상태 유지</li>
<li>feature : 기능 개발용 브랜치<h3 id="장점-1">장점</h3>
</li>
</ul>
<ol>
<li>단순한 구조</li>
<li>빠른 배포 가능</li>
<li>CI/CD에 적합<h3 id="단점-1">단점</h3>
</li>
<li>버전 관리가 어려움</li>
<li>대규모 프로젝트에는 부적합</li>
</ol>
<hr>
<h2 id="gitlab-flow">GitLab Flow</h2>
<h3 id="구조">구조</h3>
<ul>
<li>production : 배포 브랜치</li>
<li>pre-production : 사전 배포 브랜치</li>
<li>main : 개발 브랜치</li>
<li>feature : 기능 개발 브랜치<h3 id="장점-2">장점</h3>
</li>
</ul>
<ol>
<li>환경별 브랜치 관리 용이</li>
<li>단계적 배포 가능</li>
<li>Git Flow보다 단순<h3 id="단점-2">단점</h3>
</li>
<li>환경별 브랜치 동기화 필요</li>
<li>중간 규모 이상 프로젝트에 적합</li>
<li>브랜치 전략 선택 시 고려사항</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/injung_p/post/8b483149-cf5b-451f-a293-70496214acec/image.png" alt=""></p>
<h3 id="trunk-based-development">Trunk-Based Development</h3>
<h4 id="특징">특징</h4>
<ol>
<li>단일 메인 브랜치 사용</li>
<li>작은 단위의 잦은 커밋</li>
<li>짧은 수명의 피처 브랜치<h4 id="장점-3">장점</h4>
</li>
<li>빠른 개발 속도</li>
<li>간단한 브랜치 관리</li>
<li>지속적 통합 용이<h4 id="단점-3">단점</h4>
</li>
<li>높은 수준의 자동화 필요</li>
<li>코드 품질 관리 어려움<h4 id="trunk-based-development-추천">Trunk-Based Development 추천</h4>
</li>
</ol>
<ul>
<li>빠른 개발 속도</li>
<li>단순한 구조</li>
<li>즉각적인 배포</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 이란?]]></title>
            <link>https://velog.io/@injung_p/Git-%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@injung_p/Git-%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 26 Nov 2024 14:06:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/injung_p/post/d02aea56-0f28-4e2c-a507-7af8bb4eb6cb/image.png" alt=""></p>
<blockquote>
<p>Git 이란?
분산 버전 관리 시스템(DVCS, Distributed Version Control System)이며, 
소스 코드의 변경 이력을 관리하고 여러 사람이 협업할 수 있도록 돕는 도구입니다.</p>
</blockquote>
<h3 id="git의-주요-기능">Git의 주요 기능</h3>
<ul>
<li>버전 관리 : Git은 파일의 변경 내역을 추적하고, 이전 버전으로 되돌릴 수 있도록 도와줍니다. 언제든지 코드의 이전 상태로 복원하거나 특정 시점의 상태를 확인할 수 있습니다.</li>
<li>분산형 관리 : Git은 분산형 시스템으로, 모든 개발자는 자신만의 로컬 저장소에서 작업할 수 있습니다. 로컬 저장소에서 커밋하고 브랜치를 만들며, 이를 원격 저장소와 동기화할 수 있습니다.</li>
<li>협업 : 여러 개발자가 동시에 작업할 수 있습니다. Git은 각자의 작업을 관리하고 병합할 수 있도록 해주며, 예를 들어 두 명의 개발자가 각각 다른 브랜치에서 작업한 후 이를 하나로 합치는 병합(Merge) 기능을 제공합니다.</li>
<li>분기(Branching) 및 병합(Merging) : Git은 여러 가지 브랜치를 만들어 독립적으로 작업할 수 있게 해줍니다. 예를 들어, 새로운 기능을 개발하는 동안 메인 코드베이스는 그대로 두고 작업을 진행할 수 있습니다. 작업이 완료되면 브랜치를 병합하여 코드베이스에 반영할 수 있습니다.</li>
</ul>
<h3 id="git의-주요-특징">Git의 주요 특징</h3>
<ul>
<li>빠르고 효율적 : Git은 데이터를 압축하고 분산 저장하기 때문에 대규모 프로젝트도 빠르고 효율적으로 관리할 수 있습니다.</li>
<li>변경 이력 추적 : 각 커밋(commit)은 코드의 변경 사항을 기록하며, 언제, 누가, 무엇을 변경했는지를 추적할 수 있습니다.</li>
<li>협업 최적화 : Git은 팀 작업을 위해 최적화되어 있으며, 충돌(conflict) 해결 및 병합(Merge) 등의 기능을 제공합니다.</li>
</ul>
<h3 id="git-명령어">git 명령어</h3>
<h4 id="1-저장소-생성-및-복제">1. 저장소 생성 및 복제</h4>
<ul>
<li><p>git init : 새로운 Git 저장소를 생성합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/b3f96765-956b-48db-886c-3484c736c955/image.png" alt=""></p>
</li>
<li><p>git clone &lt;원격저장소 URL&gt; : Git 저장소를 복제합니다.</p>
</li>
</ul>
<h4 id="2-파일-상태-확인">2. 파일 상태 확인</h4>
<ul>
<li>git status : 현재 작업 디렉토리의 상태를 확인합니다. 
추적되지 않은 파일이나 수정된 파일을 확인할 수 있습니다.
<img src="https://velog.velcdn.com/images/injung_p/post/1c80dc4a-1349-4a86-ba94-e10446a22524/image.png" alt=""></li>
</ul>
<h4 id="3-파일-추적하기">3. 파일 추적하기</h4>
<ul>
<li>git add &lt;파일명&gt; : 변경된 파일을 스테이징 영역에 추가합니다.</li>
<li>git add . : 모든 변경된 파일을 한 번에 스테이징 영역에 추가합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/dafbf88d-708a-4b54-a02e-83f5b4b8b250/image.png" alt=""></li>
</ul>
<h4 id="4-커밋하기">4. 커밋하기</h4>
<ul>
<li>git commit -m &quot;메시지&quot; : 스테이징 영역에 있는 변경 사항을 커밋합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/1ae8d0ab-4825-4941-bc23-0d4cecf359b9/image.png" alt=""></li>
<li>git commit --amend : 마지막 커밋을 수정합니다.</li>
</ul>
<h4 id="5-변경-내용-확인">5. 변경 내용 확인</h4>
<ul>
<li>git diff : 변경된 내용을 확인합니다.</li>
<li>git difftool : 작업 디렉토리와 스테이징 영역을 시각적으로 비교합니다.</li>
<li>git log : 커밋 히스토리를 전체를 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/60875206-652a-4a96-9d76-0bd94a93a89a/image.png" alt=""></li>
<li>git log --oneline : 커밋 히스토리를 한줄로 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/4307e48c-4839-4a1a-8e0b-8ebcc5563eae/image.png" alt=""></li>
<li>git blame &lt;파일명&gt; : 파일의 각 라인의 수정이력을 확인합니다.</li>
</ul>
<p><em><strong>ex )</strong></em> <img src="https://velog.velcdn.com/images/injung_p/post/744cab27-1974-41df-a3da-36c9c81a8310/image.png" alt=""></p>
<h4 id="6-브랜치-관련-명령어">6. 브랜치 관련 명령어</h4>
<ul>
<li>git branch : 현재 브랜치 목록을 확인하고, 현재 브랜치를 표시합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/fb7fe21f-cbaf-4bc8-9bf8-0b5fb486c20a/image.png" alt=""></li>
<li>git branch &lt;브랜치명&gt; : 새로운 브랜치를 생성합니다.</li>
<li>git checkout &lt;브랜치명&gt; : 다른 브랜치로 전환합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/0475be85-c3b4-4f68-a299-e2f1f79ae961/image.png" alt=""></li>
<li>git checkout -b &lt;브랜치명&gt; : 새로운 브랜치를 생성과 동시에 해당 브랜치로 전환합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/3f5866f5-9163-4fae-a536-69435f2ff428/image.png" alt=""></li>
<li>git branch -d &lt;브랜치명&gt; : 선택한 브랜치를 삭제합니다.</li>
<li>git merge &lt;브랜치명&gt; : 현재 브랜치에 다른 브랜치를 병합합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/d156143e-9d8e-4a03-b401-d337351988aa/image.png" alt=""></li>
<li>git switch &lt;브랜치명&gt; : 다른 브랜치로 전환시킵니다.
<img src="https://velog.velcdn.com/images/injung_p/post/4ea44f7e-808c-45ce-8f8d-aa6df27c3131/image.png" alt=""></li>
</ul>
<h4 id="7-원격-저장소-관련-명령어">7. 원격 저장소 관련 명령어</h4>
<ul>
<li>git remote add origin &lt;저장소 URL&gt; : 원격 저장소를 추가합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/6c799fc4-6745-413c-8688-7ad0a799a72f/image.png" alt=""></li>
<li>git push origin &lt;브랜치명&gt; : 로컬 브랜치를 원격 저장소로 푸시합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/fda039e1-bb18-47f8-b64d-022fbc4266b6/image.png" alt=""></li>
<li>git push -u origin &lt;브랜치명&gt; : 다음번에 Git push나 Git pull을 실행할 때 브랜치를 명시적으로 지정하지 않아도 됩니다.
(로컬 브랜치와 원격 브랜치 사이의 추적 관계를 설정하는 역할)
<img src="https://velog.velcdn.com/images/injung_p/post/89dedc37-f25c-45e5-a6a1-49deb9df9ede/image.png" alt=""></li>
<li>git pull origin &lt;브랜치명&gt; : 원격 저장소에서 변경 사항을 가져옵니다.</li>
<li>git fetch : 원격 저장소의 정보를 가져옵니다.</li>
<li>git remote -v : 원격 저장소의 목록을 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/71d98246-91e4-4216-a036-7074728887b3/image.png" alt=""></li>
</ul>
<h4 id="8-되돌리기-관련-명령어">8. 되돌리기 관련 명령어</h4>
<ul>
<li>git reset --soft HEAD^ : 직전 명령을 스테이징 영역으로 되돌립니다.</li>
<li>git reset --hard HEAD^ : 직전 명령을 완전히 삭제합니다.</li>
<li>git revert &lt;커밋해시&gt; : 특정 커밋을 취소하고 새로운 커밋으로 생성합니다.</li>
<li>git restore &lt;파일명&gt; : 작업 디렉토리의 변경사항을 취소합니다.</li>
</ul>
<h4 id="9-임시저장-명령어">9. 임시저장 명령어</h4>
<ul>
<li>git stash : 현재 작업 내용을 임시저장합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/2c0589b2-7deb-41b7-972a-be3b944bf212/image.png" alt=""></li>
<li>git stash list : 임시저장된 리스트를 보여줍니다.</li>
<li>git stash apply : 가장 최근의 임시저장 내용을 가져옵니다.</li>
<li>git stash pop : 가장 최근의 임시저장 내용을 가져오고 삭제합니다.</li>
</ul>
<h4 id="10-태그-관련-명령어">10. 태그 관련 명령어</h4>
<p><img src="https://velog.velcdn.com/images/injung_p/post/c749bf0a-0f70-47e3-b101-bd1bee429fab/image.png" alt="">
Git tag란?</p>
<ul>
<li><p>프로젝트의 특정시점을 표시하는 도구 입니다.</p>
<ul>
<li>사용처로는 소프트웨어 배포버전(v1.1.0 v1.2.0) 표시로 사용합니다.</li>
</ul>
</li>
<li><p>git tag : 태그 목록을 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/51e3d412-3d4f-4bbd-8fa7-9edebf81191c/image.png" alt=""></p>
</li>
<li><p>git tag &lt;태그명&gt; : 태그를 생성합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/a348b58f-b425-4d87-b4d0-650fbd84f036/image.png" alt=""></p>
</li>
<li><p>git tag -a &lt;태그명&gt; -m &quot;메세지&quot; : 주석이 있는 태그를 생성합니다.</p>
</li>
<li><p>git push origin &lt;태그명&gt; : 태그를 원격 저장소에 푸시합니다.</p>
</li>
</ul>
<h4 id="11-이외-명령어">11. 이외 명령어</h4>
<ul>
<li>git reflog : Git 참조 로그를 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/99331cac-69aa-4ac4-a2ff-38966b1448ee/image.png" alt=""></li>
<li>git rebase &lt;브랜치명&gt; : 브랜치를 재 배치합니다.</li>
</ul>
<h4 id="12-자주-발생하는-문제해결">12. 자주 발생하는 문제해결</h4>
<ul>
<li>git clean -fd : 추적되지 않는 파일 또는 디렉토리를 삭제합니다.</li>
<li>git fetch --all : 모든 원격 브랜치 정보를 가져옵니다.
<img src="https://velog.velcdn.com/images/injung_p/post/1706eccf-ded8-46b0-ab59-81649a9b4efb/image.png" alt=""></li>
<li>git rest --hard origin/&lt;브랜치명&gt; : 원격 브랜치로 강제 초기화합니다.</li>
<li>git remote remove origin : 기존 리포지토리 remote를 제거합니다.</li>
<li>git remote add origin &lt;git remote 주소&gt; : github저장소를 remote로 연결합니다.</li>
</ul>
<h4 id="13-파일-삭제">13. 파일 삭제</h4>
<ul>
<li>git rm &lt;파일명&gt; :  파일 디렉토리와 Git저장소에서 모두 삭제합니다.</li>
<li>git rm -f &lt;파일명&gt; : 강제로 파일을 삭제합니다.
(변경사항이 있어도 삭제처리 합니다.)</li>
<li>git rm --cached &lt;파일명&gt; : git 저장소에서만 삭제합니다.
(로컬 파일은 유지합니다.)</li>
</ul>
<h4 id="14-git-상태-복원">14. Git 상태 복원</h4>
<ul>
<li>git checkout --&lt;파일명&gt; : 로컬 변경 사항을 되돌리고, 마지막 커밋 상태로 복원합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React를 배우기 전 기본 상식]]></title>
            <link>https://velog.io/@injung_p/React%EB%A5%BC-%EB%B0%B0%EC%9A%B0%EA%B8%B0-%EC%A0%84-%EA%B8%B0%EB%B3%B8-%EC%83%81%EC%8B%9D</link>
            <guid>https://velog.io/@injung_p/React%EB%A5%BC-%EB%B0%B0%EC%9A%B0%EA%B8%B0-%EC%A0%84-%EA%B8%B0%EB%B3%B8-%EC%83%81%EC%8B%9D</guid>
            <pubDate>Sun, 24 Nov 2024 11:23:15 GMT</pubDate>
            <description><![CDATA[<h2 id="spa-single-page-application">SPA (Single Page Application)</h2>
<h3 id="의미">의미</h3>
<ol>
<li>하나의 HTML 페이지로 구성된 웹 애플리케이션</li>
<li>클라이언트 측에서 페이지 전환을 처리<h3 id="특징">특징</h3>
</li>
<li>최초 로드 후 추가적인 페이지 요청 없이 동작</li>
<li>빠른 사용자 경험</li>
<li>React, Vue, Angular로 구현 가능<h3 id="장점">장점</h3>
서버 부하 감소화 됩니다.</li>
</ol>
<ul>
<li>초기로드 이후에는 필요한 데이터만 전송하기 때문입니다.<h3 id="단점">단점</h3>
SEO 최적화 어려움
( JavaScrpit 렌더링이 필요한 콘텐츠는 검색엔진이 인식하기 어렵습니다. 
그리고 각 페이지별 메타태그가 존재하지 않기 때문입니다. )</li>
<li>초기 로딩시간이 길어질 수 있습니다.</li>
</ul>
<h3 id="작동방식">작동방식</h3>
<p>초기 로드 시 전체 애플리케이션을 다운로드(번들구성(번들.js)하고 이후 웹에서 사용자 상호 작용에 따라 필요한 데이터만 서버에서 가져와 동적으로 페이지를 업데이트 합니다.</p>
<hr>
<h2 id="mpa-multi-page-application">MPA (Multi Page Application)</h2>
<h3 id="의미-1">의미</h3>
<p>여러 HTML 페이지로 구성된 전통적인 웹 애플리케이션</p>
<h3 id="특징-1">특징</h3>
<ol>
<li>페이지 구성 : 각 페이지가 독립적인 html파일로 존재</li>
<li>페이지 이동 : 사용자가 새로운 페이지로 이동할때마다 서버에서 해당 html파일을 받아 브라우저에서 랜더링</li>
<li>랜더링 방식 : 주로 SSR방식을 사용<h3 id="장점-1">장점</h3>
</li>
<li>SEO에 최적화 : 각 페이지가 독립된 URL과 콘텐츠를 가지고 있어, 검색 엔진이 쉽게 크롤링하고 인덱싱 할 수 있음</li>
<li>브라우저 호완성 : 오래된 브라우저에서 잘 작동하며 특별한 기술이나 라이브러리가 필요하지 않습니다. </li>
<li>보안 : 서버측에서 추가적인 보안제어가 가능합니다.<h3 id="단점-1">단점</h3>
</li>
<li>페이지 로딩 : 새로운 페이지로 이동할 때 마다 전체 페이지를 다시 로드해야므로 로딩 시간이 길어질 수 있습니다.</li>
<li>서버 부하 : 사용자의 모든 요청을 서버가 처리해야 하므로 트레픽이 많은 경우 서버의 부담이 큽니다.</li>
<li>사용자 경험 : 페이지 전환 시 화면 전체가 깜박이며, 다시 로딩되므로 사용자 경험에 좋지 않습니다.</li>
</ol>
<hr>
<h2 id="csr-client-side-rendering">CSR (Client-Side Rendering)</h2>
<h3 id="의미-2">의미</h3>
<p>웹 애플리케이션 렌더링을 사용자의 브라우저에서 수행하는 방식입니다. 
JavaScprit를 사용하여 브라우저에서 웹 사이트나 애플리케이션을 렌더링 합니다.</p>
<h3 id="작동방식-1">작동방식</h3>
<ol>
<li>초기요청 : 사용자가 웹 페이지를 요청하면 서버는 최소한의 html파일과 함께 JavaScrpit, css를 포함하여 응답합니다.</li>
<li>리소스 다운로드 : 브라우저는 해당 html파일을 파싱하고 css와 JavaScript파일을 다운로드 합니다.</li>
<li>렌더링 : 다운로드된 JavaScript가 실행되어 페이지에 콘텐츠를 동적으로 생성하고 사용자 인터페이스를 구성합니다.<h3 id="장점-2">장점</h3>
</li>
<li>서버 부하 감소(서버는 최소한의 html과 정적 데이터만 제공함으로 서버 부하를 줄어듭니다.)</li>
<li>동적 인터렉티브 경험 : csr은 사용자 사용작용에 즉각적으로 반응할 수 있는 동적이고 인터렉티브한 웹 에플리케이션을 구축하는데 적합합니다. 이는 실시간 업데이트가 필요한 어플리케이션에 유리 합니다.</li>
<li>빠른 후속 페이지 로드 : 초기 로드 이후에는 페이지 전환이 빠르게 이루어 지며 전체 페이지를 다시 로드할 필요 없이 필요한 데이터만 갱신합니다.<h3 id="단점-2">단점</h3>
</li>
<li>SEO 문제 : 초기 html이 빈상태로 제공되므로 검색엔진 크롤러가 콘텐츠를 제대로 인식하지 못할 수 있어 SEO에 불리합니다.</li>
<li>초기 로딩 시간 증가 : 초기 페이지 로딩 시 브라우저가 모든 JavaScrpit파일을 다운로드하고 실행하므로 시간이 더 걸릴 수 있습니다.</li>
<li>일관적이지 못한 사용자 경험 : CSR은 클라이언트 디바이스 상태에 따라 사용자 경험이 달라질 수 있습니다. 이는 인터넷 연결 속도나 브라우저 호환성에 따라 영향을 받을 수 있습니다.</li>
</ol>
<hr>
<h2 id="ssg-static-site-generation">SSG (Static Site Generation)</h2>
<h3 id="의미-3">의미</h3>
<p>빌드 시점의 모든 페이지를 정적 html파일로 생성하는 방식 입니다.</p>
<ul>
<li>대표적인 사례로 블로그, 포토폴리오, 웹 사이트, 마케팅 페이지, 문서 사이트와 같은 정적 영역이 필요한 경우에 사용됩니다. 도구로는 Gatsby, Next.js, Hugo가 있습니다.<h3 id="장점-3">장점</h3>
</li>
</ul>
<ol>
<li>매우 빠른 페이지 로딩 속도 </li>
<li>높은 보안성</li>
<li>호스팅 비용 절감</li>
<li>SEO 최적화 유리<h3 id="단점-3">단점</h3>
</li>
<li>동적 콘텐츠 처리가 제한</li>
<li>대규모 사이트인 경우 빌드 속도가 느려질 수 있음 </li>
<li>콘텐츠가 업데이트 된다면 전체 사이트 재 빌드 필요</li>
</ol>
<hr>
<h2 id="isr-incremental-static-regeneration">ISR (Incremental Static Regeneration)</h2>
<h3 id="의미-4">의미</h3>
<p>정적 생성과 서버사이드 랜더링의 장점을 결합한 것 입니다.</p>
<h3 id="작동-방식">작동 방식</h3>
<ol>
<li>빌드 시 일부 페이지를 정적으로 생성</li>
<li>설정된 시간 간격으로 백그라운드에서 페이지를 재 생성</li>
<li>새로운 요청이 들어오면 캐시된 버전을 제공 후 업데이트 된 버전으로 교체<h3 id="장점-4">장점</h3>
</li>
<li>SEO에 유리합니다.</li>
<li>서버부화 감소</li>
<li>빠른 페이지 로드와 최신 데이터 제공 균형<h3 id="단점-4">단점</h3>
</li>
<li>실시간 데이터가 필요한 경우에는 적합하지 않음
Next.js 예시<blockquote>
<pre><code>export async function getStaticProps() {
 return {
     props: { data },
     revalidate: 10, // 10초마다 데이터 재생성
 };
}</code></pre></blockquote>
</li>
</ol>
<hr>
<h2 id="ssr-server-side-rendering">SSR (Server-Side Rendering)</h2>
<h3 id="의미-5">의미</h3>
<p>서버에서 페이지에 html을 생성하고 클라이언트에게 전송하는 방식 입니다.</p>
<h3 id="작동-방식-1">작동 방식</h3>
<ol>
<li>사용자가 페이지를 요청합니다. </li>
<li>서버에서 필요한 데이터를 가져와 html을 생성합니다.</li>
<li>생성된 html을 클라이언트로 전송합니다.</li>
<li>클라이언트에서 JavaScrpit를 로드하여 인터렉티브 기능이 활성화 됩니다.<h3 id="장점-5">장점</h3>
</li>
<li>SEO에 매우 유리하다(검색 엔진이 완성된 html 을 크롤링이 가능합니다.)</li>
<li>초기 페이지 로드 속도가 빠릅니다.</li>
<li>메타 데이터 제공하기가 용이합니다.<h3 id="단점-5">단점</h3>
</li>
<li>서버 부하가 증가할 수 있습니다.</li>
<li>페이지 전환 시 전체 페이지를 다시 로드 해야 할 수 있습니다.</li>
<li>개발 학습 곡선이 큽니다.</li>
</ol>
<hr>
<h2 id="webpack과-rollup은-모두-javascrpit-모듈-번들러-입니다">Webpack과 Rollup은 모두 JavaScrpit 모듈 번들러 입니다.</h2>
<h3 id="웹에플리케이션의-자원을-최적화-하고-관리하는데-사용됩니다">웹에플리케이션의 자원을 최적화 하고 관리하는데 사용됩니다.</h3>
<hr>
<h3 id="webpack">Webpack</h3>
<h3 id="특징-2">특징</h3>
<ol>
<li>다양한 자원(JavaScrpit, CSS, img  등)을 모듈로 처리할 수 있음</li>
<li>코드 분활(Code Splitting)과 동적 이미지를 지원</li>
<li>Hot Module Replacement(HMR)를 지원하여 개발경험을 향상시킴<h3 id="장점-6">장점</h3>
</li>
<li>다양한 최적화된 옵션을 제공</li>
<li>복잡한 어플리케이션의 의존성 관리<h3 id="단점-6">단점</h3>
</li>
<li>설정이 복잡함</li>
<li>초기 빌드 시간이 상대적으로 김</li>
</ol>
<p><em><strong>Hot Module Replacement(HMR) = 웹 개발 과정에서 애플리케이션의 성능을 향상시키고 개발경험을 개선시키는 중요한 기능을 합니다.</strong></em></p>
<h3 id="장점-7">장점</h3>
<ol>
<li>상태유지 : 어플리케이션의 현재 상태를 유지한채 변경된 부분만 교체 됩니다.</li>
<li>개발속도향상 : 빠른 피드백을 통해 개발 효율성이 크게 향상 됩니다.</li>
</ol>
<hr>
<h2 id="rollup">Rollup</h2>
<h3 id="의미-6">의미</h3>
<p>경량화된 모듈 번들러. ES6 모듈 지원에 강점</p>
<h3 id="특징-3">특징</h3>
<ol>
<li>ES모듈의 초점을 맞춤</li>
<li>Tree Shaking을 효과적으로 수행하여 번들 크기를 최소화 합니다.</li>
<li>설정이 상대적으로 간단합니다.<h3 id="장점-8">장점</h3>
</li>
<li>더 작고 효율적인 번들을 생성합니다.</li>
<li>빠른 빌드 속도를 보여줍니다.</li>
</ol>
<p><em>*<em>Tree Shaking은 JavaScrpit개발에서 사용되지 않는 코드 DeadCode를 제거하여 최종 번들 크기를 줄이는 최적화된 기법 입니다. *</em></em>
기본원리 :  Tree Shaking은 어플리케이션 의존성 그래프를 분석하여 실제로 사용되지 않는 코드를 식별하고 제거 합니다.
작동방식 : ES6모듈 시스템의 정적 import와 export문을 활용하여 code의 사용여부를 확인합니다.
<img src="https://velog.velcdn.com/images/injung_p/post/db430e69-d96a-4299-b57c-e566a60cac96/image.png" alt=""></p>
<hr>
<h2 id="eslint">ESLint</h2>
<ul>
<li>JavaScript 코드의 문제점을 찾고 수정하는 데 도움을 주는 정적 분석 도구입니다.<h4 id="사용-이유">사용 이유</h4>
</li>
</ul>
<ol>
<li>코드의 일관성 유지 : 코드 스타일 가이드를 준수하여 일관성 있는 코드를 작성하도록 합니다.</li>
<li>버그 및 오류 방지 : 잠재적인 버그나 오류를 사전에 찾아내고 수정할 수 있도록 합니다.</li>
<li>팀 협업 강화 : 팀원 간에 코드 품질을 통일시켜 협업 효율을 높일 수 있습니다.<h4 id="주요-기능">주요 기능</h4>
</li>
<li>코드 스타일 검사 : 들여쓰기, 따옴표, 세미콜론(;) 등 스타일 규칙을 검사합니다.</li>
<li>오류 검사 : 잘못된 변수를 사용, 선언되지 않은 변수 사용 등 오류를 검출합니다.</li>
<li>경고 및 권고사항 : 최적화, 가독화를 향상 등을 위한 경고와 권고사항을 표시해줍니다.<h4 id="작동-원리">작동 원리</h4>
</li>
</ol>
<ul>
<li>ESLint는 코드 품질을 검사하는 &#39;두뇌파&#39; 역할을 하고, Prettier는 코드를 자동으로 포맷팅하는 &#39;행동파&#39; 역할을 합니다.</li>
<li>eslint-config-prettier는 ESLint와 Prettier 간의 충돌을 방지하여 Prettier의 포맷팅 규칙이 우선적으로 적용되도록 합니다.<h4 id="자동화-설정">자동화 설정</h4>
코드 저장 시 자동으로 포맷팅과 린팅이 적용되도록 설정되어 있어, 별도의 명령어 실행 없이도 일관된 코드 스타일을 유지할 수 있습니다. 이는 팀 프로젝트에서 특히 유용하며, 코드 품질과 일관성을 자동으로 유지할 수 있게 해줍니다.<h4 id="규칙">규칙</h4>
</li>
<li>off or 0 : 규칙을 해제하고 해당 규칙을 사용하지 않음</li>
<li>warn or 1 : 규칙을 경고로 설정하고 규칙을 강제하지는 않지만 경고만을 제공하기 위함</li>
<li>error or 2 : 규칙을 에러로 설정하고 통합 테스트, build, PR등의 경우에 오류를 발생시킴<h3 id="패키지-설치">패키지 설치</h3>
<pre><code>npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier</code></pre><h3 id="eslint-설정">ESLint 설정</h3>
</li>
<li>.eslintrc.json 파일을 프로젝트 루트에 생성합니다.<h4 id="규칙-값-설정">규칙 값 설정</h4>
<blockquote>
<pre><code>{
&quot;extends&quot;: [
  &quot;eslint:recommended&quot;,
  &quot;plugin:react/recommended&quot;
],
&quot;rules&quot;: {
  &quot;semi&quot;: [&quot;error&quot;, &quot;always&quot;],
  &quot;quotes&quot;: [&quot;error&quot;, &quot;single&quot;],
  &quot;no-console&quot;: &quot;warn&quot;,
  &quot;indent&quot;: [&quot;error&quot;, 2]
}
}</code></pre></blockquote>
</li>
</ul>
<h4 id="plugin-추가">Plugin 추가</h4>
<blockquote>
<pre><code>{
  &quot;plugins&quot;: [&quot;prettier&quot;, &quot;@typescript-eslint&quot;, &quot;react&quot;],
  &quot;extends&quot;: [&quot;plugin:prettier/recommended&quot;]
}</code></pre></blockquote>
<h4 id="실행-환경-설정">실행 환경 설정</h4>
<blockquote>
<pre><code>{
  &quot;env&quot;: {
    &quot;browser&quot;: true,
    &quot;es2021&quot;: true
  },
  &quot;parserOptions&quot;: {
    &quot;ecmaVersion&quot;: 12,
    &quot;sourceType&quot;: &quot;module&quot;
  }
}</code></pre></blockquote>
<h3 id="vite에서-eslintconfigjs파일-설정">vite에서 eslint.config.js파일 설정</h3>
<blockquote>
<pre><code>export default [
  { ignores: [&quot;dist&quot;] },
  {
    files: [&quot;*/.{js,jsx}&quot;],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        ecmaVersion: &quot;latest&quot;,
        ecmaFeatures: { jsx: true },
        sourceType: &quot;module&quot;,
      },
    },
    settings: { 
      react: { version: &quot;18.3&quot; },
      prettier: {
        printWidth: 100,
        tabWidth: 2,
        useTabs: false,
        semi: true,
        singleQuote: true,
        trailingComma: &quot;es5&quot;,
        bracketSpacing: true,
        jsxBracketSameLine: false,
        arrowParens: &quot;avoid&quot;
      }
    },
    plugins: {
      react,
      &quot;react-hooks&quot;: reactHooks,
      &quot;react-refresh&quot;: reactRefresh,
      prettier: prettier
    },
    rules: {
      ...js.configs.recommended.rules,
      ...react.configs.recommended.rules,
      ...react.configs[&quot;jsx-runtime&quot;].rules,
      ...reactHooks.configs.recommended.rules,
      ...eslintConfigPrettier.rules,
      &quot;react/jsx-no-target-blank&quot;: &quot;off&quot;,
      &quot;react-refresh/only-export-components&quot;: [&quot;warn&quot;, { allowConstantExport: true }],
      &quot;prettier/prettier&quot;: [&quot;error&quot;],
      &quot;arrow-body-style&quot;: &quot;off&quot;,
      &quot;prefer-arrow-callback&quot;: &quot;off&quot;
    },
  },
];</code></pre></blockquote>
<h3 id="prettier-설정">Prettier 설정</h3>
<ul>
<li>파일 생성 : .prettierrc<blockquote>
<pre><code>{
&quot;printWidth&quot;: 100,
&quot;tabWidth&quot;: 2,
&quot;useTabs&quot;: false,
&quot;semi&quot;: true,
&quot;singleQuote&quot;: false,
&quot;trailingComma&quot;: &quot;es5&quot;,
&quot;bracketSpacing&quot;: true,
&quot;jsxBracketSameLine&quot;: false,
&quot;arrowParens&quot;: &quot;avoid&quot;
}</code></pre></blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Lifecycle(리액트 생애주기 = 생명주기)]]></title>
            <link>https://velog.io/@injung_p/React-Lifecycle</link>
            <guid>https://velog.io/@injung_p/React-Lifecycle</guid>
            <pubDate>Wed, 20 Nov 2024 14:00:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/injung_p/post/07615ab6-7a6e-4c32-9af3-b843bb61d02b/image.png" alt=""></p>
<h2 id="리액트-생애주기--생명주기--lifecycle-">리액트 생애주기( = 생명주기 / Lifecycle )</h2>
<blockquote>
<p>우리가 생애주기를 배우는 이유에 대해서 저는 이렇게 생각합니다.
리액트의 생명주기를 이해하고 적절이 활용하면, 컴포넌트의 동작을 효과적으로 제어하고 최적화 할 수 있습니다.
특히, 데이터 fetching, 이벤트리스너 등록 및 해제, 애니메이션 처리에 유용하게 사용할 수 있습니다.</p>
</blockquote>
<p>리액트 컴포넌트 생명주기는 컴포넌트가 생성되고 업데이트가 되며, 제거되는 과정을 말합니다.
이러한 생명주기의 가장 중요한 3가지는 생성(Mounting) -&gt; 업데이트(Updating) -&gt; 제거(Unmounting) 순서로 진행됩니다.
리액트 함수형 컴포넌트와 Hook을 사용하여 생명주기를 관리합니다.</p>
<h4 id="마운팅mounting">마운팅(Mounting)</h4>
<p>마운팅 단계는 컴포넌트가 DOM에 처음 삽입될 때 발생하는 단계 입니다.
마운팅 단계에서 중요한 메서드는 componentDidMount입니다.
해당 메서드는 컴포넌트가 DOM에 삽입된 직후에 호출되기 때문에 아래와 같은 역할을 수행합니다.</p>
<ol>
<li>외부 데이터 로딩 : api 호출이나, 데이터 fetching할 때 적합한 단계 입니다.</li>
<li>DOM 조작 : 컴포넌트가 렌더링 된 후에 DOM에 직접 접근해야 하는 작업을 수행할 수 있습니다.</li>
<li>이벤트리스너 등록 : 필요한 이벤트리스너를 설정할 수 있습니다.</li>
</ol>
<p>** ★ 마운팅 단계에서의 componentDidMount는 컴포넌트 생명주기에서 딱 한번만 호출되므로 초기 설정이나, 한번만 실행되는 경우에 이상적입니다. **
** ★ 해당 메서드 안에서는 setState를 호출하여 컴포넌트의 상태를 업데이트 할 수 있습니다.
이는 추가적인 렌더링을 trigger 하지만, 브라우저가 화면을 업데이트하기 전에 발생합니다. **</p>
<ul>
<li><p>constructor
컴포넌트의 초기단계를 설정하고, 이벤트 핸들러를 바인딩하는 단계</p>
<ul>
<li>props 초기화 : props를 호출하여 부모의 constructor를 실행하고, props를 사용할 수 있게 합니다.</li>
</ul>
</li>
<li><p>getDerivedStateFromProps
props로부터 파생된 state를 가져옴
즉, props로 받아온 것을 state에 넣어주고 싶을때 사용</p>
</li>
<li><p>render
컴포넌트의 ui를 랜더링하는 과정( = 단계 )</p>
</li>
</ul>
<ol>
<li>render 메서드는 컴포넌트의 ui를 정의합니다.</li>
<li>해당 메서드는 React Element를 반환하여 컴포넌트가 어떻게 보여지는지를 설명합니다.</li>
<li>가상 DOM 생성 : render가 반환한 React Element 기반으로 가상 DOM을 생성합니다. 이는 실제 DOM에 변경사항을 적용하기 전에 메모리상에서 ui를 표현하는 과정입니다.</li>
</ol>
<ul>
<li>componentDidMount
컴포넌트가 DOM에 삽입된 직후 호출합니다.
외부 데이터를 불러오거나 DOM 조작을 수행하기 적합한 상태 입니다.<pre><code>useEffect(()=&gt;{
  console.log(&quot;componentDidMount&quot;);     
},[])</code></pre></li>
</ul>
<h4 id="업데이트updating">업데이트(Updating)</h4>
<p>컴포넌트 props나 state가 변경될 때 발생하는 단계 입니다.</p>
<ul>
<li>shouldComponentUpdate
컴포넌트가 re-rendering 여부를 결정하는 단계 입니다.</li>
</ul>
<ol>
<li>성능 최적화 : 해당 메서드는 불필요한 rendering을 방지하여 성능을 향상시킵니다.</li>
<li>렌더링 제어 : props나 state가 변경될때 다시 렌더링이 되어야하는지 여부를 결정합니다. </li>
</ol>
<ul>
<li><p>render
변경된 상태나 속성을 반영하여, ui를 다시 렌더링 하는 단계 입니다.</p>
</li>
<li><p>componentDidUpdate
컴포넌트가 완료된 후 호출 됩니다.
DOM 조작이나, 네트워크 요청을 수행할 수 있습니다.</p>
</li>
</ul>
<ol>
<li>호출 시점 : 컴포넌트가 re-rendering 된 직후 즉시 호출 됩니다.<ul>
<li>초기 렌더링에서는 호출되지 않습니다.</li>
</ul>
</li>
<li>네트워크 요청 : props나 state의 변경에 따라 새로운 데이터를 가져와야 할 때 사용할 수 있습니다.</li>
<li>조건부 실행 : 특정 props나 state가 변경되었을때만 작업을 허용할 수 있도록 조건을 설정할 수 있습니다.</li>
<li>setState 사용 : 해당 메서드 안에서 setState를 호출 할 수 있지만 반드시 조건문을 사용하여야 합니다. 만약 그렇지 않으면 무한 루프에 빠질 수 있습니다.<pre><code>useEffect(() =&gt; {
 console.log(&quot;count or exampleProp changed&quot;);     
},[count, exampleProp]);</code></pre></li>
</ol>
<h4 id="언마운팅unmounting">언마운팅(Unmounting)</h4>
<p>언마운팅 단계는 컴포넌트가 DOM에서 제거될 때 발생하는 단계 입니다.</p>
<ul>
<li>componentWillUnmount
컴포넌트가 화면에서 사라지기 직전에 호출 됩니다.
여기서 주로 DOM에 직접 등록했었던 이벤트를 제거하고, 만약에 외부 라이브러리를 사용한게 있고 해당 라이브러리에 dispose기능이 있다면 여기서 수행 합니다.</li>
</ul>
<ol>
<li>메모리 누수 방지 : 컴포넌트가 생성한 리소스를 해제하여 메모리 누수를 방지합니다.</li>
<li>이벤트 리스너 제거 : 컴포넌트에서 등록한 전역 이벤트 리스너를 제거합니다.</li>
<li>네트워크 요청 취소 : 진행중인 비동기 네트워크 요청을 취소합니다.</li>
<li>외부 라이브러리 정리 : 컴포넌트에서 사용한 외부 라이브러리 인스턴스를 정리합니다.<pre><code>useEffect(()=&gt;{
 console.log(&quot;&quot;);     
 return(() =&gt; exampleAPI.unsubscribe());
})</code></pre></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript로 간단한 스톱워치 구현하기⏱️]]></title>
            <link>https://velog.io/@injung_p/JavaScript%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%8A%A4%ED%86%B1%EC%9B%8C%EC%B9%98-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@injung_p/JavaScript%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%8A%A4%ED%86%B1%EC%9B%8C%EC%B9%98-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 18 Nov 2024 13:47:33 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>안녕하세요! 간단하지만 유용한 JavaScript 실습을 진행해보겠습니다.
GitHub에서 JavaScript 스톱워치 실습을 살펴보고, 
주요 코드를 분석하며 어떻게 동작하는지 알아보겠습니다.</p>
</blockquote>
<h4 id="1-목표">1. 목표</h4>
<p>이 실습은 HTML, CSS, 그리고 JavaScript만을 사용하여 간단한 스톱워치를 구현한 예제입니다. 실습을 통해 다음을 배울 수 있습니다.</p>
<ol>
<li>JavaScript로 시간 측정 및 업데이트하는 방법</li>
<li>DOM 조작을 통한 동적인 UI 업데이트</li>
<li>기본적인 이벤트 핸들링과 setInterval 활용</li>
</ol>
<h4 id="2-전체-코드-구조">2. 전체 코드 구조</h4>
<p>구조는 아주 간단합니다.</p>
<pre><code>.
├── app.js // 기능 로직(JS)
├── style.css // 간단한 스타일
└── index.html // 전체 레이아웃(HTML)</code></pre><p>각 파일의 주요 내용은 다음과 같습니다.</p>
<h4 id="21-indexhtmlhtml">2.1. index.html(HTML)</h4>
<blockquote>
<pre><code></code></pre></blockquote>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
    <title>Digital Clock | JS</title>
  </head>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <main>
    <h1>Stop Watch</h1>
    <!-- 시간 표시 영역 -->
    <div class="timeDisplay">00 : 00 : 00 : 000</div>
    <!-- 버튼 영역 -->
    <div class="btn">
      <button id="startTimer">Start</button>
      <button id="stopTimer">Stop</button>
      <button id="resetTimer">Reset</button>
    </div>
  </main>
  <script src="script.js"></script>
</body>
</html>

<pre><code>HTML은 간단한 타이머 화면과 버튼으로 구성되어 있습니다. 
id를 활용해 버튼을 제어합니다.

2. CSS</code></pre><p>.stopwatch {
  text-align: center;
  font-family: Arial, sans-serif;
}
h1 {
  font-size: 48px;
  margin-bottom: 20px;
}
button {
  margin: 5px;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
}</p>
<pre><code>스타일링은 매우 심플하지만, 보기 좋은 UI를 제공합니다.

3. JavaScript
- 시간 계산 및 DOM 업데이트</code></pre><p>let timer;
let seconds = 0;</p>
<p>function formatTime(sec) {
  const hrs = Math.floor(sec / 3600);
  const mins = Math.floor((sec % 3600) / 60);
  const secs = sec % 60;
  return <code>${hrs.toString().padStart(2, &#39;0&#39;)}:${mins.toString().padStart(2, &#39;0&#39;)}:${secs.toString().padStart(2, &#39;0&#39;)}</code>;
}</p>
<p>function updateDisplay() {
  document.querySelector(&#39;h1&#39;).innerText = formatTime(seconds);
}</p>
<pre><code>    - formatTime : 초 단위로 시간을 입력받아 HH:MM:SS 형식으로 변환
    - updateDisplay : DOM의 h1 태그를 업데이트
- 버튼 이벤트 핸들링</code></pre><p>document.getElementById(&#39;start&#39;).addEventListener(&#39;click&#39;, () =&gt; {
  if (!timer) {
    timer = setInterval(() =&gt; {
      seconds++;
      updateDisplay();
    }, 1000);
  }
});</p>
<p>document.getElementById(&#39;reset&#39;).addEventListener(&#39;click&#39;, () =&gt; {
  clearInterval(timer);
  timer = null;
  seconds = 0;
  updateDisplay();
});</p>
<pre><code>- Start 버튼 : setInterval로 1초마다 카운트 증가
- Reset 버튼 : 타이머 초기화

#### 동작 화면
프로젝트를 로컬에 실행해보면 아래와 같은 동작을 확인할 수 있습니다.
![](https://velog.velcdn.com/images/injung_p/post/aa9d8172-95e2-459d-bbc9-4abc245075f0/image.gif)
- Start 버튼 클릭 : 시간이 시작됩니다.
- Reset 버튼 클릭 : 타이머가 00:00:00으로 초기화됩니다.

#### 직접 실행해보기
GitHub 저장소에서 프로젝트를 클론합니다.</code></pre><p>git clone <a href="https://github.com/InJungPark/js-stopwatch.git">https://github.com/InJungPark/js-stopwatch.git</a>
cd js-stopwatch</p>
<p>```
브라우저에서 index.html 파일을 열어 실행합니다.</p>
<h4 id="마치며">마치며</h4>
<p>이 스톱워치 실습은 JavaScript의 기초를 배우고 DOM 조작 및 시간 관리 로직을 익히기에 좋은 예제입니다. 간단한 구조이지만, 다양한 활용 가능성을 생각해볼 수 있는 실습이라고 생각합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript로 간단한 QR 코드 생성기 만들기 (goqr.me API 활용)]]></title>
            <link>https://velog.io/@injung_p/JavaScript%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-QR-%EC%BD%94%EB%93%9C-%EC%83%9D%EC%84%B1%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-goqr.me-API-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@injung_p/JavaScript%EB%A1%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-QR-%EC%BD%94%EB%93%9C-%EC%83%9D%EC%84%B1%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-goqr.me-API-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Tue, 05 Nov 2024 14:55:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이번 포스팅에서는 자바스크립트와 goqr.me API를 활용해 간단한 QR 코드 생성기를 만들어보는 실습을 소개합니다. 
QR 코드는 일상생활에서 많이 접할 수 있는 2차원 바코드 형태로, 손쉽게 정보를 전달할 수 있는 장점이 있습니다. 
이 프로젝트를 통해 QR 코드가 어떻게 만들어지는지, 그리고 JavaScript, HTML, CSS를 사용하면 별도의 복잡한 라이브러리를 쓰지 않고도 손쉽게 QR 코드를 생성할 수 있습니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/injung_p/post/83ab464e-248b-4cc9-ad8b-99f85cf901c2/image.png" alt=""></p>
<h3 id="1-실습-개요">1. 실습 개요</h3>
<ul>
<li>사용 API : <a href="https://goqr.me/api/">goqr.me의 QR 코드 생성 API</a></li>
<li>GitHub Link : <a href="https://github.com/InJungPark/js-qr-basic">https://github.com/InJungPark/js-qr-basic</a></li>
<li>기본 원리 :</li>
</ul>
<ol>
<li>사용자가 입력한 텍스트를 API에 쿼리 파라미터로 전송</li>
<li>생성된 QR 코드 이미지를 <img> 태그에 표시</li>
</ol>
<ul>
<li>추가 기능 :<ul>
<li>Enter 키로도 생성 가능</li>
<li>텍스트가 비어 있을 때 에러 애니메이션(흔들기) 및 빨간색 테두리 표시</li>
</ul>
</li>
</ul>
<h3 id="2-전체-코드-구조">2. 전체 코드 구조</h3>
<p>구조는 아주 간단합니다.</p>
<pre><code>.
├─ index.html  // HTML 구조
├─ style.css   // 간단한 스타일
└─ app.js      // JS 로직</code></pre><p>각 파일의 주요 내용은 다음과 같습니다.</p>
<h3 id="21-html-indexhtml">2.1. HTML (index.html)</h3>
<pre><code>&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;title&gt;QR Code&lt;/title&gt;
  &lt;link href=&quot;style.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div class=&quot;container&quot;&gt;
    &lt;p&gt;TEXT &amp; URL&lt;/p&gt;
    &lt;input type=&quot;text&quot; id=&quot;qrText&quot; placeholder=&quot;text or url&quot; autofocus=&quot;true&quot; /&gt;
    &lt;div id=&quot;qrImgBox&quot; class=&quot;imgContainer&quot;&gt;
      &lt;img id=&quot;qrImg&quot; src=&quot;&quot; alt=&quot;qr img&quot; aria-label=&quot;QR 이미지 입니다.&quot; draggable=&quot;false&quot; /&gt;
    &lt;/div&gt;
    &lt;button&gt;QR Code Creation&lt;/button&gt;
  &lt;/div&gt;
  &lt;script src=&quot;app.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><ul>
<li><code>input</code>에 사용자가 QR 코드로 만들 문자열 또는 URL을 입력</li>
<li><code>#qrImgBox</code> 영역에 API로부터 받은 QR 코드 이미지를 출력할 <code>&lt;img&gt;</code> 배치</li>
<li>button 클릭 시 또는 Enter 키 입력 시 QR 코드 생성<h3 id="22-css-stylecss">2.2. CSS (style.css)</h3>
```</li>
<li>{
margin: 0;
padding: 0;
font-family: sans-serif;
box-sizing: border-box;
}</li>
</ul>
<p>body {
  background: black;
}</p>
<p>.container {
  background: lightgray;
  width: 60%;
  padding: 25px 35px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  position: absolute;
  border-radius: 20px;
}</p>
<p>.container p {
  font-weight: 600;
  font-size: 1.6rem;
  margin-bottom: 6px;
  text-align: center;
}</p>
<p>.container input {
  width: 100%;
  height: 50px;
  border: 1px solid #102a42;
  outline: 0;
  padding: 10px;
  margin: 10px 0 20px;
  border-radius: 10px;
  font-size: 1.2rem;
}</p>
<p>.container input.error-input {
  border-color: red;
}</p>
<p>.container button {
  width: 100%;
  height: 50px;
  border-radius: 10px;
  outline: 0;
  border: 0;
  background: white;
  color: cadetblue;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.6);
  cursor: pointer;
  margin: 10px 0;
  font-weight: 500;
  font-size: 1.2rem;
}</p>
<p>.container button:hover {
  background: #b2d8b6;
  color: #3b3b3b;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.3);
}</p>
<p>.imgContainer {
  width: 200px;
  border-radius: 5px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.8s;
}</p>
<p>.imgContainer img {
  width: 100%;
  padding: 10px;
}</p>
<p>.imgContainer.showImg {
  max-height: 300px;
  margin: 10px auto;
  border: 1px solid #b2d8b6;
}</p>
<p>/* 흔들리는 애니메이션 */
.error {
  animation: shake 0.1s linear 10;
}</p>
<p>@keyframes shake {
  0% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-2px);
  }
  50% {
    transform: translateX(0);
  }
  75% {
    transform: translateX(2px);
  }
  100% {
    transform: translateX(0);
  }
}</p>
<pre><code>- `.error-input` 클래스를 추가해 에러 시 빨간 테두리를 표시
- `.error` 애니메이션이 흔들리는 효과를 구현
- `.showImg`를 통해 QR 코드가 생성될 때 이미지 컨테이너의 최대 높이를 늘려 부드럽게 노출
### 2.3. JS (app.js)</code></pre><p>// 변수 선언
const qrText = document.getElementById(&quot;qrText&quot;);
const qrImg = document.getElementById(&quot;qrImg&quot;);
const qrImgBox = document.getElementById(&quot;qrImgBox&quot;);
const generateButton = document.querySelector(&quot;button&quot;);</p>
<p>// Error 보여주기
const showError = () =&gt; {
  qrText.classList.add(&quot;error-input&quot;);
  qrText.classList.add(&quot;error&quot;);
};</p>
<p>// Error 제거하기
const removeError = () =&gt; {
  qrText.classList.remove(&quot;error-input&quot;);
  qrText.classList.remove(&quot;error&quot;);
};</p>
<p>// QR Code 생성 함수
const generateQRCode = () =&gt; {
  if (qrText.value.length &gt; 0) {
    // goqr.me API에서 제공되는 QR 코드 생성 URL
    // data 파라미터에 입력값을 넣어주면 자동으로 QR 코드 생성
    qrImg.src = <code>https://api.qrserver.com/v1/create-qr-code/?size=150x150&amp;data=${qrText.value}</code>;</p>
<pre><code>// 이미지 보여주기
qrImgBox.classList.add(&quot;showImg&quot;);
removeError();</code></pre><p>  } else {
    // 텍스트가 비어 있을 때 에러 표시
    showError();
  }
};</p>
<p>// 버튼 클릭 시 생성
generateButton.addEventListener(&quot;click&quot;, generateQRCode);</p>
<p>// input 입력 시 에러 제거
qrText.addEventListener(&quot;input&quot;, () =&gt; {
  if (qrText.value.length &gt; 0) {
    removeError();
  }
});</p>
<p>// input에서 Enter 키를 누르면 QR 코드 생성
qrText.addEventListener(&quot;keydown&quot;, (event) =&gt; {
  if (event.key === &quot;Enter&quot;) {
    generateQRCode();
  }
});</p>
<p>```</p>
<h3 id="동작원리">동작원리</h3>
<h4 id="1-showerror">1. showError()</h4>
<ul>
<li><code>input</code>에 <code>error-input</code> 클래스를 붙여 빨간색 테두리 표시</li>
<li><code>error</code> 클래스로 흔들리는 애니메이션 부여<h4 id="2-removeerror">2. <code>removeError()</code></h4>
</li>
<li>에러 상태(빨간 테두리, 흔들림)를 제거<h4 id="3-generateqrcode">3. <code>generateQRCode()</code></h4>
</li>
<li><code>qrText</code>의 값이 있을 경우,<ul>
<li>QR 코드 API URL에 <code>data</code> 파라미터로 텍스트를 넣고,</li>
<li><code>&lt;img&gt;</code> 태그의 <code>src</code> 속성을 이 URL로 설정</li>
</ul>
</li>
<li>비어 있을 경우 showError()로 에러 표시<h4 id="3-실행-방법">3. 실행 방법</h4>
</li>
</ul>
<ol>
<li>프로젝트 다운로드 혹은 폴더 생성</li>
<li><code>index.html</code>, <code>style.css</code>, <code>app.js</code>를 위와 같이 구성</li>
<li>브라우저에서 <code>index.html</code>을 열기</li>
<li>텍스트 혹은 URL을 입력하고 &quot;QR Code Creation&quot; 버튼을 클릭하거나 Enter 키를 눌러 QR 코드 생성<h4 id="4-추가로-해볼-만한-것들">4. 추가로 해볼 만한 것들</h4>
</li>
<li>QR 코드 크기 조절</li>
</ol>
<ul>
<li><code>?size=150x150</code> 부분을 원하는 크기로 수정 (예: <code>200x200</code>, <code>300x300</code> 등)</li>
</ul>
<ol start="2">
<li>에러 보정 레벨 변경</li>
</ol>
<ul>
<li>goqr API 문서를 참고해 ECLevel(에러 보정률) 등을 변경하여 다양한 옵션 시도</li>
</ul>
<ol start="3">
<li>QR 이미지 다운로드 기능</li>
</ol>
<ul>
<li><code>&lt;img&gt;</code> 태그에 표시된 QR 코드를 마우스 오른쪽 클릭 → “이미지 저장”</li>
<li>좀 더 편리하게 ‘다운로드 버튼’을 만들어 <code>canvas</code>나 Blob 형태로 다운로드받도록 구현 가능</li>
</ul>
<ol start="4">
<li>자동 생성</li>
</ol>
<ul>
<li>버튼 클릭 없이 입력이 바뀔 때마다 자동으로 QR 이미지를 업데이트하도록 적용 가능<h4 id="5-마무리">5. 마무리</h4>
이렇게 goqr.me API를 통해 아주 간단하게 QR 코드를 생성해볼 수 있습니다.
HTML &amp; CSS를 이용해 스타일링하고, 자바스크립트로 API 호출 후 <code>&lt;img&gt;</code>에 표시하기만 하면 되는 매우 직관적인 방법입니다.</li>
<li>텍스트가 비어 있을 때 에러를 주는 부분이나,</li>
<li>이미지를 천천히 나타내는 애니메이션 효과,</li>
<li>Enter 키로도 동작하도록 만드는 디테일 등이 사용자 경험을 높여줍니다.</li>
</ul>
<p>원리를 이해했다면, 더 나아가 스캔(Decoding) 기능까지 구현하거나, QR 코드 생성/다운로드/공유 등을 통합한 다양한 프로젝트를 시도해볼 수도 있습니다.</p>
<p>궁금한 점이나 개선 아이디어가 있다면 언제든 댓글로 남겨주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기초 실습 : Counter 기능 구현하기]]></title>
            <link>https://velog.io/@injung_p/JavaScript-%EA%B8%B0%EC%B4%88-%EC%8B%A4%EC%8A%B5-Counter-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@injung_p/JavaScript-%EA%B8%B0%EC%B4%88-%EC%8B%A4%EC%8A%B5-Counter-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 03 Nov 2024 16:51:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/injung_p/post/99a54b94-1d61-4f48-a0f0-26e7c1bde80f/image.png" alt=""></p>
<blockquote>
<p>JavaScript 학습의 기본기를 다지기 위해 js-counter-basics 실습을 진행하였습니다. 
이번 글에서는 HTML, CSS, JavaScript의 연동을 통해 간단한 카운터 기능을 구현한 과정과 배운 점을 공유하고자 합니다.</p>
</blockquote>
<h2 id="실습-개요">실습 개요</h2>
<ul>
<li>폴더 이름 : js-counter-basics</li>
<li>GitHub Link : <a href="https://github.com/InJungPark/js-counter-basic">https://github.com/InJungPark/js-counter-basic</a></li>
</ul>
<p>이번 실습은 JavaScript의 기본 문법과 HTML, CSS와의 연동에 중점을 두었습니다. 카운터를 구현하는 과정에서 JavaScript의 이벤트 처리, DOM 조작 방법, 그리고 스타일링의 중요성을 이해하는 데 도움이 되었습니다.</p>
<h3 id="1-무엇을-만들었나">1. 무엇을 만들었나?</h3>
<ul>
<li>버튼(Decrease, Reset, Increase)을 클릭할 때마다 숫자가 증감하거나 리셋되는 기능</li>
<li>숫자가 음수/양수/0인지에 따라 텍스트 색상을 다르게 보여주는 기능</li>
</ul>
<p>이 기능들은 자바스크립트 DOM 조작과 이벤트 바인딩을 연습하기에 매우 좋은 예제입니다.</p>
<h3 id="2-html구조indexhtml">2. HTML구조(index.html)</h3>
<p>먼저, 아래와 같은 간단한 HTML 구조가 필요합니다.</p>
<ul>
<li><p>id=&quot;value&quot;를 가진 요소에 현재 카운트 값을 표시</p>
</li>
<li><p>.btn 클래스를 가진 버튼 3개 (각각 id=&quot;decrease&quot;, id=&quot;reset&quot;, id=&quot;increase&quot;)</p>
<pre><code>&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot; /&gt;
&lt;title&gt;JS Counter&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;!-- 숫자를 표시할 영역 --&gt;
&lt;span id=&quot;value&quot;&gt;0&lt;/span&gt;

&lt;!-- 숫자를 조작할 버튼들 --&gt;
&lt;button id=&quot;decrease&quot; class=&quot;btn&quot;&gt;Decrease&lt;/button&gt;
&lt;button id=&quot;reset&quot; class=&quot;btn&quot;&gt;Reset&lt;/button&gt;
&lt;button id=&quot;increase&quot; class=&quot;btn&quot;&gt;Increase&lt;/button&gt;

&lt;!-- JS 파일 연결 --&gt;
&lt;script src=&quot;script.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></li>
</ul>
<pre><code>HTML에서는 크게 어려운 부분이 없으며, #value로 카운트 표시, 3개의 버튼으로 카운트 조작을 수행합니다.
### 2. CSS(style.css)
아래는 예시 CSS입니다. 자유롭게 스타일링하시면 됩니다.</code></pre><p>body {
  font-family: sans-serif;
  text-align: center;
  margin-top: 50px;
}</p>
<p>#value {
  display: block;
  font-size: 3rem;
  margin-bottom: 20px;
}</p>
<p>.btn {
  margin: 0 10px;
  padding: 10px 20px;
  cursor: pointer;
  font-size: 1rem;
}</p>
<pre><code>- 중앙 정렬, 글자 크기, 버튼 스타일 정도만 지정해도 충분히 깔끔하게 만들 수 있습니다.
### 3. JavaScrpit(app.js)
이제 app.js 파일에 핵심 로직을 작성합니다.
버튼을 클릭할 때마다 숫자를 증감/리셋하고, 그 값에 따라 색상을 바꾸도록 구현해 보겠습니다.</code></pre><p>let count = 0;</p>
<p>const value = document.querySelector(&quot;#value&quot;);
const btns = document.querySelectorAll(&quot;.btn&quot;);</p>
<p>// 필요한 경우 콘솔에서 제대로 선택됐는지 확인
// console.log(&quot;btns 확인 : &quot;, btns);</p>
<p>btns.forEach((button) =&gt; {
  button.addEventListener(&quot;click&quot;, (event) =&gt; {
    // 클릭된 버튼의 id 확인
    // console.log(&quot;event 확인 : &quot;, event);</p>
<pre><code>let btnElementID = event.currentTarget.id;

if (btnElementID === &quot;decrease&quot;) {
  count--;
} else if (btnElementID === &quot;reset&quot;) {
  count = 0;
} else {
  count++;
}

// count 값에 따라 텍스트 색상 변화
if (count &gt; 0) {
  value.style.color = &quot;blue&quot;;
} else if (count &lt; 0) {
  value.style.color = &quot;red&quot;;
} else {
  value.style.color = &quot;black&quot;;
}

// 화면에 카운트 값 표시
value.textContent = count;</code></pre><p>  });
});</p>
<p>```</p>
<h4 id="코드-해석">코드 해석</h4>
<ol>
<li>변수 count : 현재 카운트 상태를 담는 전역 변수.</li>
<li>DOM 선택</li>
</ol>
<ul>
<li>#value : 카운트가 표시될 <span></li>
<li>.btn : 세 개의 버튼(Decrease, Reset, Increase)</li>
</ul>
<ol start="3">
<li>이벤트 바인딩 :</li>
</ol>
<ul>
<li>forEach로 각 버튼에 click 이벤트를 등록.</li>
<li>클릭된 버튼의 id에 따라 count를 감소, 초기화, 증가합니다.</li>
</ul>
<ol start="4">
<li>색상 변경 :</li>
</ol>
<ul>
<li>count가 0보다 큰지/작은지/같은지에 따라 각각 &#39;blue&#39;, &#39;red&#39;, &#39;black&#39;을 적용.</li>
</ul>
<ol start="5">
<li>DOM 업데이트 :</li>
</ol>
<ul>
<li>마지막에 value.textContent = count로 DOM에 반영.</li>
</ul>
<hr>
<h3 id="주요-기능-및-설명">주요 기능 및 설명</h3>
<h4 id="1-카운터-증가감소-기능-구현">1. 카운터 증가/감소 기능 구현</h4>
<p>버튼(Decrease, Reset, Increase)을 클릭할 때마다 카운트 값이 증가하거나 감소하도록 이벤트를 연결했습니다.</p>
<ul>
<li>count 변수를 통해 숫자를 관리하고, 버튼 click 이벤트가 발생하면 해당 로직에 따라 count를 증감 또는 리셋합니다.</li>
<li>JavaScript 이벤트 처리와 DOM 조작 방식을 간단히 익히기 좋았습니다.<h4 id="2-실시간-화면-업데이트">2. 실시간 화면 업데이트</h4>
값이 변경될 때마다 textContent를 통해 즉시 화면에 반영했습니다.</li>
<li>사용자가 버튼을 누르는 즉시 숫자가 변하고, 조건에 따라 색상이 바뀌는 동적 웹 페이지 동작을 체험할 수 있었습니다.</li>
<li>이 과정을 통해 DOM 갱신 원리를 자연스럽게 학습했습니다.<h3 id="구현-과정에서-어려웠던-점">구현 과정에서 어려웠던 점</h3>
<h4 id="1-이벤트-리스너-이해">1. 이벤트 리스너 이해</h4>
addEventListener로 버튼마다 click 이벤트를 연결하는 방식 자체는 알고 있었지만,</li>
<li>어떤 버튼이 클릭되었는지 식별하기 위해 event.currentTarget.id를 사용하고,</li>
<li>조건문(if-else)으로 카운트 로직을 분기하는 과정에서 초기에 헷갈리는 부분이 있었습니다.</li>
</ul>
<p>하지만 반복 연습을 통해 훨씬 간결하고 직관적으로 코드를 작성할 수 있었습니다.</p>
<h4 id="2-dom-조작과-변수-사용">2. DOM 조작과 변수 사용</h4>
<p>HTML 요소를 자바스크립트로 선택(document.querySelector 등)하고, 그 내용을 .textContent로 바꿔주는 과정이 처음에는 낯설었습니다.</p>
<ul>
<li>count 변수를 통해 숫자 상태를 관리하고, 이를 HTML 요소에 반영하는 흐름을 명확하게 이해하게 되었습니다.</li>
<li>특히 요소 선택(getElementById, querySelector)과 변수 업데이트(count++ 등)의 중요성을 실감했습니다.<h3 id="실습을-통해-배운-점">실습을 통해 배운 점</h3>
<h4 id="1-javascript-기본-문법">1. JavaScript 기본 문법</h4>
</li>
<li>변수 선언, 조건문, 함수, 이벤트 처리 등 기초를 실전 예제로 복습할 수 있었습니다.<h4 id="2-html-css-javascript의-연동-방식">2. HTML, CSS, JavaScript의 연동 방식</h4>
</li>
<li>HTML로 구조를 만들고, CSS로 스타일을 입힌 뒤, JavaScript로 동작을 추가하는 전형적인 웹 개발 흐름을 다시금 정리하게 되었습니다.</li>
<li>각각의 역할이 다르며, 이 조합으로 인터랙티브한 페이지를 만들 수 있다는 점이 인상 깊었습니다.<h4 id="3-사용자-인터페이스-고려">3. 사용자 인터페이스 고려</h4>
</li>
<li>버튼 클릭 시 즉시 숫자가 변하고 색상도 달라지므로, 사용자에게 직관적이고 즉각적인 피드백을 제공합니다.</li>
<li>비록 간단한 예제지만, “빠른 피드백”이 사용자 경험에 얼마나 중요한지 깨달았습니다.<h3 id="확장-아이디어">확장 아이디어</h3>
<h4 id="1-로컬-스토리지-연동">1. 로컬 스토리지 연동</h4>
</li>
<li>새로고침 후에도 카운트 값이 유지되도록 localStorage에 저장/불러오기 기능을 구현해볼 수 있습니다.<h4 id="2-버튼-애니메이션">2. 버튼 애니메이션</h4>
</li>
<li>클릭 시 버튼에 가벼운 애니메이션(색상 변화나 스케일 변화 등)을 추가해 UX를 개선할 수 있습니다.<h4 id="3-사용자-입력">3. 사용자 입력</h4>
</li>
<li>매 클릭마다 1씩 증가/감소하는 대신, 사용자가 설정한 값을 한 번에 증감하는 옵션을 추가해볼 수도 있습니다.<h3 id="마무리-및-향후-학습-계획">마무리 및 향후 학습 계획</h3>
이번 실습을 통해 자바스크립트로 DOM을 제어하고 이벤트 리스너를 활용하는 기본기를 확실히 다질 수 있었습니다.
이 다음에는 특정 숫자에 도달했을 때 애니메이션이나 배경색 변화 등 보다 다양한 기능을 붙여보면서, 사용자 경험을 강화하는 방법을 더 탐구할 계획입니다.
짧은 예제지만, 앞으로 웹 애플리케이션을 만들 때 필요한 사고방식(상태 관리, 화면 업데이트, 이벤트 처리) 등을 배울 수 있어 매우 유익했습니다.</li>
</ul>
<p>궁금한 점이나 더 좋은 아이디어가 있다면 댓글로 남겨주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2024 유스콘]]></title>
            <link>https://velog.io/@injung_p/2024-%EC%9C%A0%EC%8A%A4%EC%BD%98</link>
            <guid>https://velog.io/@injung_p/2024-%EC%9C%A0%EC%8A%A4%EC%BD%98</guid>
            <pubDate>Thu, 31 Oct 2024 11:32:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/injung_p/post/1d9f9e2e-978d-467b-9950-0217593369f5/image.jpg" alt=""></p>
<p>유쾌한 스프링방에서 탄생한 <strong>유스콘</strong>은  젊은 개발자와 선배 개발자가 함께 가치 있는 기술에 관한 정보와 경험을 공유하는 콘퍼런스, 발표자들은 가까운 미래에 <strong><em>“DEVIEW, if(kakao), 우아콘, SPRINGCAMP, 인프콘의 주인공이 될 개발자”</em></strong>라고 이야기 한다.
(작년에 이어서 2번째 오게 된 유스콘! 언젠가 나도 하겠지… 🤣)</p>
<h3 id="기존-공지된-유스콘-노션-공유-글"><em>기존 공지된 유스콘 노션 공유 글</em></h3>
<p><a href="https://www.notion.so/YOUTHCON-24-49177aa1b828435f98046912c6debc78?pvs=21">YOUTHCON&#39;24</a></p>
<hr>
<h1 id="am-1030---1050">AM 10:30 - 10:50</h1>
<h2 id="새로운-도전-새로운-환경-발전하는-나의-모습">새로운 도전, 새로운 환경, 발전하는 나의 모습</h2>
<h3 id="발표자--오길식엔드앤드코리아--멘토--오길환넥슨">발표자 : 오길식(엔드앤드코리아) / 멘토 : 오길환(넥슨)</h3>
<p><strong>“지금 취업을 준비하고 있거나 이직을 준비하고 있는 분들께”</strong></p>
<ul>
<li>이런 분들이 편안하게 들어주셨으면 좋겠다! 비 전공자로써 개발자를 하게된 계기 등을 발표</li>
</ul>
<ol>
<li>전혀 관련없는 업무만 골라서 했었던 자신 어떻게 개발자를 선택하게 되었는지?</li>
</ol>
<ul>
<li>게임에 대한 관심이 컸음</li>
<li>호기심이 강해 게임이 어떻게 동작하는지 알고 싶었고 클라이언트 등을 뜯어봄</li>
<li>먼저 개발을 시작한 동생의 영향이 컷음(선배인 동생의 영향이 컸음 : 동생이 멘토)</li>
<li>잘 맞는 성격<ul>
<li>공익 판정을 받고도 교육청에서 일했던 시절, 엑셀을 통한 자동화를 통하여 <strong><em>휴먼 에러 초소화</em></strong></li>
</ul>
</li>
</ul>
<ol>
<li>개발자가 되기 위해 무엇을 준비했는가?</li>
</ol>
<ul>
<li>국비 학원을 등록(팀장 역할 담당, 자바의 정석 책 정독)</li>
<li>알고리즘 공부(백준 등)</li>
<li>이력서 제출(1000개가 넘는 불합격 및 면접 기회를 받은것은 3건)<ul>
<li>“사회복지학과를 나왔는데 개발자와 관련이 있나요?” 라는 질문을 많이 받음<ul>
<li>연관성을 짓기 힘든 연결고리가 많았었음</li>
</ul>
</li>
<li>면접은 본인의 지식을 점검할 수 있는 시간이 되었음<ul>
<li>내가 가장 어려웠던 것 → 내가 가지고 있는 지식이 과연 올바른가?</li>
<li>내가 작성하는 코드의 방식이 실무에서 도움이 되는가?</li>
</ul>
</li>
<li>탈탈 털린 면접 질문 리스트들을 노션에 정리함<ul>
<li>일급 컬렉션, 리플렉션, 질렬화, 함수형 프로그래밍 등…</li>
<li>토비의 스프링책이 도움이 많이 되었음</li>
</ul>
</li>
</ul>
</li>
<li>지금 포기하면 더 어려운 미래를 준비해야 할 지도 모른다 포기하지 않아야 한다</li>
</ul>
<ol>
<li>취업 과정</li>
</ol>
<ul>
<li>작은 스타트업 (웹팀 / 앱팀)<ul>
<li>할 수 있는 것은 무엇이든지 해볼 수 있는 좋은 기회</li>
<li>프론트 개발자와 이야기를 하면서 각 포지션에 대한 이해도를 높임</li>
<li>동료와의 코드를 교환하고 서로 피드백을 받음</li>
<li><strong><em>어떤 회사라도 배울 점은 있다</em></strong></li>
</ul>
</li>
</ul>
<ol>
<li>결론</li>
</ol>
<blockquote>
<p>지금 하는 노력들이 추후 개발자가 되었을때 큰 경험이 되어 다가올 것이므로, 
끝까지 희망을 잃지 말고 훌륭한 개발자로 성장하시기를 기원합니다. 
서로 의지하며 함께 나아갈 수 있기를 바랍니다!</p>
</blockquote>
<hr>
<h1 id="am-1100---1150">AM 11:00 - 11:50</h1>
<h2 id="무모한-도전으로부터-얻은-성장">무모한 도전으로부터 얻은 성장</h2>
<h3 id="발표자--김대현한국외국어대학교--멘토--박재성jason우아한형제들">발표자 : 김대현(한국외국어대학교) / 멘토 : 박재성(Jason)(우아한형제들)</h3>
<ol>
<li>성장, 도전이란 무엇인가?</li>
</ol>
<ul>
<li>하나의 무엇에 도전하며 그를 통해 성장하는 것(연관 관계가 있다고 생각)</li>
<li>고등학교 : 임베디드(로봇), 올림피아드 수상, 수능 후 임베디드를 포기하고 컴공으로 전환<ul>
<li>전공을 전환하니 시작된 방황</li>
</ul>
</li>
</ul>
<ol>
<li>정신을 차리게 된 계기</li>
</ol>
<ul>
<li>다른 친구들이 성장하는 모습을 보면서 현실적인 자각을 함<ul>
<li>친구들은 성장하고 자신은 그러지 못한 모습을 보면서 낮아진 자존감이 커졌음</li>
</ul>
</li>
<li>‘김현준’ 이라는 야구선수가 프로무대에 도전, 성장, 노력하는 모습을 봄<ul>
<li>이 모습을 보고 본받아서 나도 할 수 있다고 다짐을 함</li>
<li>도전이 없으면 변화도 없고, 새로운 경험을 하여 성장을 하고 싶었음</li>
</ul>
</li>
<li>사회에서 1인분 하는 개발자가 되고 싶다<ul>
<li>과거 AI를 잠시 찍먹할 때, CV에서 다양한 물체들을 탐지하는 것에 대한 공부에 흥미를 느낌</li>
</ul>
</li>
</ul>
<ol>
<li>1번째 무모한 도전</li>
</ol>
<ul>
<li>NLP(자연어 처리)는 처음 접해보는 AI 분야 → 뭔소리인지 1도 알 수 없었음<ul>
<li>나도 따라잡아보자는 다짐을 함</li>
</ul>
</li>
<li>NLP 기반의 투자 자원 플랫폼 개발 프로젝트<ul>
<li>무의미한 정보 전처리, 유의미한 산업별 높은 키워드 추출</li>
</ul>
</li>
</ul>
<ol>
<li>2번째 무모한 도전</li>
</ol>
<ul>
<li>프로젝트 지도 교수님의 제안으로 논문 준비<ul>
<li>논문(학회에서 발표 후)을 통해 발표하는 개발자가 되어야 겠다고 생각 함</li>
</ul>
</li>
</ul>
<ol>
<li>하고싶은 말</li>
</ol>
<ul>
<li>기술 및 실력적으로 부족에 대한 고민이 있다면?<ul>
<li>단순이 수업, 강의에 의존을 해서는 안된다고 생각함<ul>
<li>복습, 관련 서적을 꼭 읽어보고 사이드 프로젝트를 해보기</li>
<li>다양한 분야를 경험하는것을 추천</li>
<li>좋아하는것을 말고 싫어하는것을 먼저 찾아보기<ul>
<li>좋아하는것을 먼저 찾게 되면 빨리 그 부분에 대해 빨리 종료될 수 있으니까?
(역으로 생각해서 나쁜것에서 좋은것으로 가보자 라는 뜻 같음)</li>
</ul>
</li>
<li>떡이 있어도 먼저 찾아서 먹어야 한다<ul>
<li>정보력이 좋아햐 한다는 소리<ul>
<li>개발 관련 활동 → 스터디, 동아리 활동, 컨퍼런스 참여</li>
<li>기술력 Follow up</li>
</ul>
</li>
</ul>
</li>
<li>제일 중요한건 자신감<ul>
<li>실패를 두려워 하지 않는것 또한 용기라고 생각</li>
<li>너무 큰 목표만 바라보는것은 좋은 생각이 아니라고 생각함</li>
<li>여러번 도전하고 실패하더라도 좌절감을 느낄 수 있지만 그 또한 성장이 경험임
(다음 도전으로 나아가려면 나는 할 수 있다라는 자신감으로 극복해야한다고 생각 함)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="am-1130---1150">AM 11:30 - 11:50</h1>
<h2 id="자바-퀴즈로-함께-자라기">자바 퀴즈로 함께 자라기</h2>
<h3 id="발표자--윤종민별소프트--멘토--김재연우아한형제들">발표자 : 윤종민(별소프트) / 멘토 : 김재연(우아한형제들)</h3>
<p><strong>“발표를 하는 이유”</strong></p>
<ul>
<li>경험을 공유하는것을 좋아하고 그것을 통해 서로 비교하는 시간이 되었으면 좋겠다</li>
</ul>
<h3 id="퀴즈">퀴즈</h3>
<ul>
<li>Java 8<ul>
<li>자료구조 - HashMap</li>
<li>Stream</li>
</ul>
</li>
</ul>
<p>→ 이 발표 세션은 나중에 zoom 참고 해도 될 것 같기도...! 
(퀴즈를 풀며 각자 가진 지식을 확인하고 모른 걸 되짚어보는 시간이었다)</p>
<hr>
<h1 id="pm-1200---1220">PM 12:00 - 12:20</h1>
<h2 id="cdc-네가-뭘-할-수-있는데">CDC? 네가 뭘 할 수 있는데?</h2>
<h3 id="발표자--최재용아이스크림에듀--멘토--최병균scglab">발표자 : 최재용(아이스크림에듀) / 멘토 : 최병균(SCGLAB)</h3>
<p>이번 발표로 무엇을 얻을 수 있는가?</p>
<ul>
<li>타 시스템으로 데이터 변경을 전파하는 방법</li>
<li>데이터 일관성을 유지하는 방법</li>
<li>CDC를 활용하는 법</li>
</ul>
<p>CDC란?</p>
<p>문제상황해결</p>
<ul>
<li>CDC 적용시 효과<ul>
<li>데이터 제공자의 소스 변경 없음</li>
<li>변경된 데이터를 실시간으로 전파</li>
<li>로그에서 조회한 데이터를 용도에 맞게 활용</li>
</ul>
</li>
</ul>
<p>CDC 활용사례</p>
<p>CDC 도입시 고려 사항</p>
<ul>
<li>관리 포인트의 증가</li>
<li>복잡도 증가</li>
<li>재처리 방법 고려<ul>
<li>재시도</li>
<li>후보정</li>
</ul>
</li>
</ul>
<p>정리</p>
<ul>
<li>반드시 필요할 때만 사용</li>
</ul>
<hr>
<h1 id="pm-0200---0220">PM 02:00 - 02:20</h1>
<h2 id="일단-한-번-해보고-생각하면-안돼요feat-디자이너의-시선">일단 한 번 해보고 생각하면 안돼요?(feat. 디자이너의 시선)</h2>
<h3 id="발표자--장예슬광주소프트웨어마이스터고등학교--멘토--박재성jason우아한형제들">발표자 : 장예슬(광주소프트웨어마이스터고등학교) / 멘토 : 박재성(Jason)(우아한형제들)</h3>
<p><code>학생, 외주 받고 스타트업(국내, 국외)에 대한 프로젝트 진행을 한 것이 있음</code></p>
<p><code>아직 말하는 것(발표나 말하는 표현법)에 대한 미숙함 10대 다운 언어적 표현법이 많음</code></p>
<p><code>사회생활을 발 돋움에 대한 이체 첫 시작의 자기 경험에 대한 이야기를 하는 것 같음</code></p>
<p><code>(유스콘 첫 고등학생 및 디자이너라해서 발표가 신선해서 들어봄)</code> </p>
<ul>
<li>스타트업, 대회, 해커톤, 학업, 동아리, 내부 프로젝트 등 자기성장을 위해 계속 노력중</li>
<li>QR?(QR코드는 아닌것 같은데) 디자인에 대한 뭐 공유가 필요하시면 따로 찾아주시면 공유 하겠다고 함</li>
<li>배포중인 프로젝트 소개<ul>
<li>디자인 공부 하고 프로젝트 진행 한 부분들에 대한 외주 정리에 대한 노션 리스트 보여줌</li>
</ul>
</li>
</ul>
<hr>
<h1 id="pm-0230---0250">PM 02:30 - 02:50</h1>
<h2 id="일단-개발자이긴-합니다만">일단 개발자이긴 합니다만…</h2>
<h3 id="발표자--오영택kt--멘토--박재성자바지기우아한형제들">발표자 : 오영택(KT) / 멘토 : 박재성(자바지기)(우아한형제들)</h3>
<ul>
<li>우테코를 통해 취업 성공</li>
<li>서울대 졸업(건설환경) → 음악을 함 → 학원 선생님 → 개발 전향</li>
<li>하고 싶은 것, 잘 할 수 있는 것, 해야하는 것<ul>
<li>개발<ul>
<li>음악 서비스에 대한 개발을 올린 글을 보고 개발에 더 관심이 생김</li>
<li>진짜 몰입할 수 있고 진짜 잘 하고싶은 것이 하고싶은 것이라고 생각이 듬</li>
</ul>
</li>
<li>워크 ≠ 라이프? (3항연산자 표현으로 쓴것 아님 ! = )<ul>
<li>해야 하는 것이 하고싶은것이라고 생각하고 싶지 않았다</li>
</ul>
</li>
<li>스스로가 생각하는 개발자는 무언가를 만들어내는 사람이라고 생각함</li>
<li>네트워킹에 대한 중요성(개발이야기하고 술도먹고…)</li>
</ul>
</li>
</ul>
<hr>
<h1 id="pm-0300---0320">PM 03:00 - 03:20</h1>
<h2 id="내가-만든-서비스-6명-중-1명은-사용조차-못한다고">내가 만든 서비스, 6명 중 1명은 사용조차 못한다고..?!</h2>
<h3 id="발표자--김여진--멘토--이동근당근">발표자 : 김여진 / 멘토 : 이동근(당근)</h3>
<p>프론트엔드 취준생(웹 접근성에 대해서 관심있어서 그것에 대한 이야기를 하고싶어 한듯하다)</p>
<p><strong>”사용자 경험 및 접근성에 대한 관심이 많은 분들께“</strong></p>
<ul>
<li>사실 우리도 장애 환경을 겪고 있다</li>
<li>웹 접근성이란?<ul>
<li>a11y :</li>
<li>왜 지켜야 하는가?<ul>
<li><strong><em>WCAG(웹 접근성 지침)의 4대 원칙</em></strong> : 
인지 가능성(인식), 조작 가능성, 이해 가능성, 견고성</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="pm-0330---0350">PM 03:30 - 03:50</h1>
<h2 id="오늘도-기획자가-왜-안된다고-말하냐고-말했다">오늘도 기획자가 왜 안된다고 말하냐고 말했다</h2>
<h3 id="발표자--류찬카카오--멘토--박재성자바지기우아한형제들">발표자 : 류찬(카카오) / 멘토 : 박재성(자바지기)(우아한형제들)</h3>
<p>카카오에서 브런치북을 개발중인 백엔드 개발자</p>
<p><strong>“서비스 기업에서 재직중인, 구직중인 주니어 백앤드 개발자 분들께
기획자와의 커뮤니케이션이 아직 어려우신 분들께‘</strong></p>
<ul>
<li><p>기획자와의 커뮤니케이션 방법</p>
<ul>
<li>서비스 개발에서 성능은 매우 중요한 요소이다</li>
<li>기술 스택과 일정을 고려할 때 기획의 변경이 필요하다면?</li>
<li>나는 왜 안되는지 알 수 있다? 기획자는 어떨까?<ul>
<li>개발자는 알 수 있지만 기획자는 모를 수 있는 부분에 어떻게 소통 할 수 있을까?</li>
</ul>
</li>
<li>가상의 기획자를 설득해 보자 - FIRST STEP<ol>
<li>문제를 제기한다</li>
<li>해결책을 제시한다</li>
<li>내 해결책과 기존 기획의 차이를 분석하고 기획자를 설득한다</li>
</ol>
</li>
</ul>
</li>
<li><p>결론</p>
<ol>
<li>기획자는 기획하고, 개발자는 구현한다</li>
<li>문제가 있으면 함께 고민하기, 서비스는 함께 만드는 것<ul>
<li>기획자와 ‘잘’ 논의하자<ul>
<li>어떻게? step을 생각하자 (위에 작성한 3가지 step)</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<hr>
<h1 id="pm-0430---0520">PM 04:30 - 05:20</h1>
<h2 id="다중-서버-환경에서-똑똑하게-캐싱하기">다중 서버 환경에서 똑똑하게 캐싱하기</h2>
<h3 id="발표자--김태현우아한형제들--멘토--김형준컬리">발표자 : 김태현(우아한형제들) / 멘토 : 김형준(컬리)</h3>
<ul>
<li>캐싱을 고려</li>
<li>데이터 캐싱 시 문제점</li>
<li>폴링<ul>
<li>다른장치 또는 프로그램의 상태를 <code>주기적으로 검사</code></li>
<li>폴링이 적절한 이유</li>
<li>폴링 도입</li>
<li>서버 부하 관점에서도 이로운 폴링</li>
</ul>
</li>
<li>스프링 스케줄러</li>
<li>주의 ! fixedDelay와 @Asysc? 를 같이 쓰지 않도록</li>
<li>ShedLock 라이브러리</li>
</ul>
<hr>
]]></description>
        </item>
    </channel>
</rss>