<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>될테야테야 개발자가 될테야</title>
        <link>https://velog.io/</link>
        <description>웹 프론트엔드 개발자를 꿈꾸고 있습니다.</description>
        <lastBuildDate>Sun, 14 Dec 2025 03:18:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>될테야테야 개발자가 될테야</title>
            <url>https://velog.velcdn.com/images/sohyerim-dev/profile/d6066329-59e6-4b90-a522-3652f6dca9e8/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 될테야테야 개발자가 될테야. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sohyerim-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React] UseRef]]></title>
            <link>https://velog.io/@sohyerim-dev/React-UseRef</link>
            <guid>https://velog.io/@sohyerim-dev/React-UseRef</guid>
            <pubDate>Sun, 14 Dec 2025 03:18:27 GMT</pubDate>
            <description><![CDATA[<h1 id="useref">useRef</h1>
<ul>
<li>컴포넌트가 다시 렌더링되더라도 기존 상태값을 유지하는 변수를 생성</li>
<li>함수 내부에 정의하는 지역 변수는 컴포넌트가 다시 렌더링되면(함수 재호출) 값이 초기화 됨</li>
<li><code>useState</code>는 값이 변경되면 컴포넌트가 다시 렌더링되지만 <code>useRef</code>는 값이 변경되어도 컴포넌트가 다시 렌더링되지 않음</li>
<li>JSX 태그에 <code>ref</code> 속성을 추가하면 브라우저 DOM 엘리먼트에 직접 접근 가능<ul>
<li>포커스, 미디어 재생, 애니메이션 실행 등과 같은 작업은 <code>UseRef</code>를 사용해 브라우저 DOM에 직접 접근하여 제어해야 함</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">&lt;input ref={ stepElem } // 이런 식으로 속성에 직접 추가하여 DOM 엘리먼트에 접근
                defaultValue=&quot;1&quot; // defaultValue 속성으로 초기값 지정
            onChange={ (e) =&gt; stepRef.current = Number(e.target.value) } /&gt; // ref 객체의 current에 저장</code></pre>
<pre><code class="language-jsx">const ref = useRef(initialValue);</code></pre>
<p>매개변수</p>
<ul>
<li><code>initiailValue</code> : 초기값</li>
</ul>
<p>리턴값</p>
<ul>
<li><code>current</code>라는 상태값 또는 DOM 요소가 있는 속성 하나가 정의된 객체</li>
</ul>
<pre><code class="language-jsx">  // 1. 값이 변경 되면 변경된 값을 유지하면서 리렌더링이 발생하지 않음
  const stepRef = useRef(1); // { current: 1 } 객체를 반환

  // 2. DOM 객체에 대한 직접 참조를 사용할 때
  const stepElem = useRef&lt;HTMLInputElement&gt;(null); // { current: null } 객체를 반환

const handleReset = () =&gt; {
    setCount(initCount);
// step input 요소에 포커스 지정
// const stepElem = document.querySelector(&#39;#step&#39;) as HTMLInputElement;

    stepElem.current?.focus(); // stepElem가 반환하는 객체의 current 속성으로 접근
  };</code></pre>
<p>→ <strong>폼 제출 시에만 값이 필요한 경우와 같이 입력값으로 UI를 변경하지 않아도 될 때 useState대신 useRef를 쓰면 오버 헤드를 줄이고 성능 낭비를 줄일 수 있다.</strong></p>
<h2 id="usestate-vs-useref">UseState VS UseRef</h2>
<ul>
<li>input 값이 변경되는 즉시 리렌더링 되어야 할 때 → UseState (리액트에서 직접 상태관리를 하는 제어 컴포넌트를 구현)</li>
<li>input 값이 변경 되어도 리렌더링 될 필요가 없을 때 → UseRef (브라우저에서 입력값을 관리하는 비제어 컴포넌트를 구현)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useEffect]]></title>
            <link>https://velog.io/@sohyerim-dev/React-useEffect</link>
            <guid>https://velog.io/@sohyerim-dev/React-useEffect</guid>
            <pubDate>Sat, 13 Dec 2025 12:10:17 GMT</pubDate>
            <description><![CDATA[<h1 id="useeffect">useEffect</h1>
<ul>
<li>컴포넌트 생명주기 이벤트를 등록하기 위한 훅</li>
<li>클래스 기반 컴포넌트에서는 <code>componentDidMount()</code>,<code>componentDidUpdate()</code>,<code>componentWillUnmount()</code> 메소드를 오버라이드 해서 구현해야 함</li>
<li>함수 컴포넌트에서는 useEffect에서 구현 가능</li>
<li>useEffect에서 주로 구현하는 기능<ul>
<li>컴포넌트의 렌더링 작업 외의 부가적인 작업<ul>
<li>타이머 설정</li>
<li>로깅</li>
</ul>
</li>
<li>컴포넌트의 렌더링 이후에 처리할 작업<ul>
<li>DOM 수동 조작</li>
</ul>
</li>
<li>side effect가 발생하는 작업(컴포넌트를 순수 함수로 유지)<ul>
<li>데이터 fetching</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">useEffect(setup, dependencies?);</code></pre>
<ul>
<li><p><code>setup</code> : 컴포넌트가 마운트, 업데이트, 제거 될 때 호출되는 함수로</p>
<ul>
<li><p><code>setup</code> 이 함수를 리턴하면, 리턴한 함수를 <code>cleanup</code> 이라고 부르며, 컴포넌트가 업데이트되거나 언마운트 될 때 호출됨(이전 effect의 cleanup이 먼저 실행되고 setup이 뒤에 실행됨)</p>
</li>
<li><p>setup 함수</p>
<ul>
<li>컴포넌트가 <strong>마운트될 때 실행</strong></li>
<li>의존성 값이 변경되면 <strong>업데이트 시 다시 실행</strong></li>
<li>effect에서 <strong>시작해야 할 작업</strong>을 작성하는 부분</li>
</ul>
<p>예)</p>
<ul>
<li>이벤트 리스너 등록</li>
<li>타이머 설정</li>
<li>구독 시작</li>
</ul>
</li>
<li><p>cleanup 함수</p>
<ul>
<li>setup 함수가 <strong>리턴한 함수</strong></li>
<li>setup에서 해둔 작업을 <strong>정리(원상복구)</strong> 하는 역할</li>
<li>실행 시점<ul>
<li><strong>업데이트 시</strong>: 다음 setup이 실행되기 <strong>직전</strong></li>
<li><strong>언마운트 시</strong>: 컴포넌트가 사라질 때</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">마운트:
→ effect 실행

count 변경 (업데이트):
→ cleanup
→ effect 실행

언마운트: // 의존성 배열이 [] 빈 배열 일 때 
→ cleanup
</code></pre>
<ul>
<li><code>dependencies</code> (선택) : 의존 객체 배열<ul>
<li>컴포넌트가 업데이트될 때 <code>setup</code> 함수를 호출할지 말지 여부를 결정하는데 사용</li>
<li>컴포넌트가 마운트될 때는 <code>dependecies</code>  여부와 상관없이 <code>setup</code> 이 호출됨</li>
<li><code>dependencies</code> 를 생략하면, 컴포넌트가 업데이트될 때 항상 setup이 호출됨</li>
<li><code>dependencies</code> 에 빈 배열을 지정하면, 컴포넌트가 업데이트 될 때 호출되지 않음 (최초 마운트 시에만 호출)</li>
<li><code>dependencies</code> 를 지정하면, 컴포넌트가 업데이트 될 때 지정한 값 중 하나라도 수정되었을 경우에만 <code>setup</code> 함수가 호출됨</li>
</ul>
</li>
</ul>
<p><strong>의존성 배열이 없을 경우 무한 반복이 될 가능성이 크지만, 항상 그렇지는 않다.</strong>
→ 정확하게는 렌더링 될 때마다 effect가 실행된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 컴포넌트 생명주기(라이프 사이클)]]></title>
            <link>https://velog.io/@sohyerim-dev/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4</link>
            <guid>https://velog.io/@sohyerim-dev/React-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4</guid>
            <pubDate>Fri, 12 Dec 2025 15:28:56 GMT</pubDate>
            <description><![CDATA[<p>리액트를 처음 배우기 시작하면, 코드가 언제 실행이 되는 건지, 렌더링은 왜 여러 번 일어나는 건지 이해하기가 어렵게 느껴지기도 합니다. 그래서 리액트 컴포넌트의 생성되고, 업데이트되고, 사라지기까지의 흐름을 정리해 보겠습니다.</p>
<p><img src="https://velog.velcdn.com/images/sohyerim-dev/post/e3e15e26-1be9-4414-a5a1-6224cd99fa9b/image.png" alt="컴포넌트 생명주기">
<em>(이미지 출처 - 멋쟁이사자처럼 웹 프론트엔드 부트캠프 15기, GD쌤 강의자료)</em></p>
<p>컴포넌트의 생명주기는 마운팅, 업데이팅, 언마운팅으로 세 부분으로 나눠볼 수 있습니다.</p>
<hr>
<h1 id="1마운팅mounting">1.마운팅(mounting)</h1>
<ul>
<li>컴포넌트가 처음으로 DOM에 추가되고 렌더링 되는 단계를 말합니다.</li>
<li>상태(state)와 속성(props)이 초기화되는 단계입니다.</li>
</ul>
<h2 id="1-1-constructor">1-1 constructor()</h2>
<ul>
<li>컴포넌트 인스턴스가 생성될 때 한 번 호출됩니다.</li>
<li>super(props)를 호출하지 않으면 this를 사용하지 못하므로 this.state, this.props 사용이 불가합니다.</li>
<li>props를 기반으로 상태를 초기화하는 코드를 작성합니다.</li>
<li>props를 기반으로 상태를 초기화할 필요가 없으면 생성자를 작성할 필요가 없습니다.</li>
</ul>
<p>→ 처음에 이 설명을 듣고 무슨 말인지 잘 이해가 가지 않았습니다. 이 과정은 클래스 컴포넌트의 경우에 해당이 됩니다. 클래스 컴포넌트는 React.Component의 상속을 받아 만들어지는데, 그러므로 클래스 컴포넌트의 부모 클래스는 React.Component인 것입니다. super(props)를 호출한다는 것은 부모 클래스인 React.Component의 생성자를 먼저 실행하겠다는 뜻입니다. 이 과정을 통해 React는 this를 초기화하고, this.props를 사용할 수 있도록 준비합니다.</p>
<ul>
<li>constructor에서 주로 하는 일은 props를 기반으로 초기 state를 만드는 것입니다. 이 단계에서 설정한 state는 이후 렌더링의 기준이 됩니다.</li>
</ul>
<p>하지만, 많은 경우 constructor를 직접 만들지 않아도 됩니다. 왜냐하면, state를 props로부터 만들 필요가 없거나 기본값만 있으면 되는 경우가 대부분이기 때문입니다. 예를 들어, </p>
<pre><code class="language-javascript">class Counter extends React.Component {
  state = {
    count: 0,
  };
}</code></pre>
<p>위 예시처럼 클래스 필드 문법을 사용하면 리액트가 내부적으로 초기 state를 설정해주기 때문에, constructor를 직접 작성할 필요가 없어집니다.</p>
<p>** 그리고 중요한 점은 최근에 함수형 컴포넌트와 Hooks가 표준이 되면서, constructor를 직접 사용할 일은 점점 줄어들고 있다는 것입니다. **</p>
<h2 id="2-1-static-getderivedstatefrompropsprops-state">2-1 static getDerivedStateFromProps(props, state)</h2>
<ul>
<li>부모 컴포넌트로부터 전달받은 props를 기반으로 상태를 업데이트 하고 싶을 때 사용합니다.</li>
<li>props나 state 값에 의해서 업데이트되는 새로운 state를 리턴하도록 작성합니다.</li>
<li>일반적으로 props가 state에 영향을 주는 경우가 많지 않기 때문에 사용할 일은 거의 없습니다.</li>
</ul>
<p>+) getDerivedStateFromProps는 부모로부터 받은 props 변화에 따라 state를 ‘동기화’해야 할 때 사용하는 생명주기 메서드입니다. 이 메서드는 언제 호출이 될까요?</p>
<ul>
<li>컴포넌트가 처음 마운트될 때</li>
<li>부모로부터 새로운 props를 받을 때</li>
<li>state가 변경되어 다시 렌더링될 때</li>
</ul>
<p>즉, 렌더링 직전에 항상 호출될 수 있는 단계입니다.
그러므로 이 메서드는 <strong>side effect를 만들면 안 되고, 순수하게 값 계산만</strong> 해야 합니다. </p>
<blockquote>
<p>그렇다면 <strong>side effect(부작용)</strong>란 무엇일까요?</p>
<ul>
<li>side effect는 “함수를 실행했을 때, 값 계산 말고 바깥에 영향을 주는 모든 행동”을 말합니다.</li>
</ul>
<p>이 설명만으론 아직 좀 이해가 어렵습니다.
그렇다면, side effect가 있는 경우 혹은 해야하는 경우로 어떤 것이 있을까요?</p>
<p><strong>side effect가 있는 경우</strong></p>
<ol>
<li>외부 상태나 전역 값의 변경 (변수 재할당)</li>
<li>서버 통신</li>
<li>DOM 조작</li>
<li>타이머, 이벤트 등록</li>
<li>로그 출력 (엄밀히 말하면 side effect이지만 디버깅 목적으로는 허용되는 경우가 많습니다)</li>
</ol>
<p><strong>side effect를 해야하는 곳</strong></p>
<ol>
<li>componentDidMount</li>
<li>componentDidUpdate</li>
<li>componentWillUnmount</li>
<li>함수형 컴포넌트의 useEffect</li>
</ol>
</blockquote>
<p>getDerivedStateFromProps 메서드는 잘못 사용하면 state와 props의 역할이 뒤섞이기 때문에, 대부분의 경우에는 필요하지 않습니다.</p>
<h2 id="1-3-render">1-3 render()</h2>
<ul>
<li>JSX를 이용해서 UI를 리턴합니다.</li>
<li>현재 state와 props를 바탕으로 화면에 무엇을 보여줄지 결정하는 단계입니다.</li>
</ul>
<p><strong>render는 언제 호출될까요?</strong></p>
<blockquote>
<ul>
<li>컴포넌트가 처음 마운트될 때</li>
<li>state가 변경될 때</li>
<li>props가 변경될 때</li>
<li>부모 컴포넌트가 다시 렌더링될 때</li>
</ul>
</blockquote>
<ul>
<li><strong>render는 순수 함수처럼 동작해야 한다는 규칙이 있습니다.</strong></li>
</ul>
<blockquote>
<p>즉,</p>
<ul>
<li>같은 props, 같은 state → 항상 같은 JSX 반환</li>
<li>외부 상태를 바꾸지 않음</li>
<li>side effect를 만들지 않음</li>
</ul>
</blockquote>
<h2 id="1-4-componentdidmount-함수형-컴포넌트에서는-useeffect로-사용-가능">1-4 componentDidMount() (함수형 컴포넌트에서는 useEffect로 사용 가능)</h2>
<ul>
<li>컴포넌트 마운트가 완료되고, 리액트가 JSX를 실제 DOM에 반영한 뒤 화면에 렌더링된 후 단 한 번 호출됩니다.</li>
<li>componentDidMount는 side effect를 수행하기 위한 대표적인 위치로 아래와 같은 작업을 수행합니다.</li>
</ul>
<blockquote>
<ul>
<li>서버로부터 데이터 요청 (API 호출)</li>
<li>DOM에 직접 접근해야 하는 초기 설정</li>
<li>타이머 설정</li>
<li>외부 라이브러리 초기화</li>
<li>이벤트 리스너 등록</li>
</ul>
</blockquote>
<ul>
<li>함수형 컴포넌트의 경우 useEffect를 사용해 componentDidMount와 같은 역할을 수행하며, 의존성 배열을 빈 배열로 전달하면 최초 마운트 시 한 번만 실행됩니다.</li>
</ul>
<hr>
<h1 id="2-업데이팅updating">2. 업데이팅(updating)</h1>
<ul>
<li>마운트 된 컴포넌트의 상태(state)나 속성(props)이 변경되어 리렌더링 되는 단계<h2 id="2-1-static-getderivedstatefrompropspropsstate">2-1 static getDerivedStateFromProps(props,state)</h2>
</li>
<li>1-2와 동일<h2 id="2-2-shouldcomponentupdatenextprops-nextstate">2-2 shouldComponentUpdate(nextProps, nextState)</h2>
</li>
<li>컴포넌트가 다시 렌더링될지 말지를 결정하는 단계입니다.</li>
<li>state나 props가 변경되면 기본적으로 리액트는 다시 render를 호출하지만, 이 메서드를 사용하면 그 흐름을 중간에서 제어할 수 있습니다.</li>
<li>true를 리턴하면 이어서 render가 호출되고, false를 리턴하면 render를 호출하지 않습니다.</li>
<li>생략할 경우 항상 true를 반환합니다.</li>
<li>인자로 전달되는 nextProps, nextState와 이전 값 this.props, this.state를 비교해서 렌더링 여부를 결정할 수 있습니다.</li>
<li>Component 대신 PureComponenet를 상속 받을 경우 이 메서드가 이전과 현재의 props, state를 Object.is() 함수를 사용해 얕은 비교를 하여 바뀌지 않았다면 렌더링 하지 않도록 이미 구현되어 있습니다.</li>
</ul>
<ul>
<li>함수형 컴포넌트에서는 shouldComponentUpdate를 직접 사용할 수 없습니다.</li>
</ul>
<blockquote>
<p>대신</p>
<ul>
<li>React.memo</li>
<li>useMemo</li>
<li>useCallback</li>
</ul>
<p>같은 도구로 같은 효과를 낸다.</p>
</blockquote>
<p>게다가 잘못 사용하면 버그를 만들기 쉬워 보통은 PureComponent나 memo 기반 최적화를 사용하는 것이 권장됩니다.</p>
<h2 id="2-3-render">2-3 render()</h2>
<ul>
<li>1-3과 동일<h2 id="2-4-getsnapshotbeforeupdateprevprops-prevstate">2-4 getSnapshotBeforeUpdate(prevProps, prevState)</h2>
</li>
<li>render() 메서드가 호출되어 가상 DOM으로 쓰기가 완료되고, 브라우저 DOM에 업데이트 되기 전에 호출됩니다.</li>
<li>이 메서드의 티턴값이 2-5 componentDidUpdate()의 세 번째 인자로 전달됩니다.</li>
<li>DOM이 바뀌기 “직전 상태”를 기억해두는 역할을 합니다.</li>
</ul>
<blockquote>
<p><strong>업데이트 전·후의 DOM 차이를 알아야 하는 경우를 위해 이 단계가 필요한데, 어떤 경우가 이에 해당할까요?</strong></p>
<ul>
<li>스크롤 위치 유지</li>
<li>DOM 크기 변화 감지 등...</li>
</ul>
</blockquote>
<ul>
<li>주의할 점은 여기서는 side effect를 하면 안 된다는 겁니다.<h2 id="2-5-componentdidupdateprevprops-prevstate-snapshot-함수형-컴포넌트에서는-useeffect로-사용-가능">2-5 componentDidUpdate(prevProps, prevState, snapshot) (함수형 컴포넌트에서는 useEffect로 사용 가능)</h2>
</li>
<li>브라우저 DOM 업데이트 완료 후에 호출됩니다.</li>
<li>현재 속성 this.props, this.state와 이전 값 prevProps, prevState가 다르다면 외부 API 호출 등의 작업을 수행합니다.</li>
<li>2-4에서 리턴한 값이 세 번째 인자 snapshot으로 전달되므로 보통 2-4와 같이 사용됩니다.</li>
</ul>
<blockquote>
<ul>
<li>“화면이 실제로 바뀐 뒤” 실행되는 단계입니다.</li>
<li>최초 마운트 시에는 호출되지 않고, props와 state가 변경되었을 때 호출됩니다.</li>
</ul>
</blockquote>
<p>이 단계는 업데이트 이후의 side effect 처리 공간으로 주로 아래와 같은 작업을 수행합니다.</p>
<blockquote>
<ul>
<li>props / state 변화에 따른 API 재요청</li>
<li>DOM 조작</li>
<li>외부 라이브러리 업데이트</li>
</ul>
</blockquote>
<ul>
<li>주의할 점은 반드시 조건문으로 이전 값과 비교해야 무한 업데이트에 빠지지 않습니다.</li>
<li>함수형 컴포넌트에서는 useEffect를 사용하여 이 단계를 수행합니다.</li>
</ul>
<hr>
<h1 id="3-언마운팅unmounting">3. 언마운팅(unmounting)</h1>
<ul>
<li>컴포넌트가 DOM에서 제거되는 단계입니다.<h2 id="3-1-componentwillunmount-함수형-컴포넌트에서는-useeffect로-사용-가능">3-1 componentWillUnmount() (함수형 컴포넌트에서는 useEffect로 사용 가능)</h2>
</li>
<li>컴포넌트가 애플리케이션의 컴포넌트 트리에서 삭제되기 직전에 실행됩니다.</li>
<li>주로 1-4 componentDidMount()와 세트로 사용됩니다.<ul>
<li>웹소켓을 사용할 경우 1-4에서 연결하고, 이곳에서 연결 해제합니다.</li>
<li>1-4에서 setTimeout()을 호출했다면 이곳에서 clearTimeout()으로 해제됩니다.</li>
</ul>
</li>
</ul>
<blockquote>
<ul>
<li>이 단계의 핵심 역할은 컴포넌트가 사용하던 외부 자원을 정리(clean up)하는 것입니다.</li>
</ul>
<p><strong>왜 정리가 필요할까요?</strong></p>
<p>컴포넌트는 사라지지만,</p>
<ul>
<li>타이머</li>
<li>이벤트 리스너</li>
<li>웹소켓 연결</li>
<li>외부 라이브러리</li>
</ul>
<p>같은 것들은 자동으로 정리되지 않습니다.
정리를 하지 않으면</p>
<ul>
<li>메모리 누수</li>
<li>의도치 않은 동작</li>
<li>존재하지 않는 컴포넌트에 대한 상태 업데이트</li>
</ul>
<p>같은 문제가 생길 수 있기 때문에 정리가 필요합니다.</p>
</blockquote>
<hr>
<h1 id="4-라이프사이클-메서드가-두-번씩-호출되는-이유">4. 라이프사이클 메서드가 두 번씩 호출되는 이유</h1>
<p>리액트에서 컴포넌트의 라이프사이클 메서드나 useEffect가 개발 환경에서 두 번 호출되는 현상은 버그가 아니라 의도된 동작입니다.
이는 Vite로 프로젝트를 생성했을 때 기본으로 적용되는 main.jsx의 <StrictMode> 때문이며, 개발 모드에서만 발생합니다.</p>
<h2 id="strict-mode란-무엇인가">Strict Mode란 무엇인가</h2>
<p><code>&lt;StrictMode&gt;</code>는 리액트 애플리케이션을 더 안전하게 만들기 위한 개발 도구로, 프로덕션 빌드에는 영향을 주지 않으며, 개발 중에만 잠재적인 문제를 미리 발견하도록 돕습니다.</p>
<h3 id="strict-mode에서는-컴포넌트가-다음과-같은-이유로-의도적으로-한-번-더-실행됩니다">Strict Mode에서는 컴포넌트가 다음과 같은 이유로 의도적으로 한 번 더 실행됩니다.</h3>
<ul>
<li>컴포넌트가 순수 함수인지 확인하기 위해</li>
<li>Effect의 cleanup 누락을 확인하기 위해</li>
<li>상태 관련 버그를 조기에 발견하기 위해</li>
<li>더 이상 사용되지 않는 API에 대한 경고를 위해</li>
</ul>
<p><strong>리액트의 모든 컴포넌트는 순수 함수임을 가정하기 때문에 동일한 입력에 대해(props, state, context) 동일한 출력(JSX)을 반환해야 합니다.</strong></p>
<hr>
<p>  이상 컴포넌트 생명주기(라이프 사이클)에 대한 정리를 마치겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React/JavaScript] 리액트 개발에 자주 사용하는 자바스크립트 문법 - 1]]></title>
            <link>https://velog.io/@sohyerim-dev/ReactJavaScript-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%97%90-%EC%9E%90%EC%A3%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EB%B2%95-1</link>
            <guid>https://velog.io/@sohyerim-dev/ReactJavaScript-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EA%B0%9C%EB%B0%9C%EC%97%90-%EC%9E%90%EC%A3%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%AC%B8%EB%B2%95-1</guid>
            <pubDate>Fri, 05 Dec 2025 13:32:49 GMT</pubDate>
            <description><![CDATA[<h1 id="1-es6-화살표-함수">1. ES6 화살표 함수</h1>
<ul>
<li>화살표 함수는 함수 표현식의 대안으로 간결하게 함수를 정의할 수 있으며, 익명 함수로도 정의가 가능하다. 실행할 코드가 하나만 있다면, 함수 본문의 중괄호 생략이 가능하며 함수의 코드가 자동으로 리턴값으로 사용된다. 매개 변수가 하나만 있다면 매개변수의 괄호 또한 생략이 가능하다.</li>
<li><ul>
<li>화살표 함수 예시**<pre><code class="language-javascript">// 기존 함수 표현식
const add = function(x, y) {
return x + y;
};
</code></pre>
</li>
</ul>
</li>
</ul>
<p>// 화살표 함수
const add = (x, y) =&gt; {
  return x + y;
};</p>
<p>// 화살표 함수 축약
const add = (x, y) =&gt; x + y ;</p>
<p>// -----------------------------------</p>
<p>// 기존 함수 표현식
const add10 = function(x) {
  return x + 10;
};</p>
<p>// 화살표 함수
const add10 = (x) =&gt; {
  return x + 10;
};</p>
<p>// 화살표 함수 축약
const add10 = x =&gt; x + 10;</p>
<pre><code>
# 2. 구조 분해 할당(Destructuring assignment)
- 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있는 표현식을 말한다.
** 배열 구조 분해 **
```javascript
const player = [&#39;손흥민&#39;, &#39;이강인&#39;, &#39;김민재&#39;];
const [one, two, three] = player;
console.log(one, two, three); // 손흥민, 이강인, 김민재</code></pre><p>** 객체 구조 분해 **</p>
<pre><code class="language-javascript">const so = { userName: &#39;소혜림&#39;, userAge: 34 };
const {userName, userAge: age} = so;
console.log(userName, age); // 소혜림 34</code></pre>
<h1 id="3-나머지-매개변수-rest-parameters">3. 나머지 매개변수 (Rest parameters)</h1>
<ul>
<li>정해지지 않은 수의 매개변수를 배열로 전달 받으며, 함수의 마지막 매개변수 앞에 ...을 붙인다.<pre><code class="language-javascript">function fn(a, b, ...args) {
console.log(a, b, args);
}
</code></pre>
</li>
</ul>
<p>fn(); // undefined undefined []
fn(1); // 1 undefined []
fn(2, 3); / 2 3 []
fn(7, 8, 9, 10, 11); // 7, 8, [9, 10, 11]</p>
<pre><code>
# 4. 전개 구문(Spread syntax)
- 배열이나 객체의 요소, 속성을 분해해서 배열, 객체, 함수에 전달하는 것으로 이터러블 객체(배열, 객체 등)를 손쉽게 복사할 수 있다.
- 배열, 객체의 리터럴이나 함수의 인자값 변수 앞에 ...을 붙이며, 나머지 매개변수는 여러 매개변수를 하나의 배열로 압축하는 반면 전개 연산자는 하나의 배열 객체를 여러 개의 요소, 속성으로 분해해서 전달한다.
```javascript
const state = [&#39;orange&#39;, &#39;yellow&#39;, &#39;green&#39;];
const newState = [...state]; // [&#39;ornage&#39;, &#39;yellow&#39;, &#39;green&#39;]

const state2 = {name: &#39;하츄핑&#39;, age: 10};
const newState2 = {...state2}; // {name: &#39;하츄핑&#39;, age: 10}

function sum(x, y) {
  return x+ y;
}
const numbers = [1, 2];
console.log(sum(...numbers)); //3</code></pre><h1 id="5-삼항-연산자-조건부-연산자">5. 삼항 연산자 (조건부 연산자)</h1>
<ul>
<li>조건에 따라 값을 선택하는 연산자다.</li>
<li><code>조건 ? 참일 때의 값 : 거짓일 때의 값;</code><pre><code class="language-javascript">const num = 10;
const result = num &amp; 2 === 0 ? &#39;짝수&#39; : &#39;홀수&#39;;
console.log(result); // &#39;짝수&#39;</code></pre>
</li>
</ul>
<h1 id="6-배열-메서드">6. 배열 메서드</h1>
<h2 id="6-1-배열-요소-추가제거">6-1 배열 요소 추가/제거</h2>
<p><strong>1) push(...items): number</strong></p>
<ul>
<li>배열의 마지막 위치에 items 요소들을 추가하고 새로운 배열 길이를 반환한다.</li>
</ul>
<p><strong>2) pop(): string|undefined</strong></p>
<ul>
<li>배열의 마지막 요소를 제거하고 반환한다.<pre><code class="language-javascript">const fruits = [&#39;사과&#39;, &#39;바나나&#39;];
</code></pre>
</li>
</ul>
<p>const newLength = fruits.push(&#39;오렌지&#39;);
console.log(newLength, fruits); // 3 [&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;]</p>
<p>fruits.push(&#39;딸기&#39;, &#39;포도&#39;);
console.log(fruits); // [&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;, &#39;딸기&#39;, &#39;포도&#39;]</p>
<p>let lastFruit = fruits.pop();
console.log(lastFruit, fruits); 포도 [&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;, &#39;딸기&#39;]</p>
<p>lastFruit = fruits.pop();
console.log(lastFruit, fruits); 딸기 [&#39;사과&#39;, &#39;바나나&#39;, &#39;오렌지&#39;]</p>
<pre><code>
**3) unshift(...items): number**
- 배열의 맨앞에 items 요소들을 삽입하고 새로운 배열 길이를 반환한다.

**4) shift():string|undefined**
- 배열의 첫 번째 요소를 제거하고 반환한다.
```javascript
const fruits = [&#39;사과&#39;, &#39;바나나&#39;];

const newLength = fruits.unshift(&#39;딸기&#39;);
console.log(newLength, fruits); // 3 [&#39;딸기&#39;, &#39;사과&#39;, &#39;바나나&#39;]

fruits.unshift(&#39;딸기&#39;, &#39;포도&#39;);
console.log(fruits); // [&#39;딸기&#39;, &#39;포도&#39;, &#39;딸기&#39;, &#39;사과&#39;, &#39;바나나&#39;]

let firstFruit = fruits.shift();
console.log(firstFruit, fruits); // 딸기 [&#39;포도&#39;, &#39;딸기&#39;, &#39;사과&#39;, &#39;바나나&#39;]

firstFruit = fruits.shift();
consolo.log(firstFruit, fruits); // 포도 [&#39;딸기&#39;, &#39;사과&#39;, &#39;바나나&#39;]</code></pre><p><strong>5) splice(start:number, deleteCount?:number, ...items):any[]</strong></p>
<ul>
<li>배열에서 요소를 추가, 제거 또는 교체한다.</li>
<li>start: 시작 인덱스</li>
<li>deleteCount: 제거할 요소 수</li>
<li>items: 삽입할 요소 목록<pre><code class="language-javascript">const arr1 = [&#39;신라면&#39;, &#39;열라면&#39;, &#39;비빔면&#39;, &#39;오징어짬뽕&#39;, &#39;육개장&#39;, &#39;왕뚜껑&#39;, &#39;삼양라면&#39;];
</code></pre>
</li>
</ul>
<p>let arr2 = arr1.splice(1, 2); // 인덱스 1부터 2개 추출
console.log(arr1, arr2); // [&#39;신라면&#39;, &#39;오징어짬뽕&#39;, &#39;육개장&#39;, &#39;왕뚜껑&#39;, &#39;삼양라면&#39;] [&#39;열라면&#39;, &#39;비빔면&#39;]
arr2 = arr1.splice(2, 2); // 인덱스 2부터 2개 추출
console.log(arr1, arr2); // [&#39;신라면&#39;, &#39;오징어짬뽕&#39;, &#39;삼양라면&#39;] [&#39;육개장&#39;, &#39;왕뚜껑&#39;]</p>
<p>arr2= arr1.splice(2); // 인덱스 2부터 끝까지 추출
console.log(arr1, arr2); // [&#39;신라면&#39;, &#39;오징어짬뽕&#39;] [&#39;삼양라면&#39;]</p>
<p>arr2 = arr1.splice(1, 1, &#39;진라면&#39;, &#39;불닭볶음면&#39;); // 인덱스 1부터 1개 추출하고 진라면, 불닭볶음면 추가
console.log(arr1, arr2); // [&#39;신라면&#39;, &#39;진라면&#39;, &#39;불닭볶음면&#39;] [&#39;오징어짬뽕&#39;]</p>
<pre><code>
**6) slice(start?:number, end?:number):any[]**
- 배열의 지정한 범위를 복사해서 새 배열로 반환한다.
- start: 시작 인덱스(기본값 0)
- end: 종료 인덱스(기본값 length)
```javascript
const arr1 = [&#39;토끼&#39;, &#39;사자&#39;, &#39;호랑이&#39;, &#39;강아지&#39;, &#39;고양이&#39;, &#39;기니피그&#39;, &#39;돼지&#39;];

let arr2 = arr1.slice(1, 3); // 인덱스 1부터 3 앞까지 복사
console.log(arr2); // [&#39;사자&#39;, &#39;호랑이&#39;]

arr2 = arr1.slice(2, 2); // 인덱스 2부터 2 앞까지 복사
console.log(arr2); // []

arr2 = arr1.slice(5); // 인덱스 5부터 끝까지 복사
console.log(arr2); // [&#39;기니피그&#39;, &#39;돼지&#39;]

arr2 = arr.slice(-2); //인덱스 -2부터 끝가지 복사
console.log(arr2); // [&#39;기니피그&#39;, &#39;돼지&#39;]

console.log(arr1); // [&#39;토끼&#39;, &#39;사자&#39;, &#39;호랑이&#39;, &#39;강아지&#39;, &#39;고양이&#39;, &#39;기니피그&#39;, &#39;돼지&#39;]</code></pre><p><strong>7) concat(...items): any[]</strong></p>
<ul>
<li>items 배열들을 병합한 새로운 배열을 반환한다.<pre><code class="language-javascript">const arr = [&#39;오렌지&#39;, &#39;딸기&#39;, &#39;레몬&#39;];
const arr2 = arr.concat([&#39;사과&#39;, &#39;바나나&#39;], [&#39;포도&#39;]);
console.log(arr2.includes(&#39;사과&#39;)); // true
</code></pre>
</li>
</ul>
<p>console.log(arr); // [ &#39;오렌지&#39;, &#39;딸기&#39;, &#39;레몬&#39; ]
console.log(arr2); // [ &#39;오렌지&#39;, &#39;딸기&#39;, &#39;레몬&#39;, &#39;사과&#39;, &#39;바나나&#39;, &#39;포도&#39; ]</p>
<pre><code>
## 6-2 배열 요소 검색
**1) indexOf(searchElement, fromIndex?:number):number**
- 배열의 요소 중 searchElement와 일치하는 첫 번째 요소의 인덱스를 반환. 일치하는 요소가 없으면 -1을 반환한다.
- `fromIndex`: 지정한 인덱스부터 탐색을 시작(기본값 0)
**2) lastIndexOf(searchElement, fromIndex?:number):number**
- 배열의 요소 중 searchElement와 일치하는 마지막 요소의 인덱스를 반환. 일치하는 요소가 없으면 -1을 반환한다.
- `fromIndex`: 지정한 인덱스부터 탐색을 시작 (기본값 0)
**3) includes(searchElement, fromIndex?:number):boolean**
- 배열의 요소 중 searchElement 값이 있는지 여부를 반환한다.
- `fromIndex`: 지정한 인덱스부터 탐색을 시작 (기본값 0)
```javascript
const arr = [1, 3, 5, 8, 9, 3, 4, 5];
console.log(&#39;첫 번째 3의 위치&#39;, arr.indexOf(3)); // 첫 번째 3의 위치 1
console.log(&#39;마지막 3의 위치&#39;, arr.lastIndexOf(3)); // 마지막 3의 위치 5

const arr2 = [&#39;오렌지&#39;, &#39;딸기&#39;, &#39;레몬&#39;];
console.log(arr2.includes(&#39;레몬&#39;)); //true
console.log(arr2.includes(&#39;사과&#39;)); // false</code></pre><h2 id="6-3-배열-반복-메서드">6-3 배열 반복 메서드</h2>
<p><strong>1) forEach(callbackFn(currentValue, index, array), thisArg?): void</strong></p>
<ul>
<li>배열의 각 요소에 대해 callbackFn 함수를 실행한다.</li>
<li>콜백 함수의 currentValue에는 배열의 요소가, Index에는 전달되는 요소의 인덱스가, array에는 원본 배열이 전달된다.</li>
<li>thisArg는 콜백 함수에서 this로 사용할 객체를 전달한다.</li>
<li>리턴값이 없다.</li>
<li><em>2) map(callbackFn(currentValue, index, array), thisArg?):any[]*</em></li>
<li>forEach와 동일하게 동작한다.</li>
<li>forEach는 리턴값이 없지만 map은 콜백 함수에서 리턴한 값을 새로운 배열로 만들어서 반환한다.<pre><code class="language-javascript">const arr = [10, 20, 30];
let newArr: number[] = [];
</code></pre>
</li>
</ul>
<p>// 배열의 각 요소를 순회하며 실행
arr.forEach((elem, i) =&gt; {
      newArr.push(elem **2);
});
console.log(&#39;forEach&#39;, newArr); // [100, 400, 900]</p>
<p>// 배열의 각 요소를 순회하며 반환받은 값으로 새로운 배열 생성
const newArr2 = arr.map(function(elem, i) {
  // 요소의 제곱값 반환
  return elem **2;
});
console.log(&#39;map&#39;, newArr2); // [100, 400, 900]</p>
<pre><code>**3) find(callbackFn, thisArg?):any|undefined**
- 배열의 각 요소에 대해 callbackFn 함수가 호출된다.
- true를 반환한 첫 콜백 함수에 전달된 엘리먼트가 find의 결과로 반환된다.
- true를 반환한 콜백 함수가 없을 경우 undefined가 반환된다.
**4) findIndex(callbackFn, thisArg?):number**
- 배열의 각 요소에 대해 callbackFn 함수가 호출된다.
- true를 반환한 첫 콜백 함수에 전달된 인덱스가 findIndex의 결과로 반환된다.
- true를 반환한 콜백 함수가 없을 경우 -1이 반환된다.
**5) filter(callbackFn, thisArg?): any[]**
- 배열의 각 요소에 대해 callbackFn 함수가 호출된다.
- true를 반환한 콜백 함수에 전달된 요소만 모아서 새로운 배열로 반환한다.
- true를 반환한 콜백 함수가 없을 경우 빈 배열이 반환된다.
```javascript
const arr = [1, 3, 5, 8, 9, 3, 4, 5];
console.log(arr.find(num =&gt; num % 2 === 0)); // 8
console.log(arr.findIndex(num =&gt; num % 2 === 0)); // 3
console.log(arr.filter(n =&gt; n % 2 === 0)); // [8, 4]</code></pre><p><strong>6) some(callbackFn, thisArg?):boolean</strong></p>
<ul>
<li>배열의 각 요소에 대해 callbackFn 함수가 호출된다.</li>
<li>콜백 함수 중 하나라도 true를 반환하면 some은 true를 반환한다.</li>
<li>콜백 함수 전부 true를 반환하지 않으면 some은 false를 반환한다.</li>
<li><em>7) every(callbackFn, thisArg?)boolean*</em></li>
<li>배열의 각 요소에 대해 callbackFn 함수가 호출된다.</li>
<li>콜백 함수 전부 true를 반환하면 every는 true를 반환한다.</li>
<li>콜백 함수 중 하나라도 true를 반환하지 않으면 every는 false를 반환한다.<pre><code class="language-javascript">const arr = [1, 2, 3];
const hasEven = arr.some(n =&gt; n % 2 === 0); // true
const isAllEven = arr.every(n =&gt; n % 2 === 0); // false
</code></pre>
</li>
</ul>
<p>console.log(hasEven, isAllEven); // true false</p>
<pre><code>**8) reduce(callbackFn(accumulator, currentValue, index, array), initialValue?):any**
- 배열의 각 요소에 대해 제공한 리듀서 함수를 실행한다.
- 이전 리듀서의 반환값이 다음 리듀서의 인자값으로 전달되며 최종적으로 하나의 결과값을 반환한다.
- 리듀서가 처음 실행되면 &quot;이전 리듀서의 반환값&quot;이 없으므로 reduce 함수의 두 번째 인자로 전달하는 값을 사용하거나 두번째 인자가 생략될 경우 배열의 Index 0 값이 지정되고 배열의 두 번째 요소부터 리듀서가 실행된다.
```javascript
const arr = [1, 2, 3, 4];
const initialValue = 0;
const sum = arr.reduce(function(accumulator, currentValue){
  return accumulator + currentValue
}, initialValue);

console.log(sum); // 0 + 1 + 2 + 3 + 4 = 10</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 동기/비동기 방식, async/defer]]></title>
            <link>https://velog.io/@sohyerim-dev/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-async-defer</link>
            <guid>https://velog.io/@sohyerim-dev/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-async-defer</guid>
            <pubDate>Mon, 03 Nov 2025 13:07:19 GMT</pubDate>
            <description><![CDATA[<p>개발을 배우다 보면 ‘동기’와 ‘비동기’라는 말을 한 번쯤은 들어봤을 것이다. 오늘 수업에서 이 내용을 배웠기 때문에, 배운 내용을 나만의 방식으로 다시 설명해보려 한다.</p>
<h1 id="동기-방식">동기 방식</h1>
<p>우선, 아래와 같은 HTML 마크업과 4개의 스크립트가 있다고 가정해보자.
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/87054847-21df-4801-a9e2-5ec3cc6b3bc3/image.jpg" alt="HTML 마크업 예시"><img src="https://velog.velcdn.com/images/sohyerim-dev/post/cc0035f3-90d8-482d-b894-2ee6adaf40e2/image.png" alt="자바스크립트 코드 예시">(자바스크립트 코드의 경우, 변수로 선언한 버튼만 다르고 코드가 반복되어 스크립트 하나만 첨부함.)</p>
<ul>
<li>html 마크업 내에 body 태그 안 가장 아래에 버튼 4개가 있고,</li>
<li>4개의 버튼에 이벤트를 추가하는 함수가 등록된 스크립트는 head태그 안에 각각 차례대로 존재한다.</li>
<li><strong><em>동기 방식의 경우 직렬로 위에서 아래로 차례대로 파싱을 하는게 원칙이다.</em></strong>
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/c7029da1-d108-41b1-908e-421c7f680865/image.jpg" alt="동기방식"></li>
<li>그렇기 때문에, 위에서 아래로 차례대로 파싱을 하다가 script 태그를 만나면 HTML 파싱을 멈추고, 스크립트 로드(Script fetch)와 스크립트 실행(Script Execution)을 진행한다. </li>
<li>스크립트 실행이 진행되는 때에 스크립트 코드 안에서 변수로 선언한 버튼 요소가 파싱되지 않은 시점이기 때문에 타입에러가 발생하게 된다.
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/099475e6-a19c-4d4d-9b92-62ed4fad7c1b/image.png" alt="콘솔에러"></li>
<li>만일 스크립트 코드 내에 문제가 없어서 에러가 발생하지 않았다고 가정한다면, 스크립트 로드와 실행이 끝난 이후 HTML 파싱을 재개하게 된다.</li>
</ul>
<h1 id="비동기-방식">비동기 방식</h1>
<ul>
<li><strong><em>동기 방식과는 달리 비동기 방식은 HTML파싱과 스크립트 로드를 병렬로(동시에) 진행한다.</em></strong></li>
<li>단, 스크립트 실행 방식에 따라 두 경우로 나눌 수 있는데, async와 defer가 그러하다.</li>
<li>두 경우 모두 외부 스크립트(src 속성으로 적용한 경우)에만 적용 가능하다.
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/f183180e-d0c8-4720-8df8-9eb591b74fff/image.jpg" alt="async와 defer"></li>
</ul>
<h2 id="async스크립트-즉시-실행">async(스크립트 즉시 실행)</h2>
<ul>
<li>async의 경우 스크립트 로드는 HTML과 동시에 진행하지만, 스크립트 로드가 끝나면 HTML 파싱을 멈추고, 스크립트 실행을 진행한다.</li>
<li>그렇기 때문에 async를 스크립트에 적용할 경우 HTML 파싱이 끝나기 전에 스크립트가 먼저 실행이 될 가능성이 있다.</li>
<li>또한, 스크립트간 실행 순서가 보장되지 않는다.</li>
<li>그렇기 때문에, async는 방문자 수 카운트, 접속 통계 기록 등과 같이 페이지 내의 스크립트와 독립적인 기능 사용시 주로 사용한다.<h2 id="defer스크립트-지연-실행">defer(스크립트 지연 실행)</h2>
</li>
<li>반면에 defer는 스크립트 로드를 끝마치더라도 HTML 파싱이 모두 끝날 때 까지 기다렸다가 스크립트를 실행한다.</li>
<li>또한, defer 속성을 적용한 스크립트가 여러 개 있을 경우, 작성 순서대로 순차 실행한다.</li>
<li>그렇기 때문에 페이지 렌더링이 우선시 되는 경우에 주로 사용한다.</li>
<li>또한, type=&quot;module&quot; 속성이 있으면 기본적으로 defer 속성으로 동작하게 된다.</li>
</ul>
<p>이상 오늘 배운 내용을 정리해 보았습니다. 읽는 분들께 도움 되시길!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[웹 브라우저 프로그래밍] 노드 찾기 (+요소노드 내부 콘텐츠 제어)]]></title>
            <link>https://velog.io/@sohyerim-dev/%EB%85%B8%EB%93%9C%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@sohyerim-dev/%EB%85%B8%EB%93%9C%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Mon, 20 Oct 2025 12:17:03 GMT</pubDate>
            <description><![CDATA[<p>노드 찾기에 대해 알아보기 전에 DOM에 대해 먼저 알아봅시다.</p>
<h1 id="domdocument-object-model이란">DOM(Document Object Model)이란?</h1>
<ul>
<li>브라우저가 HTML 문서를 <strong>객체의 트리 구조</strong>로 표현한 모델(부모-자식 관계로 연결된 계층 구조)</li>
<li>브라우저는 웹서버에서 다운로드 받은 텍스트 기반의 HTML문서를 파싱하면서 HTML 문서의 각 구성 요소를 트리 구조의 객체로 만들어 자바스크립트로 제공한다.</li>
<li><strong>노드(Node)</strong>: DOM 트리 구조의 모든 구성원은 각각의 객체로 인식되며 이러한 객체 하나 하나를 노드라고 한다.</li>
<li>DOM API를 이용하면 정적인 HTML 문서를 자바스크립트로 동적으로 제어하는게 가능하다.(특정 요소를 찾거나 생성, 삽입, 삭제, 이동 등)</li>
</ul>
<h2 id="dom-apidom-application-programming-interface">DOM API(DOM Application Programming Interface)</h2>
<ul>
<li>DOM을 조작할 수 잇는 속성과 메서드들의 집합</li>
<li>querySelector() : 요소 찾기</li>
<li>createElement() : 요소 생성</li>
<li>remove() : 요소 삭제</li>
<li>appendChild() : 요소 삽입, 이동</li>
<li>...</li>
</ul>
<h2 id="doument-객체">Doument 객체</h2>
<ul>
<li>브라우저의 최상위 객체는 window, 웹페이지의 최상위 객체는 window.document(window 생략 가능)</li>
<li>HTML 문서 전체를 나타낸다.</li>
<li>모든 DOM 조작의 시작점</li>
</ul>
<h2 id="주요-노드">주요 노드</h2>
<ul>
<li><p>DOM에는 12 종류의 노드가 존재하며 주요 노드는 다음과 같다.</p>
<ul>
<li>문서 노드(document node): 문서 전체</li>
<li>요소 노드(element node): HTML 태그</li>
<li>속성 노드(attribute node): 태그의 속성</li>
<li>텍스트 노드(text node): 태그 내의 텍스트 내용</li>
<li>...</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>종류</th>
<th>설명</th>
<th>nodeName</th>
<th>nodeType</th>
<th>nodeValue</th>
</tr>
</thead>
<tbody><tr>
<td>문서 노드</td>
<td>문서 전체</td>
<td>#document</td>
<td>9</td>
<td>null</td>
</tr>
<tr>
<td>요소 노드</td>
<td>태그</td>
<td>태그의 이름</td>
<td>1</td>
<td>null</td>
</tr>
<tr>
<td>속성 노드</td>
<td>요소의 속성</td>
<td>속성의 이름</td>
<td>2</td>
<td>속성의 값</td>
</tr>
<tr>
<td>텍스트 노드</td>
<td>요소의 내용</td>
<td>#text</td>
<td>3</td>
<td>문자열 값</td>
</tr>
</tbody></table>
<p>이제 노드 찾기를 알아 보기 전에 알아야 할 내용을 살펴 봤으니 본격적으로 노드 찾기에 대해 알아봅시다.</p>
<h1 id="노드-찾기">노드 찾기</h1>
<h2 id="1-태그의-id로-노드-찾기">1. 태그의 id로 노드 찾기</h2>
<ul>
<li>document.getElementById(id) : HTML 문서에서 해당 id를 가진 요소를 찾아서 반환한다.</li>
<li><em>❗️ id로 선택한 요소는 단 하나만 반환한다.❗️*</em><pre><code class="language-html">&lt;!-- HTML 예제 --&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;선수 명단&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
 &lt;h1&gt;선수 명단&lt;/h1&gt;
 &lt;p&gt;대한민국 국가대표 팀에 포함된 선수&lt;/p&gt;
 &lt;ul id=&quot;player-list&quot; class=&quot;list&quot;&gt;
   &lt;li&gt;손흥민&lt;/li&gt;
   &lt;li&gt;김민재&lt;/li&gt;
   &lt;li&gt;이강인&lt;/li&gt;
 &lt;/ul&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<pre><code class="language-javascript">// id가 player-list인 ul 요소를 선택하기
const playerList = document. getElementById(&#39;player-list&#39;);</code></pre>
<h2 id="2-태그명으로-노드-찾기">2. 태그명으로 노드 찾기</h2>
</li>
<li>document(또는)요소노드.getElementsByTagName(tagName) : 문서 전체 또는 지정한 요소노드의 하위 모든 요소를 대상으로 태그명에 해당하는 요소노드를 NodeList(유사배열객체)로 반환한다.</li>
<li><em>❗️태그명에 해당하는 요소노드가 한 개라도 객체로 반환한다.❗️*</em><pre><code class="language-javascript">// 위에서 선택한 ul 하위의 li 태그명을 가진 요소노드를 유사배열 객체로 반환
const liList = buyList.getElementsByTagName(&#39;li&#39;);</code></pre>
</li>
</ul>
<h2 id="3-트리구조로-노드-찾기">3. 트리구조로 노드 찾기</h2>
<h3 id="부모자식과-관련된-노드의-속성">부모/자식과 관련된 노드의 속성</h3>
<ul>
<li>childNodes : <strong>자식 노드(요소, 텍스트, 주석 등의 노드)</strong>의 목록이 저장된 <strong>NodeList(유사 배열 객체)</strong> 반환</li>
<li><ul>
<li>❗️요소, 텍스트, 주석 등을 모두 반환❗️ **</li>
</ul>
</li>
<li>children : <strong>자식 요소 노드</strong>의 목록이 저장된 <strong>HTMLCollection(유사 배열 객체)</strong> 반환</li>
<li><ul>
<li>❗️요소만 반환❗️**</li>
</ul>
</li>
</ul>
<ul>
<li>firstChild : <strong>첫 번째 자식 노드</strong> 반환</li>
<li>firstElementsChild : <strong>첫 번째 자식 요소 노드</strong> 반환</li>
</ul>
<ul>
<li>lastChild : <strong>마지막 자식 노드</strong> 반환</li>
<li>lastElementsChild : <strong>마지막 자식 요소 노드</strong> 반환</li>
</ul>
<ul>
<li>parentNode : <strong>부모 노드</strong> 반환</li>
<li>parentElement : <strong>부모 요소 노드</strong> 반환</li>
</ul>
<pre><code class="language-javascript">const playerList = document.getElementById(&#39;player-list&#39;);
const firstPlayer = playerList.firstElementChild;
const lastPlayer = playerList.lastElementChild;
const liList = playerList.childNodes;</code></pre>
<h3 id="형제와-관련된-노드의-속성">형제와 관련된 노드의 속성</h3>
<ul>
<li>previousSibling : <strong>바로 앞의 형제 노드(요소, 텍스트, 주석 등의 노드)</strong></li>
<li>previousElementSibling : <strong>바로 앞의 형제 요소 노드</strong></li>
</ul>
<ul>
<li>nextSibling : <strong>바로 뒤의 형제 노드(요소, 텍스트, 주석 등의 노드)</strong></li>
<li>nextElementSibling : <strong>바로 뒤의 형제 요소 노드</strong></li>
</ul>
<pre><code class="language-javascript">const playList = document.getElementById(&#39;player-list&#39;);
const secondPlayer = playerList.children[1]; // 유사 배열 객체로 반환하기 때문에 인덱스로 접근
const firstPlayer = secondPlayer.previousElementSibling;
const lastPlayer = secondPlayer.nextElementSibling;</code></pre>
<h2 id="class-속성으로-노드-찾기">class 속성으로 노드 찾기</h2>
<ul>
<li>document.getElementsByClassName(className) : 지정한 클래스명을 가진 요소 노드의 목록을 반환(NodeList, 유사 배열 객체)</li>
<li><em>❗️클래스는 여러 개일 수도 있기 때문에 여러 개 선택 가능❗️*</em><pre><code class="language-javascript">const playerList = document.getElementsByClassName(&#39;list&#39;)[0];
// list라는 클래스를 가진 요소 중 첫 번째 요소를 반환</code></pre>
</li>
</ul>
<h2 id="css-셀렉터로-노드-찾기">CSS 셀렉터로 노드 찾기</h2>
<ul>
<li>Selector : CSS에서 사용하는 노드 선택 구문</li>
<li>document.querySelector(selector) : 지정한 selector 구문에 매칭되는 노드 목록 중 첫번째 노드 반환 (하나만 선택할 때 사용)</li>
<li>document.querySelectorAll(selector) : 지정한 selector 구문에 매칭되는 노드 목록을 반환(NodeList, 유사 배열 객체/ 여러 개 선택할 때 사용)</li>
<li><em>❗️querySelectorAll로 선택한 NodeList는 유사 배열 객체이지만, forEach 메서드 사용 가능❗️*</em><pre><code class="language-javascript">const playerList = document.querySelector(&#39;.list&#39;);
const playerList = document.querySelector(&#39;#buy-list&#39;);
const playerList = document.querySelectorAll(&#39;ul&#39;)[0];
// querySelectorAll의 경우 다수가 선택되기 때문에 하나에만 접근하기 위해 인덱스를 사용</code></pre>
</li>
</ul>
<p>이상 노드 찾기에 대해 알아봤습니다.
하나만 선택할지 여러 개를 선택할지,
혹은 자식 노드를 선택할지 자식 요소 노드를 선택할지에 따라
사용해야 하는 속성이 다르기 때문에 주의하여 사용할 필요가 있습니다. </p>
<p>추가적으로 요소 노드 내부 컨텐츠를 제어하는 것도 알아보겠습니다!</p>
<h1 id="요소노드의-내부-콘텐츠-제어">요소노드의 내부 콘텐츠 제어</h1>
<h2 id="innerhtml과-outerhtml">innerHTML과 outerHTML</h2>
<ul>
<li>elem.innerHTML : elem의 내부 HTML 코드의 값을 조회하거나 수정 <strong>(elem 자신은 제외)</strong></li>
<li>elem.outerHTML : <strong>elem 자신을 포함</strong>하여 elem 내부 HTML 코드의 값을 조회하거나 수정<pre><code class="language-html">&lt;ul id=&quot;nct-wish&quot; class=&quot;members&quot;&gt;
&lt;li&gt;시온&lt;/li&gt;
&lt;li&gt;리쿠&lt;/li&gt;
&lt;li&gt;유우시&lt;/li&gt;
&lt;li&gt;재희&lt;/li&gt;
&lt;li&gt;료&lt;/li&gt;
&lt;li&gt;사쿠야&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<pre><code class="language-javascript">const memberList = document.querySelector(&#39;#nct-wish&#39;);
console.log(memberList.innerHTML);
// &#39;\n     &lt;li&gt;시온&lt;/li&gt;\n  &lt;li&gt;리쿠&lt;/li&gt;\n  &lt;li&gt;유우시&lt;/li&gt;\n  &lt;li&gt;재희&lt;/li&gt;\n  &lt;li&gt;료&lt;/li&gt;\n  &lt;li&gt;사쿠야&lt;/li&gt;\n  &#39;
console.log(memberList.outerHTML);
// &#39;&lt;ul id=&quot;nct-wish&quot; class=&quot;members&quot;&gt;\n     &lt;li&gt;시온&lt;/li&gt;\n  &lt;li&gt;리쿠&lt;/li&gt;\n  &lt;li&gt;유우시&lt;/li&gt;\n  &lt;li&gt;재희&lt;/li&gt;\n  &lt;li&gt;료&lt;/li&gt;\n  &lt;li&gt;사쿠야&lt;/li&gt;\n  &lt;/ul&gt;&#39;</code></pre>
<h2 id="textcontent와-innertext">textContent와 innerText</h2>
</li>
<li>elem.textContent : elem의 내부 텍스트 노드의 소스코드 값 그대로 조회하거나 수정</li>
<li>elem.innerText : elem의 내부 텍스트 노드의 브라우저에 실제 보이는 값만 조회하거나 수정 <strong>(화면에 보이지 않는 요소는 제외)</strong><pre><code class="language-html">&lt;ul id=&quot;song-list&quot; class=&quot;list&quot;&gt;
  &lt;li&gt;Steady&lt;span&gt;✔️&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;WISH&lt;span hidden&gt;✔️&lt;/span&gt;&lt;/li&gt;
  &lt;li&gt;Songbird&lt;span&gt;✔️&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<pre><code class="language-javascript">const secondLi = document.querySelector(&#39;#song-list &gt; li:nth-child(2)&#39;);
console.log(secondLi.textContent); // WISH✔️ 출력
console.log(secondLi.innerText); // WISH만 출력</code></pre>
</li>
</ul>
<p>이상 요소 노드의 콘텐츠 내부를 제어하는 방법까지 알아 보았습니다.
요소 노드의 콘텐츠 내부를 제어할 때에는 어떤 것 까지 포함하여 제어하고 싶은지에 따라 주의하여 사용할 필요가 있습니다. 이상입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 브라우저 렌더링(Reflow, Repaint)]]></title>
            <link>https://velog.io/@sohyerim-dev/ReflowAndRepaint</link>
            <guid>https://velog.io/@sohyerim-dev/ReflowAndRepaint</guid>
            <pubDate>Thu, 02 Oct 2025 08:15:34 GMT</pubDate>
            <description><![CDATA[<p>수업 중 강사님께서 Reflow와 Repaint에 대해 언급하셨고, 이에 대해 자세히 공부해보라는 말씀에 이번 기회에 브라우저 랜더링에 대해 알아 보았습니다.</p>
<p>우선, 웹브라우저는 어떤 일을 할까요? 우리가 작성한 HTML, CSS, Javascript를 읽고 웹페이지를 그려주는 일을 하는데요.</p>
<p>이때, 브라우저에서 어떤 일이 일어나는지를 알아봅시다.
아래는 웹 브라우저의 기본 구조를 보여주는 그림과 설명입니다.</p>
<p>웹 브라우저의 구조
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/1196133a-323c-49a0-9031-c9350b667d72/image.png" alt="웹 브라우저의 구조"></p>
<h2 id="1-사용자-인터페이스user-interface">(1) 사용자 인터페이스(User Interface)</h2>
<p>웹 페이지를 제외한 주소 표시줄, 이전/다음/새로고침 버튼, 북마크 등 사용자와 상호작용하는 부분</p>
<h2 id="2-브라우저-엔진browser-engine">(2) 브라우저 엔진(Browser Engine)</h2>
<p>유저 인터페이스와 렌더링 엔진 사이에서 동작을 제어하고 연결하는 엔진</p>
<h2 id="3-렌더링-엔진rendering-engine">(3) 렌더링 엔진(Rendering Engine)</h2>
<p>HTML과 CSS를 파싱하여 요청한 웹 페이지(콘텐츠)를 표시하는 엔진</p>
<h2 id="4-자료-저장소data-persistence">(4) 자료 저장소(Data Persistence)</h2>
<p>로컬 저장소(localStorage)나 쿠키(Cookie)와 같이 보조 기억장치에 데이터를 저장하는 파트</p>
<h2 id="5-통신networking">(5) 통신(Networking)</h2>
<p>각종 네트워크 요청을 수행하는 파트</p>
<h2 id="6-자바스크립트-해석기javascript-interpreter">(6) 자바스크립트 해석기(Javascript Interpreter)</h2>
<p>자바스크립트 코드를 실행하는 파트</p>
<h2 id="7-ui-백엔드ui-backend">(7) UI 백엔드(UI Backend)</h2>
<p>예를 들어, 콤보박스나 창과 같은 기본적인 장치를 그려주는 UI 백엔드 파트</p>
<hr>
<p>이 중에서 우리는 렌더링 엔진에 대해 자세히 알아봅시다.
우선, 여러 브라우저는 각 브라우저마다 다른 렌더링 엔진을 사용합니다. (Safari는 Webkit, Firfox는 Gecko, Chrome은 Blink 등)
모든 렌더링 엔진은 웹표준을 준수하면서도 엔진마다 조금씩 다르게 동작하는 부분이 있습니다.</p>
<p>렌더링 엔진은 두가지 목표를 가집니다.
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/058f351f-055c-46d5-a11b-889af70b2df2/image.png" alt="핵심 렌더링 경로">
HTML, CSS, JS, 이미지 등 웹페이지에 포함된 모든 요소들을 화면에 보여줍니다.
업데이트가 필요할 때, 효율적으로 렌더링을 할 수 있도록 자료 구조를 생성합니다.
(업데이트의 예 : 사용자에 의한 입력 발생, 스크롤, 애니메이션, 비동기 요청으로 인한 데이터 로딩 등)
이런 목표를 위해서 렌더링 엔진은 크게 다음의 과정을 거쳐서 동작합니다.</p>
<h3 id="1-dom-tree-생성">(1) DOM Tree 생성</h3>
<p><img src="https://velog.velcdn.com/images/sohyerim-dev/post/c3f73a5e-de22-428f-afb4-823baac187a5/image.png" alt="토큰화">
위 예시의 마크업 코드는 토큰화(Tokenization) 과정을 거쳐 HTML5에서 정의한 고유한 토큰으로 변환됩니다.
이후 브라우저는 트리 구성(Tree Construction) 단계를 통해 토큰을 노드 객체로 변환하고, 최종적으로 DOM 트리를 만듭니다.</p>
<p><img src="https://velog.velcdn.com/images/sohyerim-dev/post/a43f6f33-0949-4484-8cbe-f2bff9a77a6e/image.png" alt="DOM Tree 생성">
<em>(요소와 속성, 텍스트를 계층적 노드 구조로 표현한 객체 모델)</em>
또한, 브라우저는 HTML을 파싱하는 과정에서 자바스크립트나 CSS와 같은 필요한 파일들을 불러오기도 하는데, 브라우저는 DOM Tree를 생성하듯이 CSS를 파싱하여 CSSOM Tree를 생성합니다.</p>
<h3 id="2-cssom-tree-생성">(2) CSSOM Tree 생성</h3>
<p><img src="https://velog.velcdn.com/images/sohyerim-dev/post/1138f06e-1509-4c99-822e-11d3dc5f70a0/image.png" alt="CSSOM Tree 생성">
DOM Tree와 CSSOM Tree가 모두 생성되면, 렌더링 엔진이 DOM Tree와 CSSOM Tree를 합쳐서 Render Tree를 생성합니다.</p>
<h3 id="3-render-tree-생성">(3) Render Tree 생성</h3>
<p><img src="https://velog.velcdn.com/images/sohyerim-dev/post/65440e6b-3a6b-4bfb-8d26-31058a04c9a9/image.png" alt="Render Tree 생성">
<em>(참고로 간소화한 랜더트리입니다. 실제로는 더 많은 정보를 가지고 있고, 브라우저마다 조금씩 다르게 생성됩니다.)</em>
Render Tree는 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보를 포함하는 트리를 말합니다.
이때, meta태그나 display:none;같은 속성은 트리에 포함하지 않습니다.</p>
<p>Render Tree가 생성되면, Layout이라는 과정을 거칩니다
뷰포트 내에서 요소들의 정확한 위치와 크기를 계산하는 과정으로 박스 모델에 따라서 텍스트나 요소의 박스가 화면에서 차지하는 영역이나 여백 그리고 이외의 스타일 속성이 계산됩니다.</p>
<p>레이아웃 과정에서 렌더링 엔진이 각 요소들이 어떻게 생겼고, 어떻게 보여줘야 할지 알게 되면 화면에 실제 픽셀로 그려지도록 변환하는 과정을 거치는데, 이를 Paint 과정이라고 합니다.</p>
<p>이렇게 렌더링 엔진이 어떻게 동작하는지를 알아봤습니다.
위에서 알아 본 핵심 렌더링 경로(Critical Rendering Path)의 시간을 줄이면, 브라우저가 웹 페이지를 보여주는 시간도 줄일 수 있게 됩니다.</p>
<p>그런데 사용자 동작으로 자바스크립트가 실행되어서 CSS가 변경되거나 애니메이션 재생이 일어났을 때 무슨 일이 일어날까요?</p>
<p>이런 경우 3가지의 상황이 생길 수 있습니다.
<img src="https://velog.velcdn.com/images/sohyerim-dev/post/3c5e5855-3106-4587-b4aa-920217790112/image.png" alt="Reflow"></p>
<h3 id="ui가-업데이트되는-3가지-상황">UI가 업데이트되는 3가지 상황</h3>
<h4 id="1-reflow-리플로우">1. Reflow (리플로우)</h4>
<ul>
<li>정의: 요소의 크기나 위치가 변할 때, 브라우저가 레이아웃을 다시 계산하는 과정.</li>
<li>발생 조건:<ul>
<li>브라우저 창 크기 변경</li>
<li>크기(높이, 너비, margin 등) 변경</li>
<li>위치(position, left/right 등) 변경</li>
<li>레이아웃(display, flex 등) 변경</li>
<li>폰트 크기/굵기(font-size, font-weight 등) 변경</li>
</ul>
</li>
<li>과정: 레이아웃 → 페인트 → 합성</li>
<li>특징: 부모의 변화가 자식에게 전파되며 CPU 부하가 큼. 성능에 가장 큰 영향을 미침.</li>
</ul>
<h4 id="2-repaint-리페인트">2. Repaint (리페인트)</h4>
<ul>
<li>정의: 요소의 시각적 표현(색상 등) 만 변할 때, 다시 화면에 그리는 과정.</li>
<li>발생 조건:<ul>
<li>색상(color, background-color 등) 변경</li>
<li>테두리(border-color, border-radius 등) 변경</li>
<li>그림자(box-shadow 등) 변경</li>
</ul>
</li>
<li>과정: 페인트 → 합성</li>
<li>특징: 레이아웃은 변하지 않고 GPU를 주로 사용. 상대적으로 비용이 적음.</li>
</ul>
<h4 id="3-레이어-합성만-발생하는-경우">3. 레이어 합성만 발생하는 경우</h4>
<ul>
<li>레이아웃, 페인트 없이 합성 단계만 다시 실행.</li>
<li>가장 성능 이점이 큼.</li>
<li>예: transform, opacity 변경 시.</li>
</ul>
<h4 id="4-성능상-차이">4. 성능상 차이</h4>
<ul>
<li>Reflow: CPU 의존, 부모→자식 영향 전파 → 비용 큼.</li>
<li>Repaint: GPU 의존, 독립적 요소만 다시 그림 → 비용 적음.</li>
<li>따라서 최적화에서는 Reflow를 최소화하는 것이 핵심.</li>
</ul>
<p>그렇다면, Reflow를 최소화 하는 방법을 알아볼까요?</p>
<h4 id="5-reflow를-최소화-하는-방법">5. Reflow를 최소화 하는 방법</h4>
<p>(1) DOM 업데이트 배치 (Batch Update)</p>
<ul>
<li>DOM 조작을 모아 한 번에 처리.</li>
</ul>
<p>(2) 계산 값 재사용</p>
<ul>
<li>요소 크기/위치 값을 변수에 저장 후 재사용.</li>
</ul>
<p>(3) 레이아웃 변경 최소화</p>
<ul>
<li>flex, grid 대신 absolute, fixed와 같이 독립적인 레이아웃 사용.</li>
</ul>
<p>(4) GPU 활용</p>
<ul>
<li>transform: translate3d(x, y, 0)</li>
<li>will-change 속성으로 변화 예상 힌트 제공.</li>
</ul>
<p>(5) 애니메이션 최적화</p>
<ul>
<li>transform, opacity 기반 애니메이션 사용.</li>
<li>transition/animation 활용.</li>
</ul>
<p>(6) CSS contain 속성 활용</p>
<ul>
<li>특정 요소의 레이아웃/스타일/페인트 영향 범위를 제한.</li>
</ul>
<p>이상 Reflow, Repaint와 같은 브라우저 렌더링에 대해 알아본 내용이었습니다. 감사합니다 :)</p>
<p>참고 자료 : <a href="https://www.youtube.com/watch?v=sJ14cWjrNis">https://www.youtube.com/watch?v=sJ14cWjrNis</a>
<a href="https://www.youtube.com/watch?v=TZz9VHjJzMk">https://www.youtube.com/watch?v=TZz9VHjJzMk</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git/GitHub] origin과 main(master)의 차이]]></title>
            <link>https://velog.io/@sohyerim-dev/GitGitHub-origin%EA%B3%BC-mainmaster%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@sohyerim-dev/GitGitHub-origin%EA%B3%BC-mainmaster%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Thu, 02 Oct 2025 07:58:51 GMT</pubDate>
            <description><![CDATA[<p>예전에 Git을 제대로 공부하지 않고, 특히 Branch의 개념을 제대로 이해하지 않고 GitHub에 디렉토리를 Push하려다가 실패한 적이 있었다. 그때 Branch에 대해 다시 공부를 하면서 origin과 main(master)의 차이를 알게되었다. </p>
<p> 예전의 나와 같이 origin과 main의 개념이 헷갈리는 분들을 위해 예전 기록을 다시 공유해본다.</p>
<h2 id="1-origin">1. origin</h2>
<p>origin은 branch가 아닌 원격저장소(GitHub의 Git저장소)의 기본 이름이다. 그렇기 때문에 원격저장소와 로컬저장소를 연결할 때 origin을 사용한다.</p>
<p>예)</p>
<pre><code>git clone origin (원격 저장소 repository 주소)
# 이 명령어는 로컬 저장소 디렉토리를 origin이라는 원격저장소의 repository에 클론한다는 것을 뜻한다.
# 하지만 origin을 생략하고 이 명령어를 실행할 수도 있는데,
# 이 경우 자동으로 원격저장소의 이름을 origin으로 설정한다.</code></pre><h2 id="2-mainmaster">2. main(master)</h2>
<p>Git에서 사용하는 브랜치(branch) 이름 중 하나로, 일반적으로 프로젝트의 기본 브랜치로 사용된다. 새로운 저장소를 만들 때 기본 브랜치로 생성되며, 주로 배포 가능한 안정적인 버전을 포함한다.
이 때, 주의할 점은 로컬 저장소의 기본 브랜치(main)와 원격 저장소의 기본브랜치(origin/main)가 각각 다르다는 점이다.</p>
<ul>
<li><p>로컬 저장소의 main 브랜치는 아래와 같이 사용할 수 있다.</p>
<pre><code>git checkout main
# 로컬 저장소의 main 브랜치에서 작업하겠다는 뜻이다.</code></pre></li>
<li><p>원격 저장소의 origin/main 브랜치는 아래와 같이 사용할 수 있다.</p>
<pre><code>git push origin main
# 해당 명령어는 origin(원격 저장소)의 main(브랜치)에 로컬 저장소의 main브랜치에 있는 커밋 및 변경 사항을 push한다는 것을 의미한다.</code></pre></li>
</ul>
<p>이상이다. origin과 main의 개념이 헷갈리시는 분들께 도움이 되길! :)</p>
]]></description>
        </item>
    </channel>
</rss>