<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>miin-hyukkk.log</title>
        <link>https://velog.io/</link>
        <description>Born to be FE developer 🧑🏻‍💻</description>
        <lastBuildDate>Tue, 17 Sep 2024 04:32:38 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>miin-hyukkk.log</title>
            <url>https://velog.velcdn.com/images/miin-hyukkk/profile/0a853158-5a13-4872-988a-8bd9de3766dd/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. miin-hyukkk.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/miin-hyukkk" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[프로젝트] 다이나믹 임포트]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9-%EC%9E%84%ED%8F%AC%ED%8A%B8</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9-%EC%9E%84%ED%8F%AC%ED%8A%B8</guid>
            <pubDate>Tue, 17 Sep 2024 04:32:38 GMT</pubDate>
            <description><![CDATA[<p>다이나믹 임포트 활용하기</p>
<h2 id="취지">취지</h2>
<p>물론 내가 다이나믹 임포트 처리를 진행할 컴포넌트 크기가 미미해서, 번들사이즈에 크게 영향을 줄지는 의문이었다.
하지만 이것을 진행했던 취지는 번들 사이즈를 줄여본 경험을 해보고 싶어서였다.</p>
<h2 id="들어가기-전에">들어가기 전에</h2>
<p>hydrate라는 개념, 그리고 리엑트에서의 hydrate과 next.js에서의 hydrate의 차이를 명확히 알고 해당 작업을 진행해야 함 -&gt; <a href="https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Hydrate">링크</a></p>
<p>Dynamic Import는 첫 렌더링 시에 바로 보여줄 필요가 없는 요소들을 걷어내어 성능을 향상시키는 방식임.</p>
<p>내 프로젝트에서는 Footer에 적용할 예정이므로 Footer로 예를 들어보겠음</p>
<blockquote>
<p>초기 Preredering 시 Footer에 대한 컴포넌트는 완전히 제외된 상태로 렌더링을 한 뒤, Client Side 단에서 실제 Footer 열게 되면, 서버 단에 해당 Footer 관련 Chunk File을 요청하여 별도 렌더링을 진행하게 됨</p>
</blockquote>
<p>개념을 명확히 알면 여기까지는 그렇게 어려운 작업이 아님</p>
<h2 id="작업-진행-순서">작업 진행 순서</h2>
<ol>
<li>footer를 그냥 import</li>
<li>footer를 dynamic import</li>
<li>footer를 dynamic import + IntersectionObserver</li>
</ol>
<h3 id="1-footer를-그냥-import">1. footer를 그냥 import</h3>
<p><code>ANALYZE=true yarn build</code>로 번들사이즈를 체크
(<code>scr/componets/Layout</code> 내부에 <code>Footer</code>컴포넌트가 존재함)
<img src="https://velog.velcdn.com/images/miin-hyukkk/post/1b42a06c-41ee-4e84-9998-1727ff0636a3/image.png" alt=""></p>
<h3 id="2-footer를-dynamic-import">2. footer를 dynamic import</h3>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/50ae34ac-3273-483e-aacb-6fd3badbe558/image.png" alt=""></p>
<pre><code>const Footer = dynamic(() =&gt; import(&quot;@/components/Layout/Footer&quot;), {
  ssr: false,
});</code></pre><p>해당 경로의 번들사이즈가 15.35KB-&gt; 11.41KB로 줄어든걸 확인할 수 있음.</p>
<p>마찬가지로 네트워크 창에서 확인해보면 아래 이미지와 같이 chunk파일이 분리된걸 확인할 수 있음.
<img src="https://velog.velcdn.com/images/miin-hyukkk/post/12ad4dcb-1ec6-45aa-bc98-1973d9773133/image.png" alt=""></p>
<p>하지만 내가 원하는 것은 사용자의 뷰포인트에 <code>Footer</code>가 등장하기 전까지 청크 파일이 생성되지 않는 것이였음</p>
<h3 id="3-footer를-dynamic-import--intersectionobserver">3. footer를 dynamic import + IntersectionObserver</h3>
<blockquote>
<p><code>IntersectionObserver</code>는 웹 API로, 요소가 뷰포트(브라우저의 가시 영역)와 교차하는 시점을 관찰하고 이를 기반으로 특정 작업을 수행</p>
</blockquote>
<pre><code>useEffect(() =&gt; {
  const footerPlaceholder = document.getElementById(&quot;footer-placeholder&quot;);

  if (footerPlaceholder) {
    const observer = new IntersectionObserver(
      (entries) =&gt; {
        if (entries[0].isIntersecting) {
          setLoadFooter(true);
          observer.disconnect();
        }
      },
      { rootMargin: &quot;100px&quot; } // 이 설정으로 footer가 뷰포트에 들어오기 100px 전에 로드됩니다.
    );

    observer.observe(footerPlaceholder);

    // 컴포넌트가 unmount될 때 observer 해제
    return () =&gt; observer.disconnect();
  }
}, []);
</code></pre><p>해당 코드를 통해 footer가 뷰포인트에 등장 전에는 chunk 파일을 요청하지 못하도록 제어함.</p>
<blockquote>
<p>네트워크 탭을 확인하면, <code>document</code>에서는 <code>Footer</code>가 빠져있고, 뷰포인트에 등장 <code>100px</code>전에 <code>Footer</code> 파일이 생성되는 것을 확인 가능함</p>
</blockquote>
<h3 id="4-dynamic-import--seo">4. dynamic import + SEO</h3>
<p><strong>만약, Footer에 SEO에 영향을 주는 요소가 있어서 Footer요소가 html에 포함되길 원하다면 어떻게 해야할까?</strong></p>
<blockquote>
<p>next.js에서 다이나믹 임포트로 <code>Footer</code> 요소를 불러오게된다면 PreRendering 된 Document에서도 보이지 않게 됨</p>
</blockquote>
<blockquote>
<p><strong>기존 html에서는 footer요소가 들어가서 seo에 영향을 주면서 동시에 footer Chunk File이 필요한 순간에 Lazy 하게 요청</strong>을 하는 것임</p>
</blockquote>
<p>구글링을 해보니, 해당 기능을 구현하려면, 설정파일들에 커스텀이 필요한 것을 알았다.
구글링과 gpt를 이용해서 구현해보려했으나, 깊은 이해가 없이는 구현이 힘들것 같다는 판단이 들었다.</p>
<p>(기본 제공되는 기능으로는 dynamic만 되고, html에는 안들어감...)</p>
<p>별도의 Webpack 플러그인이나 빌드 시 커스텀 처리가 필요</p>
<hr>
<p>다음 포스트에서 해당 기능을 구현해보며 이해한 내용을 작성해볼 예정.......
.
.
.
끝🫠</p>
<p>참고한 블로그 : <a href="https://helloinyong.tistory.com/323">https://helloinyong.tistory.com/323</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 회고록...]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Mon, 02 Sep 2024 03:12:28 GMT</pubDate>
            <description><![CDATA[<h1 id="회고록">회고록</h1>
<h2 id="프로젝트-취지">프로젝트 취지</h2>
<p>2개의 프로젝트를 진행해봤으니, 마지막으로 사용자가 실제로 존재하는 프로젝트를 진행해보고 싶다는 생각을 함. 
친구의 sns 계정을 이용해서 쇼핑몰을 오픈해보려고함.</p>
<p>처음 기획할때는 쇼핑몰이니 의류들을 보여주는 shop페이지, 마이페이지 등등 가볍게 생각하고 진행.</p>
<p>하지만 관리자페이지 구현,결제 시스템 연동, 쇼핑몰 특성상 많은 이미지를 딜레이없이 보여주는 등 생각할 것들이 굉장히 많았음....</p>
<p>그 전 프로젝트에서는 넘어갔단 작은 이슈들에 대해 정말 사용자가 있다고 생각하니 넘어갈 수 있는 문제가 하나도 없었고, + 처음 6개월정도로 기획했던 프로젝트는 1년이 되어서야 마무리 됨</p>
<h2 id="초기-기획의도와-비교했을-때-바뀐-점">초기 기획의도와 비교했을 때 바뀐 점</h2>
<p>친구가 sns활동을 하면서 장기적으로 사용할 쇼핑몰을 만들려고 했으나 여러 비용적인 문제로 이벤트성으로 한달정도만 이벤트성으로 쇼핑몰을 오픈하기로 결정 -&gt; 주 컨텐츠가 ‘<strong>이벤트</strong>’로 바뀜</p>
<p>다양한 sns 홍보 + 친구 sns 계정 팔로워수로 인해 약 1500명의 회원이 생성됐고, 약 2만건의 이벤트참여율이 발생함.</p>
<h2 id="seo향상을-위해-노력한-이유---쇼핑몰이니까">SEO향상을 위해 노력한 이유   “쇼핑몰이니까&quot;</h2>
<p>csr만 작업을 해온 나에겐 첫 도전이였음.</p>
<p>구글에 어떻게 하면 우선순위로 검색이 되고, 어떤 메타태그를 사용해야 페이지 노출 정도를 높일 수 있고 등등에 대해 많이 고민을 함.</p>
<p>어떤 데이터는 SSR로, 또 어떤 데이터는 SSG로 구현을 해야겠다 등등 많은 고민을 함.</p>
<h2 id="초기-뷰포인트-로딩시간--너무-오래걸림---lighthouse-점수">초기 뷰포인트 로딩시간  너무 오래걸림 -&gt; lighthouse 점수</h2>
<p>페이지를 로딩하는 데 너무 오랜 시간이 걸려 뭐가 문제인지 고민을 좀 해봄</p>
<p>비록 결과적으로는 많은 도움이 되지는 않았지만, 경험이라 생각하고 번들사이즈를 줄이려고 노력을 해봄.</p>
<blockquote>
<ol>
<li>사용자의 뷰포인트에 당장 등장하지 않는 요소는 나중에 hydrate해보자!</li>
<li>일부 사용자에게만 보이는 팝업창 요소는 다이나믹 임포트로 구현해보자!</li>
<li>이미지를 전부 next/image로 변경!</li>
<li>폰트를 otf-&gt;wott2로 변경!</li>
</ol>
</blockquote>
<p>결과적으로 눈의 띄게 큰 변화를 준 것은 3,4번이였음</p>
<h2 id="테스트-코드의-중요성을-피부로-직접-깨달음">테스트 코드의 중요성을 피부로 직접 깨달음</h2>
<p>회사 지원을 하다보면 여기저기 테스트코드에 대한 언급이 많음.
그리하여 직전 프로젝트의 경우 jest를 통해 unit test를 진행하고 cypress를 통해 e2e테스트를 진행함.
하지만 하면서도 이 테스트코드가 정말 도움이 될까라는 생각이 많이 들었음. 왜냐면 이미 잘될거를 알았으니까. 그런데 시간도 많이 드니까.</p>
<p>이런 생각을 가진채로 이번 프로젝트의 경우 정말 일부의 기능만 e2e테스트를 진행함.</p>
<p>로그인, 결제, 장바구니 위 세기능에 대해만 작성함</p>
<p><strong>그리고 오픈함</strong></p>
<p>이벤트는 약 4일간 진행되었고 매일매일 약 1000명이 넘는 사람들이 우리의 페이지를 방문함. 그러던 도중 백엔드에서 정말 사소한 이슈가 발생했고, 해당 코드 한줄을 고침으로써 사용자의 정보가 담긴 디비가 꼬이는 일이 발생함.</p>
<p>남들은 어떻게 생각할지 모르겠지만 나는 테스트커버리지가 높은 코드라면 해당 이슈들이 발생하지 않았을 것이라고 생각이 들었음.</p>
<p>결국 사이드 이펙트 체크가 정말 중요하다는 거임. 사용자가 많아져서 미처 발견하지 못한 이슈가 발생하거나, 작은 기능하나가 추가될때 나머지 기능들이 원활하게 돌아가는지 메인에 코드가 푸쉬되고 빌드가 되기전에 개발자가 알아야한다는 거임.</p>
<h2 id="새로운-테스트코드-툴--api-요청-수-확인-후-이상-감지">새로운 테스트코드 툴? -&gt;api 요청 수 확인 후 이상 감지</h2>
<p>마찬가지로 프론트엔드 쪽에서도 이벤트 참여이후 응모하기 버튼이 즉시 멈추지않아서 급하게 조건문없이 refetch코드를 작성했다가, 응모내역조회가 응모상품페이지 방문 시 10번 이상 발생함. </p>
<p>코드 추가 후 같은 api가 중복호출되는 경우를 잡을 수는 없을까?
e2e테스트 코드에서 해당 api가 한번만 불리는게 맞는지 체크하는 코드를 작성해보면 어떨까?</p>
<blockquote>
<p><strong>경험삼아 메인코드에 푸쉬전에 api 요청 수 확인해서 한기능에 한번씩 요청을 하고 있는지 테스트코드를 추가해보기로 결정</strong></p>
</blockquote>
<h2 id="유지보수의-중요성">유지보수의 중요성</h2>
<p>1년동안 길어지면서 7~8개월 전에 작성했던 코드에 대해 직관적으로 이해가 되지 않는 경우들이 발생. 
<strong>일반적인 네이밍과 구조!</strong>가 얼마나 중요한지 알게됨</p>
<p>.
.
.</p>
<p>친구의 계정 덕분에 너무너무 귀중한 경험을 했고, 이력서에 잘 반영해봐야겠다. 끝!🫠</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우타스] 타입 조합]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-%ED%83%80%EC%9E%85-%EC%A1%B0%ED%95%A9</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-%ED%83%80%EC%9E%85-%EC%A1%B0%ED%95%A9</guid>
            <pubDate>Tue, 27 Aug 2024 03:50:50 GMT</pubDate>
            <description><![CDATA[<p>좀 심화한 타입 검사에 필요한 지식들</p>
<h2 id="교차-타입intersection">교차 타입(Intersection)</h2>
<p>여러 가지 타입을 결합하여 하나의 단일 타입으로 만들 수 있음
&amp;를 사용해서 표기함. <code>A&amp;B</code>
결과물로 탄생한 단일 타입에는 타입별칭(type alias)을 붙일 수 있음
<code>type ProductItemWithDiscount = ProductItem &amp; { discountAmount : number }</code></p>
<h2 id="유니온-타입">유니온 타입</h2>
<p><code>A|B</code> 타입 A나 B중 하나에 해당</p>
<h2 id="인덱스-시그니처">인덱스 시그니처</h2>
<p>특정 타입의 속성 이름은 알 수 없지만 속성값의 타입을 알고 있을 때 사용하는 문법</p>
<pre><code>interface IndexSignatureEx2 {
  [key: string]: number | boolean;
  length: number;
  isValid: boolean;
  name: string; // 에러 발생
}</code></pre><p>인덱스 시그니처의 키가 <code>string</code>일 때는 <code>number | boolean</code> 타입이 오게끔 선언되어 있어서 에러 발생</p>
<h2 id="인덱스드-엑세스-타입">인덱스드 엑세스 타입</h2>
<p>다른 타입의 특정 속성이 가지는 타입을 조회,추출하기 위해 사용됨</p>
<pre><code>type Person = {
  name: string;
  age: number;
  location: string;
};

// 인덱스드 엑세스 타입을 사용하여 &#39;Person&#39; 타입의 &#39;name&#39; 속성의 타입을 가져옵니다.
type NameType = Person[&#39;name&#39;]; // NameType은 string 타입이 됩니다.
</code></pre><h2 id="맵드-타입mapped-types">맵드 타입(Mapped Types)</h2>
<p>자바스크립트 map : 배열 A를 기반으로 새로운 배열 B를 만들어내는 배열 메서드
마찬가지로 맵드 타입은 다른 타입을 기반으로 한 타입을 선언할 때 사용하는 문법
인덱스 시그니처 문법을 사용해서 반복적인 타입 선언을 효과적으로 줄일 수 있음</p>
<pre><code>type Example = {
  a: number;
  b: string;
  c: boolean;
};

type Subset&lt;T&gt; = {
  [K in keyof T]?: T[K];
};

const aExample: Subset&lt;Example&gt; = { a: 3 };
const bExample: Subset&lt;Example&gt; = { b: &quot;hello&quot; };
const acExample: Subset&lt;Example&gt; = { a: 4, c: true };</code></pre><p><code>Subset&lt;T&gt;</code>는 <strong>T</strong>타입의 모든 속성을 선택적으로 포함할 수 있는 새로운 타입을 만듦</p>
<p>맵드 타입이 실제로 사용된 예시
배민 선물하기 서비스에는 &#39;바텀시트&#39;라는 컴포넌트개 존재. 밑에서부터 스르륵 올라오는 모달. 이 바텀시트는 선물하기 서비스의 최근 연락처 목록,카드 선택, 상품 선택 등 여러 지면에서 사용됨. 바텀시트마다 각각 resolver, isOpened 등의 상태를 관리하는 스토어가 필요한데 이 스토어의 타입(BottomSheetMap)을 선언해줘야 함. 
이때 이 타입에 존재하는 모든 키에 대해 일일이 스토어를 만들어줄 수도 있지만 불필요한 반복이 발생함.</p>
<p>이럴때 인덱스 시그니처 문법을 사용해서 BottomSheetMap을 기반으로 각 키에 해당하는 스토어를 선언할 수 있음.</p>
<pre><code>const BottomSheetMap = {
  RECENT_CONTACTS: RecentContactsBottomSheet,
  CARD_SELECT: CardSelectBottomSheet,
  SORT_FILTER: SortFilterBottomSheet,
  PRODUCT_SELECT: ProductSelectBottomSheet,
  REPLY_CARD_SELECT: ReplyCardSelectBottomSheet,
  RESEND: ResendBottomSheet,
  STICKER: StickerBottomSheet,
  BASE: null,
};

// BOTTOM_SHEET_ID는 BottomSheetMap에서 정의된 키들 중 하나만을 허용하는 타입
export type BOTTOM_SHEET_ID = keyof typeof BottomSheetMap;

// 불필요한 반복이 발생한다
type BottomSheetStore = {
  RECENT_CONTACTS: {
    resolver?: (payload: any) =&gt; void;
    args?: any;
    isOpened: boolean;
  };
  CARD_SELECT: {
    resolver?: (payload: any) =&gt; void;
    args?: any;
    isOpened: boolean;
  };
  SORT_FILTER: {
    resolver?: (payload: any) =&gt; void;
    args?: any;
    isOpened: boolean;
  };
  // ...
};

// Mapped Types를 통해 효율적으로 타입을 선언할 수 있다
type BottomSheetStore = {
  [index in BOTTOM_SHEET_ID]: {
    resolver?: (payload: any) =&gt; void;
    args?: any;
    isOpened: boolean;
  };
};</code></pre><h2 id="템플릿-리터럴-타입">템플릿 리터럴 타입</h2>
<p>자바스크립트의 템플릿 리터럴 문자열을 사용하여 문자열 리터럴 타입을 선언할 수 있는 문법</p>
<pre><code>type Stage =
  | &quot;init&quot;
  | &quot;select-image&quot;
  | &quot;edit-image&quot;
  | &quot;decorate-card&quot;
  | &quot;capture-image&quot;;
type StageName = `${Stage}-stage`;
// ‘init-stage’ | ‘select-image-stage’ | ‘edit-image-stage’ | ‘decorate-card-stage’ | ‘capture-image-stage’</code></pre><h2 id="제네릭">제네릭</h2>
<p>제네릭은 정적 언어에서 다양한 타입 간에 <strong>재사용성</strong>을 높이기 위해사용하는 문법임.
<code>사전적 의미</code> : 특징이 없거나 일반적인 것</p>
<p>한마디로 일반화된 데이터 타입
내부적으로 사용할 타입을 미리 정해두지 않고 타입 변수를 사용해서 해당 위치를 비워둔 다음에, 실제로 그 값을 사용할 때 외부에서 <strong>타입 변수 자리에 타입을 지정하여 사용</strong>하는 방식</p>
<p>보통 타입 변수명으로 <strong><code>T(Type)</code>, <code>E(Element)</code>, <code>K(Key)</code>, <code>V(Value)</code></strong> 등 한글자로 된 이름을 주로 사용</p>
<p>제네릭은 any랑 다름. any처럼 아무 타입이나 무분별하게 받는 게 아니라, 배열 생성 시점에 원하는 타입으로 특정할 수 있음. 다시 말해 제네릭을 사용하면 배열 요소가 전부 동일한 타입이라고 보장할 수 있음</p>
<p>제네릭 함수를 호출할 때 반드시 꺾쇠괄호(&lt;&gt;)안에 타입을 명시해야 하는 것은 <strong>아님</strong>. 타입을 명시하는 부분을 생략하면 컴파일러가 인수를 보고 타입을 추론해줌. <strong>타입 추론 가능한 경우엔 생략 가능!</strong></p>
<pre><code>function identity&lt;T&gt;(value: T): T {
  return value;
}

// 타입을 명시하지 않음. 컴파일러가 &#39;number&#39; 타입으로 추론.
const num = identity(42); // num의 타입은 number

// 타입을 명시하지 않음. 컴파일러가 &#39;string&#39; 타입으로 추론.
const str = identity(&quot;hello&quot;); // str의 타입은 string</code></pre><p>제네릭에 기본 값 추가도 물론 가능!</p>
<p>함수나 클래스 등의 내부에서 제네릭을 사용할 때 <strong>어떤 타입이든 될 수 있다는 개념</strong>을 알고 있어야해
특정한 타입에서만 존재하는 멤버를 <strong>참조하려고 하면 안됨</strong>. 배열에만 존재하는 length 속성을 제네릭에서 참조하려고 하면 당연히 에러가 발생함. 당연히 안됨 ㅇㅇ</p>
<pre><code>function exampleFunc2&lt;T&gt;(arg: T): number {
  return arg.length; // 에러 발생: Property ‘length’ does not exist on type ‘T’
}</code></pre><p><code>제네릭 타입은 호출 시점에 어떤 구체적인 타입으로 결정되기 때문에, T에 대해 length 속성이 정의되어 있는지 여부를 컴파일러가 알 수 없음</code></p>
<p>이럴땐!.. 제네릭 꺾쇠괄호 내부에 <strong>&#39;length속성을 가진 타입만 받는다&#39;</strong> 라는 제약을 걸어주면 사용할 수 있음.</p>
<pre><code>interface TypeWithLength {
  length: number;
}

function exampleFunc2&lt;T extends TypeWithLength&gt;(arg: T): number {
  return arg.length;
}</code></pre><p>화살표 함수에 제네릭 사용하면 에러 발생함. JSX의 태그와 제네릭의 꺾쇠괄호를 혼동해버림.
extends키워드 사용하던지, 일반 함수 사용하던지!</p>
<h2 id="제네릭-사용하기">제네릭 사용하기</h2>
<ul>
<li>함수의 제네릭</li>
<li>호출 시그니처의 제네릭</li>
<li>제네릭 클래스</li>
<li>제한된 제네릭</li>
<li>확장된 제네릭</li>
</ul>
<p>제네릭의 장점이 뭐냐하면...
<strong>다양한 타입을 받게함</strong>으로써 <strong>코드를 효율적으로 재사용</strong>할 수 있다는 것!
그렇다면 현업에서는 언제 가장 많이 쓰일까?</p>
<h3 id="api-응답-값-타입을-지정할-때">API 응답 값 타입을 지정할 때!</h3>
<pre><code>export interface MobileApiResponse&lt;Data&gt; {
  data: Data;
  statusCode: string;
  statusMessage?: string;
}</code></pre><p>API응답 값에 따라 달라지는 data를 <strong>제네릭 타입 Data</strong>로 선언하고 있음
이렇게 만든 <code>MobileApiResponse</code>는 실제 API 응답값의 타입을 지정할때 아래처럼 사용됨</p>
<pre><code>export const fetchPriceInfo = (): Promise&lt;MobileApiResponse&lt;PriceInfo&gt;&gt; =&gt; {
  const priceUrl = &quot;https: ~~~&quot;; // url 주소

  return request({
    method: &quot;GET&quot;,
    url: priceUrl,
  });
};

export const fetchOrderInfo = (): Promise&lt;MobileApiResponse&lt;Order&gt;&gt; =&gt; {
  const orderUrl = &quot;https: ~~~&quot;; // url 주소

  return request({
    method: &quot;GET&quot;,
    url: orderUrl,
  });
};</code></pre><p>제네릭이 과하게 사용되면 가독성을 해치기 때문에 코드를 읽고 타입을 이해하기가 어려워짐
복잡한 제네릭은 <strong>의미 단위로 분할</strong>해서 사용하는게 좋다</p>
<p>.
.
.
끝
🫠</p>
<p>출처: 우아한 타입스크립트 with 리엑트</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우타스] TS만의 독자적 타입 시스템]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-TS%EB%A7%8C%EC%9D%98-%EB%8F%85%EC%9E%90%EC%A0%81-%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-TS%EB%A7%8C%EC%9D%98-%EB%8F%85%EC%9E%90%EC%A0%81-%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Mon, 26 Aug 2024 14:55:41 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가기전에">들어가기전에</h2>
<p>자바스크립트에 any타입이 있는가?
any타입은 타입스크립트에만 존재하는 독자적인 타입 시스템으로 간주됨</p>
<p>하지만 any타입의 개념은 이미 자바스크립트에서 사용됨. 이름 그대로 어떤 타입이든 매핑할 수 있는 성질을 가지고 있고, 이건 원래 자바스크립트의 사용방식과 일치하기 때문</p>
<p><strong>지금 알아볼 모든 타입 시스템은 타입스크립트에만 존재하는 키워드이지만 그 개념은 자바스크립트에 기인한 타입시스템이라는 점을 인지하자</strong></p>
<h2 id="any타입">any타입</h2>
<p>any타입은 타입스크립트로 달성하고자 하는 정적 타이핑을 무색하게 만듦
any타입은 지양해야할 패턴.회피하는 것이 좋은 습관</p>
<p><code>tsconfig.json</code>에서 <code>noImplicitAny</code>옵션을 활성화하면 any타입에 대한 경고를 발생시킬 수 있음</p>
<p><strong>하지만 어쩔 수 없이 사용해야할 때가 있음</strong></p>
<h3 id="개발-단계에서-임시로-값을-지정해야-할때">개발 단계에서 임시로 값을 지정해야 할때</h3>
<p>세부항목에 대해 아직 타이빙 확정되지 않은 경우</p>
<h3 id="어떤-값을-받아올지-또는-넘겨줄-지-정할-수-없을때">어떤 값을 받아올지 또는 넘겨줄 지 정할 수 없을때</h3>
<pre><code>type FeedbackModalParams = {
    show: boolean;
    content: string;
    cancelButtonText?: string;
    confirmButtonText?: string;
    beforeOnClose?: () =&gt; void;
    action?: any;
  };</code></pre><p>acition속성이 any로 선언된 것을 볼 수 있음. action속성은 모달 차을 그릴 때 실행될 함수를 의미함
모달창을 화면에 그릴 때 다양한 범주의 액션에 따라 읹자의 개수나 타입을 일일이 명시하기 힘들 수 있음</p>
<h3 id="값을-예측할-수-없을-때-암묵적으로-사용">값을 예측할 수 없을 때 암묵적으로 사용</h3>
<p>그래도 지양해라~</p>
<h2 id="unknown-타입">unknown 타입</h2>
<p>any와 유사하게 <strong>모든 타입의 값이 할당&#39;될&#39;</strong> 수 있음
그러나 any를 제외한 다른 타입으로 선언된 변수에는 unknown <strong>타입 값을 할당&#39;할&#39; 수 없음</strong></p>
<pre><code>let unknownValue: unknown;

unknownValue = 100; // any 타입과 유사하게 숫자이든
unknownValue = &quot;hello world&quot;; // 문자열이든
unknownValue = () =&gt; console.log(&quot;this is any type&quot;); // 함수이든상관없이할당이가능하지만

let someValue1: any = unknownValue; // (O) any 타입으로 선언된 변수를 제외한 다른 변수는 모두 할당이 불가
let someValue2: number = unknownValue; // (X)
let someValue3: string = unknownValue; // (X)</code></pre><p>무엇이 할당될지 아직 모르는 상태의 타입을 말함 -&gt; any와 똑같아보일 수 있음
왜 unknown이 추가된걸까?</p>
<pre><code>// 할당하는 시점에서는 에러가 발생하지 않음
const unknownFunction: unknown = () =&gt; console.log(&quot;this is unknown type&quot;);

// 하지만 실행 시에는 에러가 발생; Error: Object is of type &#39;unknown&#39;.ts (2571)
unknownFunction();</code></pre><p>보면 할당할때는 에러가 안생기는데 실행하면 에러가 생김. 이거말고도 객체 내부에 접근하는 모든 시도에서 에러가 발생할거임.</p>
<p>unknown타입으로 선언된 변수는 값을 가져오거나 내부 속성에 접근할 수 없음</p>
<p><strong>any타입과 비교를 해보자</strong></p>
<blockquote>
<p>any타입은 어떤 값이든 허용됨. 
any타입을 모두 허용하기 때문에 할당하는 시점에 any로 사용을 하고, 나중에 실행 시에 타입을 특정해주지 않아도 에러가 발생하지 않는다. 
결국 깜빡하고 타입 지정을 누락할 경우 어떤 값이든 전달될 수 있기 때문에 런타임에 버그가 발생할 가능성이 높아진다는 얘기임</p>
</blockquote>
<p>이런 상황을 보완하기 위해 등장한 타입이 unknown타입이다. any타입과 유사하지만 타입검사를 강제하고 타입이 식별된 후에 사용 가능하기 때문에 any타입보다 안전함.</p>
<p><strong>결론 : 데이터 구조 파악이 힘든 경우 any보다는 unknown타입을 써라!</strong></p>
<h2 id="void타입">void타입</h2>
<p>함수에 전달되는 매개변수의 타입과 반환하는 타입을 지정해야 함
타입스크립트에서 함수가 어떤 값을 반환하지 않는 경우에는 void를 지정하여 사용해야됨</p>
<p>일반적으로 함수 자체를 다른 함수의 인자로 전달하는 경우가 아니라면 void타입은 잘 명시하지 않음
왜냐면 반환문 없을때 알아서 void로 추론해주기 때문에</p>
<h2 id="never타입">never타입</h2>
<p>값을 반환할 수 없는 타입을 말함
<strong>값을 반환하지 않는 것, 값을 반환할 수 없는 것</strong>을 명확히 구분해야됨</p>
<h3 id="에러를-던지는-경우">에러를 던지는 경우</h3>
<p>자바스크립트에서는 런타임에 의도적으로 에러를 발생시키고 캐치할 수 있음. throw 키워드를 사용하면 에러를 발생시키는데, 이는 값을 반환하는 거로 간주하지 않아서 타입은 never임</p>
<h3 id="무한히-함수가-실행되는-경우">무한히 함수가 실행되는 경우</h3>
<p>말그대로 무한루프니까 값을 반환을 못하니 타입이 never</p>
<p>never타입은 모든 타입의 하위 타입임. 즉, never자신을 제외한 어떤 타입도 never타입에 할당될 수 없음
심지어 any타입도 안됨</p>
<p>따라서 타입스크릡트에서는 조건부 타입을 결정할 때 특정 조건을 만족하지 않는 경우에 엄격한 타입 검사 목적으로 never타입을 명시적으로 사용하기도 함</p>
<h2 id="array타입">Array타입</h2>
<p>배열 타입을 가리키는 Array키워드는 자바스크립트에서도 확인할 수 있음.
근데 왜 소개하냐. 엄밀히 말하면 JS는 배열을 객체에 속하는 타입으로 분류함. 즉, JS는 배열을 단독으로 자료형으로 국한하지 않음
타입스크립트에서 Array라는 타입을 사용하기 위해서는 타입스크립트의 특수한 문법을 함꼐 다뤄야 함</p>
<p>타입스크립트는 배열의 크기까지 제한하지는 않지만 정적 타입의 특성을 살려 <strong>명시적인 타입을 선언하여 해당 타입의 원소를 관리하는 것을 강제</strong>함</p>
<p>배열 타입 선언에는 두가지 방식이 있음</p>
<pre><code>const array: number[] = [1,2,3];
const array: Array&lt;number&gt; = [1,2,3]; // 제네릭</code></pre><p>차이점은 딱히 없음 개인의 선호,팀 컨벤션 따르거나 혼용하면 됨</p>
<p>만약!..숫자형과 문자열 등 여러 타입을 모두 관리해야 하는 배열을 선언하려면 <strong>유니온 타입</strong>을 사용</p>
<pre><code>const array1: Array&lt;number | string) = [1,&quot;string&quot;]
const array2: number[] | string[] = [1,&quot;string]

const array3: (numver | array)[] = [1,&quot;string&quot;]
</code></pre><p>튜플은 길이까지 제한하여 원소 개수와 타입을 보장함. ex) <code>let tuple: [number] = [1]</code></p>
<p><strong>튜플의 쓰임새</strong></p>
<blockquote>
<p>리엑트 hook요소 중 useState는 튜플 타입을 반환함. 첫 원소는 훅으로부터 생성 및 관리되는 상태 값을 의미, 두번째 원소는 해당 상태를 조작할 수 있는 세터를 의미함.
배열 원소의 자리마다 명확한 의미를 부여하기 때문에 컴폰넌트에서 사용하지 않는 값에 접근하는 오류를 방지해줌. 
<strong>구조분해 할당</strong>을 하니까 사용자가 자유롭게 이름도 정의할 수 있음</p>
</blockquote>
<p>구조분해 할당은 배열말고 객체에 대해서도 적용 가능. 물론 객체의 경우 사전에 선언된 속성의 이름을 통해 값을 가져오므로 튜플보다 유언성은 다소 떨어짐</p>
<pre><code>const useStateWithObject = (initialValue: any) =&gt; {
    ...
    return {value,setValue}
}

const [value,setValue] =useStateWithObject(false); // 정의된 속성이름으로 가져와야됨
const [vaue: userName, setValue: setUsername} = useStateWithObject(&#39;&#39;) //정 하고싶으면 일차적으로 먼저 접근 후 다른 이름 지정해야됨</code></pre><h2 id="enum-타입">enum 타입</h2>
<p>열거형이라고도 부르는 타입스크립트에서 지원하는 트구샇ㄴ 타입
일종의 구조체를 만드는 타입 시스템
enum을 사용하여 열거형을 정의할 수 있는데 열거형은 각각의 멤버를 가지고 있음. 명명한 각 멤버의 값을 스스로 추론함. 기본적인 추론방식은 숫자 0부터 1씩 늘려가며 값을 할당하는 것!</p>
<pre><code>enum ItemStatusType {
  DELIVERY_HOLD = &quot;DELIVERY_HOLD&quot;, // 배송 보류
  DELIVERY_READY = &quot;DELIVERY_READY&quot;, // 배송 준비 중
  DELIVERING = &quot;DELIVERING&quot;, // 배송 중
  DELIVERED = &quot;DELIVERED&quot;, // 배송 완료
}

const checkItemAvailable = (itemStatus: ItemStatusType) =&gt; {
  switch (itemStatus) {
    case ItemStatusType.DELIVERY_HOLD:
    case ItemStatusType.DELIVERY_READY:
    case ItemStatusType.DELIVERING:
      return false;
    case ItemStatusType.DELIVERED:
    default:
      return true;
  }
};</code></pre><p>itemStatus의 타입이 문자열로 지정된 경우와 비교해보자</p>
<p><strong>타입 안정성</strong>
ItemStatusType에 명시되지 않은 다른 문자열은 인자로 받을 수 없음. 따라서 타입 안정성이 우수함.</p>
<p><strong>명확한 의미 전달과 높은 응집력</strong>
ItemStatusType 타입이 다루는 값이 무엇인지 명확함.</p>
<p>열거형은 관련이 높은 멤버를 모아 문자열 상수처럼 사용하고자 할 때 유용하게 쓰임</p>
<p>역방향 접근을 막기 위해 <strong>const enum</strong>으로 선언함, but 숫자 상수로 관리된느 열거형은 다른 값을 할당하거나 접근할 때 못 막음. 반면 문자열은 접근을 막아줌</p>
<p>따라서 문자열 상수 방식으로 열거형을 사용하는 것이 안전함</p>
<pre><code>const enum NUMBER {
  ONE = 1,
  TWO = 2,
}
const myNumber: NUMBER = 100; // NUMBER enum에서 100을 관리하고 있지 않지만 이는 에러를 발생시키지 않는다

const enum STRING_NUMBER {
  ONE = &quot;ONE&quot;,
  TWO = &quot;TWO&quot;,
}
const myStringNumber: STRING_NUMBER = &quot;THREE&quot;; // Error</code></pre><p>.
.
.
끝
🫠</p>
<p>출처: 우아한 타입스크립트 with 리엑트</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우타스] 원시 타입, 객체 타입]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85</guid>
            <pubDate>Fri, 23 Aug 2024 11:56:45 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 값은 타입을 가지지만 변수는 별도의 타입을 가지지않음
타입스크립트는 이 변수에 타입을 지정할 수 있는 타입 시스템 체계를 구축함
-&gt; 특정 타입을 지정한 변수에 해당 타입의 값만 할당 가능</p>
<h1 id="원시-타입">원시 타입</h1>
<h2 id="boolean">boolean</h2>
<p>자바스크립트에는 boolean 원시 값은 아니지만 형 변환을 통해 true/false로 취급되는 Truthy/Falsy 값이 존재함 
ex&gt; <code>0, -0, undefined</code></p>
<p>이 값은 boolean 원시 값이 아니므로 타입스크립트에서도 boolean 타입에 해당하지 않음</p>
<h2 id="undefined">undefined</h2>
<p>정의되지 않음, 초기화되지 않은 값
변수 선언만 한 경우</p>
<pre><code>type Person {
    name: string;
    job?: string;</code></pre><p>Person 타입의 job속성의 경우 undefined 할당가능</p>
<h2 id="null">null</h2>
<p>오직 null만 할당 가능
보통 빈값을 할당해야 할 때 null을 사용
이때 사용된 null은 명시적 의도적으로 값이 아직 비어있음을 보여줌</p>
<p><strong>undefined vs null</strong>
자바스크립트에서는 흔히 값이 없다는 것을 나타낼때 이 둘을 혼용함
심지어 ==연산자로 둘 비교하면 true값을 뱉음
하지만 엄연히 따로 존재하는 원시 값이기에 서로의 타입에 할당할 수 없음</p>
<pre><code>type Person1 = {
  name: string;
  job?: string;
};

type Person2 = {
  name: string;
  job: string | null;
};</code></pre><p><code>undefined</code> : job속성이 있을 수 도 없을 수도...
<code>null</code> : job속성을 사람마다 가지고 있지만 값이 비어있을 수도....</p>
<h2 id="number">number</h2>
<p>모든 숫자는 number 타입에 할당 가능
숫자에 해당하는 원시 값 중 <code>NaN</code>이나 <code>Infinity</code>도 포함됨</p>
<h2 id="bigint">bigInt</h2>
<p>ES2020에 새롭게 도입된 데이터 타입. 타입스크립트 3.2버전부터 사용 가능
이전의 js에서는 가장 큰수인 <code>Number.MAX_SAFE_INTEGER</code>를 넘어가는 값을 처리할 수 없었는데 <code>bigInt</code>를 사용하면 이보다 큰 수 처리가능
<code>Number</code>, <code>bitInt</code>는 엄연히 서로 다른 타입이기에 상호작용은 불가능</p>
<h2 id="string">string</h2>
<h2 id="symbal">symbal</h2>
<p>ES2015에서 도입된 데이터 타입으로 Symbol()함수를 사용하면 어떤 값과도 중복되지 않는 유일한 값을 생성할 수 있음</p>
<pre><code>const MOVIE_TITLE = Symbol(&quot;title&quot;);
const MUSIC_TITLE = Symbol(&quot;title&quot;);
console.log(MOVIE_TITLE === MUSIC_TITLE); // false</code></pre><h1 id="객체-타입">객체 타입</h1>
<p>위 7가지 원시 타입에 속하지 않는 값은 모두 객체 타입으로 분류할 수 있음</p>
<h2 id="object">object</h2>
<p><code>object</code>타입은 가급적 사용하지 말도록 권장함. <code>any</code>타입과 유사하게 객체에 해당하는 모든 타입 값을 유동적으로 할당 가능해서 <strong>정적 타이핑</strong>의 의미가 없어져버림</p>
<h2 id="">{}</h2>
<p>중괄호는 자바스크립트에서 객체 리터럴 방식으로 객체를 생성할 때 사용함
빈 객체 타입을 지정하기 위해서는 {}보다는 유틸리티 타입으로 Record&lt;string, never&gt;처럼 사용하는 게 바람직함</p>
<h2 id="array">array</h2>
<p>자바스크립트의 배열 자료구조는 원소를 자유롭게 추가하고 제거할 수 있음
그리고 타입 제한 없이 다양한 값을 다룸, 즉 하나의 배열 안에 숫자, 문자열과 같은 서로 다른 값이 들어있을 수 있음</p>
<p><strong>하지만 이런 쓰임은 타입스크립트가 추구하는 정적 타이핑 방향과 맞지 않음</strong>
그래서 타입스크립트에서는 배열을 array라는 별도 타입으로 다룸
타입스크립트 배열 타입은 하나의 타입 값만 가질 수 있음</p>
<p>Array키워드 사용 or 대괄호([]) 사용</p>
<h2 id="type과-interface키워드">type과 interface키워드</h2>
<p>object타입은 실무에서 잘 안씀.
흔히 객체를 타이핑하기 위해 자주 사용하는 키워드로 type과 interface가 있음.
중괄호를 사용한 객체 리터럴 방식으로 타입을 매번 일일이 지정하기에는 중복적인 요소가 많음. 그래서 type,interface를 아래처럼 씀</p>
<pre><code>type NoticePopupType = {
  title: string;
  description: string;
};

interface INoticePopup {
  title: string;
  description: string;
}
const noticePopup1: NoticePopupType = { /* ... */ };
const noticePopup2: INoticePopup = { /* ... */ };</code></pre><p>일반적으로 타입스크립트에서는 변수 타입을 명시적으로 선언하지 않아도 컴파일러가 타입을 추론함 -&gt; 타입 유추
<strong>명시적으로 할건지, 타입추론을 컴파일러한테 맡길지는 개인취향 or 팁의 컨벤션을 따르자</strong></p>
<p>둘 다 쓸 수 있을 때는 내 기준을 만들거나 팀 컨벤션 따르자 -&gt; <code>책 p76</code></p>
<h2 id="function">function</h2>
<p>함수를 별도 함수 타입으로 지정
자바스크립트에서 typeof 연산자로 확인한 function이라는 키워드 자체를 카입으로 사용하지 않음
둘째, 함수는 매개변수 목록을 받을 수 있는데 이걸 별도 타입으로 지정해야됨
반환값 있으면 반환값에 대한 타이핑이 필요</p>
<pre><code>function add(a: number, b: number): number {
  return a + b;
}</code></pre><p><strong>호출 시그니처</strong>(함수 타입을 정의할 때 사용하는 문법)를 정의하는 방식으로 한다~ 아래처럼</p>
<pre><code>type add = (a: number, b: number) =&gt; number;
</code></pre><p>끝
.
.
.
🫠</p>
<p>출처 : 우아한 타입스크립트 with 리엑트</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우타스] 타입 시스템]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Fri, 09 Aug 2024 00:30:31 GMT</pubDate>
            <description><![CDATA[<h2 id="정적-타입과-동적-타입">정적 타입과 동적 타입</h2>
<p>타입을 결정하는 시점에 따라 타입을 분류</p>
<p><strong>정적 타입(static type)</strong> 
모든 변수의 타입이 컴파일 타임에 결정. 코드 수준에서 타입을 명시해줘야 함
번거롭지만 컴파일타임에 타입에러를 발견할 수 있기 때문에 프로그램의 안정성을 보장</p>
<p><strong>동적 타입(dynamic type)</strong>
변수 타입이 런타임에서 결정됨. 개발자가 직접 타입 정의 X. </p>
<h2 id="강타입과-약타입">강타입과 약타입</h2>
<p><strong>암묵적 타입 변환</strong>
개발자가 의도적으로 타입을 명시하거나 바꾸지 않았는데도 컴파일러 또는 엔진 등에 의해서 런타임에 타입이 자동으로 변경되는 것</p>
<p><strong>강타입</strong>
서로 다른 타입을 갖는 값끼리 연산 시도하면 에러 발생
ex) <code>파이썬</code>, <code>루비</code>, <code>타입스크립트</code>
<strong>약타입</strong>
서로 다른 타입을 갖는 값끼리 연산 시도하면 내부적으로 판단해서 특정 값의 타입을 변환하여 연산을 수행
ex) <code>c++</code>, <code>자바</code>, <code>자바스크립트</code></p>
<h2 id="컴파일-방식">컴파일 방식</h2>
<p><strong>일반적인 컴파일의 의미</strong>
사람이 이해할 수 있는 코드를 컴퓨터가 이해할 수 있는 기계어로 바꿔주는 과정
c#,Java(고수준 언어) -&gt; 컴퓨터가 해석할 수 있는 바이너리 코드(저수준 언어)</p>
<p>but, 타입스크립트의 컴파일 결과물은 자바스크립트 파일임
왜냐 타입스크립트는 사람이 이해하기 쉬운 방식으로 코드를 작성하려고 나온게 아니기 때문임
<strong>JS의 컴파일 타임에 런타임 에러를 사전에 잡아내기 위한 것</strong>임.</p>
<p>-&gt; 타입스크립트를 컴파일하면 타입이 모두 제거된 JS소스코드만 남게됨</p>
<h1 id="타입-시스템">타입 시스템</h1>
<h2 id="구조적-타이핑-구조적-서브-타이핑">구조적 타이핑, 구조적 서브 타이핑</h2>
<p>타입스크립트는 구조로 타입을 구분함. 이것을 구조적 타이핑이라고 함</p>
<p><strong>구조적 서브 타이핑</strong>
타입스크립트의 타입은 값의 집합으로 생각할 수 있음.
<strong>타입은 단지 집합에 포함되는 값이고 특정 값은 많은 집합에 포함될 수 있다.</strong>
따라서 타입스크립트에서는 특정 값이 string 또는 number 타입을 동시에 가질 수 있음.</p>
<p>이런 TS의 타입 시스템을 지탱하고 있는 개념이 바로 <strong>구조적 서브 타이핑</strong>임
: 객체가 가지고 있는 속성을 바탕으로 타입을 구분하는 것. 이름이 다른 객체라도 속성이 동일하다면 TS는 서로 호환이 가능한 동일한 타입으로 여김</p>
<pre><code>interface Pet {
  name: string
}

interface Cat {
  name: string
  age: number
}

let pet: Pet;
let cat: Cat = { name: &quot;Zag&quot;, age: 2 };

// ✅ OK
pet = cat;</code></pre><p>Cat은 Pet과 다른 타입으로 선언. 하지만 Pet이 가지고 있는 name속성을 가지고 있음.
따라서 Cat타입으로 선언한 cat을 Pet타입으로도 선언한 pet에 할당 가능</p>
<p><strong>JS</strong> - <code>덕타이핑</code> - <code>런타임에 검사</code>
<strong>TS</strong> - <code>구조적 타이핑</code> - <code>컴파일타임에 검사</code>
두 방식 모두 객체가 가진 속성을 기반으로 타입을 검사</p>
<h2 id="ts의-점진적-타입-확인">TS의 점진적 타입 확인</h2>
<p>필요에 따라 타입 선언 생략을 허용하는 방식</p>
<pre><code>function add(x, y) {
  return x + y;
}

// 위 코드는 아래와 같이 암시적 타입 변환이 일어난다.
function add(x: any, y: any): any</code></pre><p>그러나 TS는 컴파일타임에 프로그램의 모든 타입을 알고 있을 때 최상의 결과를 보여줌
그리하여, TS컴파일옵션에 <code>noImplicitAny = true</code>로 설정하는 것이 좋음</p>
<h2 id="값-vs-타입">값 vs 타입</h2>
<p>값은 프로그램이 처리하기 위해 메모리에 저장하는 모든 데이터
객체 역시 값. JS에서는 함수도 값. 모든 것이 객체인 언어이기 때문에 런타임에 객체로 변환됨</p>
<p>ex)</p>
<pre><code>const goWork = function (developer) {
    console.log(`tired ${developer}`);
}</code></pre><p>JS대신 타입스크립트에서는  변수,매개변수,객체 속성 등에 : type 형태로 타입을 명시함
ex) <code>const a:number = 223</code></p>
<p><code>type</code>,<code>interface</code>키워드로도 가능</p>
<p>값 공간과 타입 공간의 이름은 서로 충돌하지 않기 때문에 타입과 변수를 같은 이름으로 정의할 수 있음
<strong>타입스크립트 문법인 type으로 선언한 내용은 JS 런타임에서 제거되기 때문</strong></p>
<p>함수의 매개변수처럼 여러개의 심볼이 함께 쓰인다면 타입과 값을 명확하게 구분해야 함
TS는 개발자가 작성한 코드 문맥을 파악해서 스스로 값,타입을 해석 -&gt; <strong>구분해서 작성해야함</strong></p>
<p>ex)</p>
<pre><code>function email(options: { person: Person; subject: string; body: string }) {}</code></pre><p>타입스크립트에서 구조분해할당하면 <code>Person</code>과 <code>string</code>이 값의 관점에서 해석됨.
그니까 <code>Person</code>,<code>string</code>이 값 공간에 있는 것으로 해석한다는 거임.</p>
<p>개발자의 의도는 매개변수 객체의 속성인 <code>perosn</code>을 <strong>Person타입</strong>, <code>subject</code>,<code>body</code>는 <strong>string타입</strong>으로 설정해서 제한하는 건데,Person과 string이 값의 관점에서 해석해버림.</p>
<p>그래서 값과 타입을 구분해서 작성해야됨</p>
<p><strong>like this</strong></p>
<pre><code>function email({
  person,
  subject,
  body
}:{
  person: Person;
  subject:string;
  body:string;
}){
  ~~~~~~
}</code></pre><p>class나 enum은 값으로도 타입으로도 사용됨</p>
<p>ex) </p>
<pre><code>const me: Developer = new Developer(&quot;zig&quot;,&quot;frontend&quot;)
          -&gt;타입          -&gt;값</code></pre><p>enum을 자주 사용하는 팀도 있고 아닌 팀들도 있는 듯!...</p>
<p>.
.
.</p>
<p>출처: 우아한 타입스크립트 with 리엑트</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우타스] 타입스크립트는 좋은 선택지]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%A2%8B%EC%9D%80-%EC%84%A0%ED%83%9D%EC%A7%80</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9A%B0%ED%83%80%EC%8A%A4-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%A2%8B%EC%9D%80-%EC%84%A0%ED%83%9D%EC%A7%80</guid>
            <pubDate>Wed, 07 Aug 2024 01:14:11 GMT</pubDate>
            <description><![CDATA[<p>앞으로 우타스를 읽으면서 중요한 내용들을 내 말로 적어놓을 계획!...</p>
<h1 id="타입스크립트의-등장">타입스크립트의 등장</h1>
<p>먼저...</p>
<h2 id="웹개발-역사를-간략히-알아보자">웹개발 역사를 간략히 알아보자!</h2>
<p><strong>JS가 어떻게 브라우저에서 널리 사용되기 시작했을까?</strong></p>
<blockquote>
<p>두 경쟁 업체에서 각자의 브라우저에 새로운 기능을 빠르게 늘리기 시작. 
추가된 기능은 각자의 브라우저에서만 동작(다르게 동작 or 크로스 브라우징 이슈).
따라서 개발자는 따로 개발해야하는 어려움이 있었고, 따라서 JQuery와 같이 호환성 고민필요없는 라이브러리가 유행하게됨</p>
</blockquote>
<p>하지만 이런 라이브러리에 기댈 수는 없었고 표준화된 JS의 필요성이 제기됨
*<em><code>ECScript</code>라는 이름으로 자바스크립트 표준화를 공식화
*</em></p>
<h2 id="웹사이트에서-웹-애플리케이션으로의-전환">웹사이트에서 웹 애플리케이션으로의 전환</h2>
<p><strong>웹사이트</strong> </p>
<blockquote>
<p>수집된 데이터 및 정보를 특정 페이지에 표시하기 위한 정적인 웹
단뱡향으로 정보 제공, 상호작용X, 콘텐츠가 동적으로 업데이트X</p>
</blockquote>
<p><strong>웹 애플리케이션</strong></p>
<blockquote>
<p>쌍방향 소통의 웹</p>
</blockquote>
<p>웹 서비스는 점차 페이지에서 애플리케이션의 특성을 가지게됨
<code>이유</code> : 디바이스 댜양성 증가. 데이터 폭발적 증가. UI/UX 다양 및 복잡</p>
<p>그리하여 <strong>CBD방법론</strong>이 등장 </p>
<blockquote>
<p><strong>컴포넌트 베이스 개발</strong> : 재사용할 수 잇는 컴포넌트를 개발 또는 조합해서 개발 </p>
</blockquote>
<p>여튼 이런 개발 생태계 발전과 동적 웹서비스의 수요 증가로 인해 JS개발자가 증가하게 됐다~</p>
<h2 id="js의-한계">JS의 한계</h2>
<p><strong>동적 타입 언어</strong>
변수에 타입을 명시적으로 지정하지 않고 코드가 실행되는 <strong>런타임</strong>에 변숫값이 할당될 때 해당 값의 타입에 따라 변수 타입이 결정됨</p>
<p>뭔말이냐하면
변수 a의 타입이 <code>number</code>인지 <code>string</code>인지는 실제 코드가 동작할 때 a에 값이 할당되는 그 순간에 그 값이 1인지 &#39;1&#39;인지에 따라 결정된다는 거임</p>
<pre><code>const sumNumber = (a,b) =&gt;{
    return a + b;
}

sumNumber(100) // NaN
sumNumber(&#39;a&#39;,&#39;b&#39;) // ab</code></pre><p>JS에서는 해당 코드가 오류가 안난다. 왜? 동적 타입 언어니까.
<code>subNumber</code>함수를 호출할 때 사용되는 인수 값에 따라 <code>a</code>와 <code>b</code>의 타입이 결정됨.
심지어 하나만 전달했을때는 나머지 하나를 적절한 타입인 <code>NaN</code>으로 형변환한 후에 실행해버림</p>
<p>해당 함수를 짠 개발자의 의도는 <strong>두 숫자의 합을 구하는 함수</strong>이다.
그러나 하나의 숫자만 전달해도 오류없이 NaN값을 뱉고, 문자열의 합을 구하는데에도 쓰임 -&gt; <strong>개발자의 의도와 다르게 동작할 수 있음</strong></p>
<p>이러한 문제들을 다양한 방법으로 해결하려고 했고 여러 해결방안 뒤에 
.
.
.
JS의 슈퍼셋 언어인 <strong>타입스크립트</strong>가 등장함</p>
<p>책에서 말하기를 &#39;자바스크립트는 사용하면 안 된다. 무조건 타입스크립트를 사용해야 한다&#39;라는 의미로 받아들이지 말라고 한다.</p>
<p>단지 <strong>좋은 선택지</strong>가 될 수 있다는 것을 의미</p>
<p>.
.
.</p>
<p>출처: 우아한 타입스크립트 with 리엑트</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS]This]]></title>
            <link>https://velog.io/@miin-hyukkk/JSThis</link>
            <guid>https://velog.io/@miin-hyukkk/JSThis</guid>
            <pubDate>Mon, 05 Aug 2024 08:28:38 GMT</pubDate>
            <description><![CDATA[<h1 id="this">This</h1>
<p><strong>기술 질문</strong></p>
<p><strong>JavaScript 에서 Function안의 this란?</strong></p>
<blockquote>
<p>현재 함수를 부른 객체가 누구인지를 나타내며 고정값이 아닙니다. 함수 내 this는 함수가 호출되는 방식에 따라 결정됩니다.</p>
</blockquote>
<h3 id="예시를-통해-this가-뭔지-감을-잡아보자"><strong>예시를 통해 this가 뭔지 감을 잡아보자!</strong></h3>
<p><strong>this</strong>는 기본적으로 <strong>window</strong>임</p>
<pre><code class="language-jsx">this; // Window {}</code></pre>
<p>일반 함수 내에서 혼자 <strong>this</strong>를 선언하면, 그 <strong>this</strong>는 <strong>window</strong> 객체를 가리킴</p>
<pre><code class="language-jsx">function myFunction() {
  console.log(this);
}
myFunction();</code></pre>
<p>객체의 메서드 내에서 <strong>this</strong>는 그 메서드가 <strong>속한 객체</strong>를 가리킴</p>
<p>객체 메서드 <strong>sayHello</strong> 안의 <strong>this</strong>는 객체 <strong>myObject</strong>를 가리킴 (호출 시 내부적으로 바꿔줌)</p>
<pre><code class="language-jsx">const myObject = {
  name: &#39;민혁&#39;,
  sayHello: function() {
    console.log(this.name);
  }
};

myObject.sayHello();</code></pre>
<p><strong>but, 아래처럼하면??</strong></p>
<pre><code class="language-jsx">var sayHello2 = myObject.sayHello()
sayHello2(); </code></pre>
<p>이 경우 <strong>sayHello2</strong>는 <strong>myObject.sayHello 메서드의 참조를 변수에 할당</strong>한거임</p>
<p>이 할당된 함수 <strong>sayHello2</strong>는 독립적인 함수가 되고, myObject 객체와 연결되어 있지 않음</p>
<p>따라서 전역으로 <strong>sayHello2</strong>를 호출하면, <strong>this</strong>는 기본적으로 <strong>전역 객체(window)를 참조함</strong>.</p>
<p>브라우저 환경에는 당연히 name이라는 속성이 없고, 따라서 undefined를 출력함</p>
<p>대강 봤을때, JS에서  함수 내 this는 함수가 호출되는 방식에 따라 결정된다는 걸 알 수 있음.</p>
<p>.
.
.</p>
<h3 id="객체-메서드에서의-this"><strong>객체 메서드에서의 this</strong></h3>
<pre><code class="language-jsx">function getThis() {
  return this;
}

const obj1 = { name: &quot;obj1&quot; };
const obj2 = { name: &quot;obj2&quot; };

obj1.getThis = getThis;
obj2.getThis = getThis;

console.log(obj1.getThis()); // { name: &#39;obj1&#39;, getThis: [Function: getThis] }
console.log(obj2.getThis()); // { name: &#39;obj2&#39;, getThis: [Function: getThis] }</code></pre>
<p><strong>obj1.getThis()</strong>와 <strong>obj2.getThis()</strong>는 각각 obj과 obj2를 this로 참조</p>
<h3 id="프로토타입-체인에서의-this"><strong>프로토타입 체인에서의 this</strong></h3>
<p>함수가 객체의 프로토타입 체인 상에서 호출될 때도, this는 호출하는 객체를 참조함</p>
<pre><code class="language-jsx">const obj1 = {
  name: &quot;obj1&quot;,
  getThis() {
    return this;
  },
};

const obj3 = {
  __proto__: obj1,
  name: &quot;obj3&quot;,
};

console.log(obj3.getThis()); // { name: &#39;obj3&#39; }</code></pre>
<p>JS의 모든 객체는 다른 객체를 참조하는 프로토타입을 가질 수 있음</p>
<p>예제에서 obj3는 obj1을 프로토타입으로 설정함. 이를 통해 obj3은 obj1의 속성과 메서드를 상속받음</p>
<p><strong>작동방식</strong></p>
<blockquote>
<ol>
<li>JS엔진은 obj3객체에서 getThis를 찾으려고 시도</li>
<li>없으니까, JS엔진은 obj3의 프로토타입인 obj1로 가서 getThis를 찾음</li>
</ol>
</blockquote>
<h3 id="strict-mode에서의-this"><strong>Strict mode에서의 this</strong></h3>
<p><strong>strict mode에서는</strong> 다음과 같은 상황에 애초에 this가 undefined를 가리킴</p>
<p><strong>strict mode가 아닐경우</strong>, this는 기본적으로 전역 객체를 가리킴</p>
<p><strong>strict mode에서 this가 undefined를 가리키는 이유</strong></p>
<p>: 코드 작성자가 의도치 않게 전역 객체의 속성을 수정하거나 접근할 수 있기 때문</p>
<h3 id="콜백-함수의-this">콜백 함수의 this</h3>
<p><strong>strict mode</strong></p>
<pre><code class="language-jsx">function logThis() {
  &quot;use strict&quot;;
  console.log(this); // 100
}

[1, 2, 3].forEach(logThis, 100); // 100, 100, 100</code></pre>
<p>this가 명시적으로 설정되지 않으면 undefined가 되지만, 여기서는 thisArg를 사용함.</p>
<p>그래서 thisArg로 설정된 값(100)이 this로 사용됨</p>
<p><strong>non strict mode</strong></p>
<pre><code class="language-jsx">function logThis() {
  console.log(this); // 100
}

[1, 2, 3].forEach(logThis, 100); // [Number: 100],[Number: 100],[Number: 10</code></pre>
<p>여기서는 this가 전역인 window 값이지만 thisArg를 사용함으로서,  thisArg(100)는 Number객체로 변환됨</p>
<p><strong>이게 가능한 이유</strong></p>
<p>배열의 반복 메서드(<code>forEach</code>, <code>map</code>, <code>filter</code> 등)와 <code>Set.prototype.forEach()</code> 메서드는 <code>thisArg</code> 매개변수를 받아 콜백 함수의 <code>this</code> 값을 설정할 수 있음</p>
<p><strong><code>JSON.parse</code>와 <code>JSON.stringify</code>의 콜백</strong></p>
<pre><code class="language-jsx">const json = &#39;{&quot;name&quot;:&quot;Alice&quot;,&quot;age&quot;:25}&#39;;

const parsed = JSON.parse(json, function(key, value) {
  console.log(this); // &#39;this&#39;는 현재 처리 중인 객체
  return value;
});

const obj = { name: &quot;Bob&quot; };
const jsonString = JSON.stringify(obj, function(key, value) {
  console.log(this); // &#39;this&#39;는 obj
  return value;
});</code></pre>
<p>JSON의 <code>parse</code>와 <code>stringify</code> 메서드는 콜백의 this를 처리 중인 객체로 설정함</p>
<h3 id="화살표-함수의-this">화살표 함수의 this</h3>
<blockquote>
<ul>
<li>상위 스코프의 this를 그대로 사용함</li>
</ul>
</blockquote>
<ul>
<li>자기 자신만의 this를 가지지 않음</li>
<li>화살표 함수가 정의된 위치의 this를 그대로 사용</li>
</ul>
<p><strong>즉, 화살표 함수가 만들어질때의 this를 기억하고, 그 값을 계속 사용함</strong></p>
<p>화살표함수는 어떻게 호출을 하던 <strong>this</strong>가 바뀌지 않음. </p>
<p><strong>this</strong>는 항상 함수가 정의될때의 <strong>상위 스코프의 this를 유지</strong></p>
<pre><code class="language-jsx">const cat = {
  name: &#39;meow&#39;;
  callName: () =&gt; console.log(this.name);
}

cat.callName();    // undefined</code></pre>
<p><strong>callName</strong>메소드의 this는 자신을 호출한 객체 <strong>cat</strong>이 아니라 함수 선언 시점의 상위 스코프, 즉 <strong>전역객체</strong>를 가리킴. </p>
<p>(strictmode라면 undefined이고, non strictmode라면 window일거임!)</p>
<p><strong><em>따라서 저럴 경우는 일반 함수로 callName을 선언해야됨</em></strong></p>
<h3 id="생성자-함수에서-this">생성자 함수에서 this</h3>
<p><strong>기본 생성자 함수</strong>:  <strong>new</strong>와 함께 호출하면, 새 객체가 만들어지고 <strong>this</strong>는 그 새 객체를 가리킴</p>
<pre><code class="language-jsx">function C() {
  this.a = 37; // 새로 만들어진 객체에 &#39;a&#39;라는 프로퍼티를 37로 설정
}

let o = new C(); // &#39;new&#39;를 사용해 C 함수 호출
console.log(o.a); // 37</code></pre>
<p><strong>객체 반환</strong>: 생성자 함수가 객체를 반환하면, 새로 만든 객체 대신 반환된 객체가 사용됨</p>
<p>.
.
.
끝🫠</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS]Closures(클로저)]]></title>
            <link>https://velog.io/@miin-hyukkk/JSClosures</link>
            <guid>https://velog.io/@miin-hyukkk/JSClosures</guid>
            <pubDate>Mon, 05 Aug 2024 08:22:50 GMT</pubDate>
            <description><![CDATA[<h1 id="closures"><strong>Closures</strong></h1>
<p><strong>기술질문</strong> </p>
<p><strong>클로저가 뭔가요?</strong></p>
<blockquote>
<p>클로저는 함수와 그 함수가 정의된 렉시컬 환경이 결합된 상태를 말합니다.
이 상태로 인해 함수는 자신이 정의될 당시의 변수를 기억하고, 그 변수에 접근할 수 있는 것입니다.</p>
</blockquote>
<p><strong>MDN 공식 문서</strong></p>
<blockquote>
<p>클로저는 함수와 그 함수가 선언된 주변 상태(렉시컬 환경, 그 환경에 있는 변수들)를 함께 묶은 조합임.
쉽게 말해 클로저는 내부함수가 외부함수의 스코프에 접근할 수 있게 해주는 메커니즘임. </p>
</blockquote>
<p><strong>자바스크립트에서는 함수가 생성될 때마다 클로저가 만들어진다고 보면됨.</strong></p>
<h3 id="일단-렉시컬-스코핑에-대해-가볍게-알아보자"><strong>일단 렉시컬 스코핑에 대해 가볍게 알아보자</strong></h3>
<p>렉시컬 스코핑은 자바스크립트가 변수를 찾는 방식임. </p>
<p>함수가 정의된 <strong>위치</strong>에 따라 변수의 스코프가 결정되고, 함수가 실행될 때, 해당 함수가 어디에서 정의되었는지에 기반에 외부 변수에 접근 가능함.</p>
<p>이런 접근 가능성은 함수가 호출되는 시점이 아니라 <strong>정의되는 시점에 결정</strong>됨</p>
<h3 id="클로저는-다음-세가지-요소가-결합된-상태"><strong>클로저는 다음 세가지 요소가 결합된 상태</strong></h3>
<blockquote>
<ul>
<li>내부 함수 : 외부 함수의 스코프 안에서 정의된 함수</li>
</ul>
</blockquote>
<ul>
<li>외부 함수의 변수: 내부 함수가 접근할 수  있는 외부 함수의 변수들</li>
<li>환경 : 내부 함수가 정의될 때의 외부 함수의 스코프</li>
</ul>
<h3 id="클로저의-주요-포인트"><strong>클로저의 주요 포인트</strong></h3>
<blockquote>
<ul>
<li>내부 함수가 외부 함수의 변수를 참조할 수 있어야함</li>
</ul>
</blockquote>
<ul>
<li>외부함수의 실행이 끝난 후에도 변수 접근이 유지됨</li>
</ul>
<p><strong>외부함수의 실행이 끝난 후에도 변수 접근이 유지됨:</strong></p>
<blockquote>
<p>일반적인 함수는 실행이 끝나면 메모리에서 해당 함수의 스코프 및 변수는 사라짐.
하지만 외부함수의 변수를 내부함수가 참조한 형태에서는 외부함수의 호출이 끝난 후에도, 내부함수(클로저)가 외부함수의 스코프를 계속 참조하고 있으므로, 메모리에서 사라지지 않음</p>
</blockquote>
<p>⇒  <code>inner</code>함수가 <code>outer</code>함수 변수 참조하고 있어서, <code>outer</code>함수 실행이 끝난 뒤에도 <code>outer</code>함수의 변수들을 기억하고 있다는 뜻</p>
<h3 id="클로저-작동-예제1"><strong>클로저 작동 예제1</strong></h3>
<pre><code class="language-jsx">function outer() {
  let outerVar = &quot;I am outside!&quot;;

  function inner() {
    console.log(outerVar); // innerFunction이 외부 함수의 변수에 접근
  }

  return inner; // 클로저를 반환
}

const myClosure = outer(); // outer 실행 후 innerFunction 반환
myClosure();</code></pre>
<p><code>outerFunction</code>의 실행이 끝난 후에도 <code>innerFunction</code>이 <code>outerVar</code>을 계속 참조할 수 있기 때문에 클로저가 형성돼.</p>
<h3 id="클로저-작동-예제2"><strong>클로저 작동 예제2</strong></h3>
<pre><code class="language-jsx">function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12</code></pre>
<p><code>makeAdder</code>는 x라는 매개변수를 받아서 x와 y를 더하는 함수를 반환함 → 이 반환된 함수는 x+y를 반환함</p>
<blockquote>
<p><code>makeAdder(5)</code>를 호출하면, 내부에서는 x가 5로 설정된 함수를 반환함.
이 함수는 x=5가 포함된 렉시컬 환경을 기억하고 있고, 이 반환된 함수가 <code>add5</code>에 할당됨</p>
</blockquote>
<blockquote>
<p><code>makeAdder(10)</code>을 호출하면, 내부에서 x가 10으로 설정된 함수를 반환함.
이 함수는 x=10이 포함된 렉시컬 환경을 기억하고 있고, 이 반환된 함수가 add10에 할당됨</p>
</blockquote>
<p><strong>add5와 add10은 동일한 함수 본문을 사용하고 있지만, 각기 다른 렉시컬 환경을 가지고 있음</strong></p>
<p><strong>클로저 덕분에 add5와 add10은 자신이 정의될 때의 x값을 계속해서 사용 가능한거임</strong></p>
<h3 id="결론"><strong>결론</strong></h3>
<p>클로저는 함수의 생성 시점에서의 상태를 “<strong>기억</strong>”하고, 나중에 호출되었을 때 그 상태를 <strong>유지</strong>하며 사용할 수 있게 해준다</p>
<p>.
.
.</p>
<p>끝🫠</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 변경에 유연한 컴포넌트]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B3%80%EA%B2%BD%EC%97%90-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8</guid>
            <pubDate>Wed, 27 Mar 2024 04:31:31 GMT</pubDate>
            <description><![CDATA[<h1 id="변경에-유연">변경에 유연</h1>
<blockquote>
<ol>
<li>Headless 기반의 추상화</li>
<li>한가지 역할만 하기</li>
<li>도메인 분리하기</li>
</ol>
</blockquote>
<p>컴포넌트는 무엇을 할까?</p>
<blockquote>
<p><strong>데이터 관리</strong> : 외부에서 들어오는 데이터, 상태 같은 내부 데이터를 관리
<strong>UI</strong> :  그 데이터를 어떻게 보여질지를 정의
<strong>유저와 상호작용</strong></p>
</blockquote>
<h2 id="headless-기반의-추상화">Headless 기반의 추상화</h2>
<h3 id="데이터-추상화">데이터 추상화</h3>
<p>디자인에 의존하는 UI를 컴포넌트가 관리하는 &#39;데이터&#39;와 분리해보자</p>
<p>내가 제작한 로그인 페이지를 예로 살펴보자</p>
<p>데이터와 UI를 분리해보자</p>
<p><strong>로그인 정보에 필요한 데이터를 추상화</strong>해서 <code>useLogin</code>라는 <code>hook</code>으로 표현해줌</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/7022ce39-46b9-472d-a088-b91cff223ed4/image.png" alt=""></p>
<p>이제 이 <code>Login</code>이라는 컴포넌트에서는 컴포넌트에서는 <code>hook</code>에서 반환된 값을 <strong>어떻게 보여질지</strong>만 정의하면됨</p>
<p>로그인 정보를 관리하는 창 혹은 로그인 관련된 정보를 보여줘야 하는 창에서는 이 <code>useLogin hook</code>을 가져다 사용 할 수 있음.</p>
<p>지금 이렇게 한 작업은 ui를 관심사에서 제거한 작업임. =&gt; Headless</p>
<p>오로지 데이터에만 집중해서 모듈화를 진행. 한가지 문제에만 집중하기 때문에 더 많은 곳에서 사용할 수 있고, 다른 변경으로부터 격리시킬 수 있음.</p>
<h3 id="동작-추상화">동작 추상화</h3>
<p>로그인, 회원가입, 주문페이지 등등 쇼핑몰 프로젝트 내부 다양한 페이지에서 input창의 쓰이고 그럴때마다 input에 관련된 동일한 동작들에 대한 코드가 반복됨 =&gt; 컴포넌트 내부에 여러가지 로직이 들어가게 되고 결국 복잡해짐</p>
<p>데이터 부분을 추상화했던 것처럼 상호작용 부분을 추상화</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/df2f52fd-263b-4e48-9f23-3fe0058d2111/image.png" alt="">
: 메모이제이션을 활용해 input을 추상화</p>
<h2 id="한가지-역할만-하기">한가지 역할만 하기</h2>
<p>변경에 유연해지려면 각 컴포넌트들이 한가지 역할만 하는게 중요함.
결국 같은 UI 내부에 있어도 각 컴포넌트들은 기능별로, 데이터별로 분리되어 있어야 하고, 그에 따라 서로의 역할을 몰라야함.</p>
<p>그래야 변경에 유연하게 컴포넌트를 제작할 수 있음.</p>
<h2 id="도메인-분리하기">도메인 분리하기</h2>
<p>모든 컴포넌트에서 데이터로 접근할 수 있지만, 컴포넌트를 주입 받듯 데이터를 주입 받자 -&gt; 도메인을 분리</p>
<blockquote>
<p>이해하기 쉽게 설명을 해보자면, <strong>컴포넌트에서 도메인에 해당하는 정보들을 걷어내는거임</strong>. <code>A 컴포넌트</code>와 <code>B 컴포넌트</code>는 각각 다른 데이터를 통해 비슷한 UI를 보여준다고 가정해보자. 만약 <code>A 컴포넌트</code> 제작 시, <code>A 컴포넌트</code>의 데이터들에 국한되게 컴포넌트들을 네이밍한다면, 그대로 <code>B 컴포넌트</code>에 <strong>해당 컴포넌트를 재사용하기는 어려워질 것</strong>이다. </p>
</blockquote>
<p>정리하자면, <strong>컴포넌트에서 도메인에 해당하는 정보, 즉 데이터에 관련된 정보를 걷어내서 네이밍을 일반적으로 함으로써 여러 페이지에서 재사용이 가능</strong>해지는 것이다.</p>
<ul>
<li><p>컴포넌트 인터페이스는 일반적일수록 이해하기 쉬움</p>
<ul>
<li>사람은 배경지식으로 무언가를 해석함 
=&gt; 최대한 일반적인 단어로 표현해야 의도를 드러내기 쉽다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>실제 프로젝트를 하면서도 네이밍을 일반적이지 않게 했다가, 나중에 비슷한 UI를 제작하고 해당 인터페이스를 가져다 사용하려고 할때, 네이밍을 다시 일반적이게 수정한 경험이 수두룩하다.</p>
</blockquote>
<p>결국 표준에 가까울수록 많은 사람들이 쉽게 이해할 수 있음.</p>
<hr>
<blockquote>
<p>*<em>구현해야하는 기능이 이미 있듯이 작성하고, 그것을 사용하듯이 개발해라
*</em></p>
</blockquote>
<p>🫠</p>
<p>출처 : <a href="https://www.youtube.com/watch?v=fR8tsJ2r7Eg">https://www.youtube.com/watch?v=fR8tsJ2r7Eg</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Hydrate]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Hydrate</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Hydrate</guid>
            <pubDate>Wed, 21 Feb 2024 08:44:22 GMT</pubDate>
            <description><![CDATA[<h1 id="hydrate">Hydrate</h1>
<p><strong>:HTML코드와 React인 JS코드를 서로 매칭시키는 과정</strong>
서버사이드에서 클라이언트 사이드한테 렌더링 된 정적 페이지, 번들링된 JS파일 보냄. 클라이언트는 받아서 HTML,JS 서로 매칭</p>
<p><strong>정적인 페이지에 물을 주어 동적으로 만듦</strong></p>
<p>이것에 대해 알아보기 전 리엑트의 웹페이지 구성원리에 대해 알아보자</p>
<h3 id="react에서의-웹페이지-구성-원리">React에서의 웹페이지 구성 원리</h3>
<blockquote>
<ol>
<li>도메인 주소(<a href="http://www.naver.com)%EC%97%90">www.naver.com)에</a> 접속</li>
<li>DNS 서버는 해당 도메인 주소에 맞는 IP주소로 요청을 보내줌</li>
<li>서버는 클라이언트에게 HTML documentI(index.html), JS파일(App.js)를 보내줌</li>
<li>서버로부터 받아온 파일들로 Render Tree 구성하고 웹화면을 렌더링</li>
</ol>
</blockquote>
<p>React는 JS파일만을 이용하여 웹화면을 구성하는 원리를 가지고 있음.</p>
<p>그래서 실제 HTML코드는 안에 내용이 하나도 없음</p>
<p><strong>단순뼈대만 있는 HTML document</strong>와 <strong>JS파일</strong>을 클라이언트에게 보내면, 클라이언트는 이 JS코드들을 통해 웹화면을 렌더링하며 페이지를 그리게됨</p>
<p>public/index.html은 알다시피 아무내용없고 뼈대만 있음.
src/index.js의 자바스크립트 코드에서 모든 화면을 렌더링 한 뒤 HTML DOM요소 중 root라는 아이디를 가진 엘리먼트를 찾아서 하위로 주입하게 된다.</p>
<h3 id="nextjs에서의-웹페이지-구성-원리">Next.js에서의 웹페이지 구성 원리</h3>
<p>리엑트와는 다르게 Next.js는 클라이언트에게 웹 페이지를 보내기전에 서버 사이드 단에서 미리 웹페이지를 Pre-Rendering 함.
그리고 그렇게 생성된 HTML document를 클라이언트에게 전송함.
즉, React처럼 빈껍데기인 index.html이 아니라 pre-rendering된 HTML 파일을 보내는 거임</p>
<p>하지만 알다시피, 현재 클라이언트가 받은 웹 페이지는 단순히 웹 화면만 보여주는 HTML이다.
자바스크립트 요소는 하나도 없음(=JS모듈,이벤트리스너들이 DOM요소에 적용안된 상태)</p>
<p>프로젝트를 실행하고 네트워크 탭을 누르면</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/cb9c598a-9dcb-4cda-9eeb-44ebe0366a0a/image.png" alt=""></p>
<p>맨처음 Pre-rendering된 document 파일을 받고, 이후에 <strong>렌더링된 JS파일</strong>들이 Chunk단위로 다운로드 되는것을 볼 수 있음.</p>
<p>그리고 이 JS코드들이 이전에 보내진 HTML DOM 위에서 <strong>한번 더 렌더링</strong>을 하면서, 각자 자기 자리를 찾아가며 매칭이 됨</p>
<p>-&gt;이 과정을 <strong>Hydrate</strong>이라고 부름</p>
<p>✔️  Pre-rendering한 Document는 모든 JS요소들이 빠진 가벼운 상태이므로 클라이언트에게 빠른 로딩이 가능함. 두번 렌더링이 일어나는 단점을 보완하고도 남음</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 웹 동작 과정]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%9B%B9-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%9B%B9-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Wed, 21 Feb 2024 08:03:31 GMT</pubDate>
            <description><![CDATA[<p>최근 next.js 프로젝트에서 웹페이지 성능을 올리기 위해 이것저것 하다 기초적인 지식이 탄탄하지 않다는 느낌을 받아 이 포스트를 작성</p>
<h3 id="웹페이지가-렌더링-되는-과정">웹페이지가 렌더링 되는 과정</h3>
<blockquote>
<ol>
<li>HTML parser가 HTML을 바탕으로 DOM tree를 그림</li>
<li>CSS parser가 CSS를 바탕으로 CSSOM을 그림</li>
<li>DOM에 CSSOM을 적용하여 Reder Tree를 그림</li>
<li>Render Tree를 바탕으로 Painting하여 실제 화면에 렌더링</li>
</ol>
</blockquote>
<h3 id="dom이란"><strong>DOM이란?</strong></h3>
<p>웹 브라우저와 Javascript가 HTML을 이해하기 쉽도록 트리 구조로 파싱하여 만든 구조화된 표현, 즉 객체입니다.</p>
<p><strong>그저 텍스트에 불과한 HTML을 HTML파서가 DOM이라는 트리구조의 객체로 변환함</strong></p>
<blockquote>
<p><strong>누구를</strong> :  HTML을
<strong>누가</strong>: HTML파서가<br><strong>무엇으로</strong> : DOM이라는 트리구조로</p>
</blockquote>
<p>DOM: 브라우저와 Javascript가 이해할 수 있는 구조</p>
<h3 id="cssom이란"><strong>CSSOM이란?</strong></h3>
<p>DOM에 CSS를 입힌것. DOM에 CSS가 적용된 객체 모델</p>
<p>ex&gt; <code>&lt;p style=&quot;display: none;&quot;&gt;How are you?&lt;/p&gt;</code><br>→ <strong>DOM에는 포함</strong>, but <strong>CSSOM에는 포함X</strong></p>
<blockquote>
<p><strong>웹을 동적으로 제어한다 = DOM을 제어한다</strong>
JS가 DOM을 동적으로 제어할 수 있게, DOM API 라는 것이 기본적으로 제공됨</p>
</blockquote>
<h3 id="jquery-등장-한계점"><strong>JQuery 등장, 한계점</strong></h3>
<blockquote>
<ul>
<li>JS라이브러리, DOM 조작 중심 개발 방식 → 애플리케이션의 상태관리 복잡하게 만듦→ 유지보수 어려움</li>
</ul>
</blockquote>
<ul>
<li>모듈화 부족 → 코드 재사용성 떨어짐, 유지보수 어려움</li>
<li>성능 문제 → 동적인 DOM이 잦은 요즘에는 많은 연산량으로 성능 하락</li>
</ul>
<h3 id="virtual-dom-등장"><strong>Virtual DOM 등장</strong></h3>
<p>직접적인 DOM조작 → 성능저하 → Virtual DOM 등장</p>
<p>Virtual DOM:  실제 DOM을 추상화한 메모리 내 표현</p>
<blockquote>
<ul>
<li>조작이 편함 : 리모컨이 TV조작하는거마냥, 복잡한 내부구조 몰라도 원하는 결과를 얻음</li>
</ul>
</blockquote>
<ul>
<li>성능 최적화 : Virtual DOM은 변경사항을 메모리에 빠르게 적용 → 실제 DOM에는 Diffing알고리즘을 사용하여 최소한의 변경사항으로 계산</li>
<li>자동화된 프로세스 : 리엑트 같은 라이브러리는 이 전체 과정을 자동화함. 개발자가 할 일이라고는 상태관리와 상태변화에 따라 UI를 어떻게 변경할지 선언 뿐임</li>
</ul>
<p><strong>React에서의 Virtual DOM</strong></p>
<p>리엑트에서 값이 변할때 화면의 깜빡임 없이 빠르게 값이 변경되는건 모두 Virtual DOM 때문임
가상 돔을 실제 돔과 비교해 다른 부분만 빠르게 반영해 새로 화면에 렌더링해줌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] 서스펜스와 SSR]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%84%9C%EC%8A%A4%ED%8E%9C%EC%8A%A4%EC%99%80-SSR</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%84%9C%EC%8A%A4%ED%8E%9C%EC%8A%A4%EC%99%80-SSR</guid>
            <pubDate>Tue, 13 Feb 2024 06:13:26 GMT</pubDate>
            <description><![CDATA[<p>SSR을 사용하면 JavaScript 번들이 로드되고 실행되기 전에 사용자가 페이지의 콘텐츠를 볼 수 있음</p>
<p>목적 : 앱의 사용자가 콘텐츠를 더 빨리 보고 훨씬 더 빠르게 상호 작용을 시작</p>
<h3 id="이-부분을-공부하고-프로젝트에-적용해야겠다고-생각한-이유"><strong>이 부분을 공부하고 프로젝트에 적용해야겠다고 생각한 이유</strong></h3>
<p>유튜브,네이버 등등 타 사이트의 경우, 느린 네트워크 환경에서도 <strong>뷰포인트의 일부분을 먼저 보여줌</strong>으로써 사용자에게 이 페이지가 멈추지 않음을 느끼게 해줌
일부분이 아직 로딩 스페너가 돌아가고 있고, 이미지,썸네일의 경우 스켈레톤 처리 되어 있어도, 헤더나 메뉴의 경우 클릭이 가능함
이렇게 사용자가 페이지가 멈추지 않았음을 느끼게 하는게 UX측면에서 굉장히 중요하다는 것을 깨달음</p>
<h3 id="ssr만을-사용했을때-문제점"><strong>SSR만을 사용했을때 문제점</strong></h3>
<p>상호작용 가능한 상태를 만들려면 모든것을 수화(Hydrate)해야함
즉, 수화가 시작된 후에는(컴포넌트 함수를 호출한 후에는) 전체 트리에 대해 이 작업이 완료될 때까지 React가 멈추지 않음. 그래서 모든 컴포넌트가 수화될때까지 기다려야함</p>
<p><strong>댓글기능에는 비용이 많이드는 렌더링 로직이 있다고 가정해보자.</strong> </p>
<p>내 컴퓨터에서는 빠르게 작동할 수 있지만, 저사양 기기에서는 그 로직을 실행하는데에 비용이 많이 들고, 화면이 멈출 수 있음. 물론 이런 기능은 Server Components를 사용하는 게 이상적임. 하지만 일부 로직은 이벤트 핸들러를 사용하는게 불가피해서 어쩔 수 없음. <strong>어쨋든, 수화가 시작되면 전체 트리가 수화될때까지 사용자는 네비게이션바, 헤더, 사이드바 등등과 상호작용할 수가 없음</strong>. 사용자는 사이드바나 네비게이션바와 상호작용하여(홈을 누른다던지, 다른 마이페이지로 이동한다던지) 이 페이지를 완전히 벗어나고 싶지만, 계속해서 수화가 일어나고 있어서 현재 페이지에 머물 수 밖에 없음</p>
<p><strong>결국 둘 중 선택해야함</strong>
댓글을 서버 출력에서 제외하여 사용자가 JS가 로드될때까지 댓글을 못보게 하거나, 
서버출력에 포함해서 댓글이 로드되고 전체 트리를 렌더링될때까지 다른 HTML과의 상호작용을 지연시키거나</p>
<p>이런 것들은** waterfall<strong>한 구조때문임
**데이터 패칭(서버)-&gt;HTML로 렌더링(서버)-&gt;코드 로드(클라이언트)-&gt; 수화(클라이언트)</strong>
앞 단계가 완료되기전까지 다음 단계를 실행할 수 없음</p>
<p>결국 해결책은 화면의 일부에 대해 각 단계를 수행할 수 있도록 작업을 분리하는 것임
React18부터 이게 가능한  &lt;<strong>Suspense</strong>&gt;가 정식 적용됨</p>
<h3 id="suspense-사용"><strong>Suspense 사용</strong></h3>
<p>댓글을 서스펜스로 감싼다</p>
<pre><code>&lt;Suspense fallback={&lt;Spinner /&gt;}&gt;
   &lt;Comments /&gt;
&lt;/Suspense&gt;</code></pre><p><code>&lt;Comments&gt;</code>를 <code>&lt;Suspense&gt;</code>로 래핑함으로써, React에게 댓글을 스트리밍하기 위해 기다릴 필요가 없다고 알림. 대신, React는 댓글 대신 플레이스홀더(스피너)를 보냄</p>
<p>초기 HTML에서 Comments는 빠지고 그자리를 spinner가 대체함
댓글에 대한 데이터가 준비되면 React는 추가 HTML을 동일한 스크림으로 보냄</p>
<p>그러면 React자체가 클라이언트에 로드되기 전에 댓글에 대한 HTML이 팝업됨</p>
<p>이제 문제 하나가 해결됨
<strong>화면의 일부가 초기 HTML을 지연시킬 경우 모든 HTML을 지연시키거나 HTML에서 제외할지 선택할 필요가 없게됨</strong></p>
<h4 id="hydrating-the-page-before-all-the-code-has-loaded"><strong>Hydrating the page before all the code has loaded</strong></h4>
<p>초기 HTML을 더 일찍 보낼 수 있지만, 댓글의 JavaScript코드가 로드될 떄까지 클라이언트에서 앱을 수화할 수 없음. 코드 크기가 크면 시간 많이걸림.
그래서 이런 대규모 번들을 피하기 위해 &#39;코드 분할&#39;을 사용해야함.</p>
<p><code>React.lazy</code>를 사용하여 기본 번들에서 Comments코드를 분리</p>
<p> 이렇게 React 18 <code>&lt;Suspense&gt;</code> 에서는 댓글 위젯이 로드되기 전에 앱을 하이드레이션할 수 있음</p>
<h3 id="결론">결론</h3>
<ul>
<li>HTML을 보내기 전에 더 이상 모든 데이터가 서버에 로드될 때까지 기다릴 필요가 없어짐</li>
<li>하이드레이션을 시작하기 위해 더 이상 모든 JavaScript가 로드될 때까지 기다릴 필요가 없음</li>
<li>더 이상 페이지와 상호작용하기 위해 모든 구성 요소가 하이드레이션 될때까지 기다릴 필요가 없음</li>
</ul>
<p>🫠
출처  : <a href="https://github.com/reactwg/react-18/discussions/37#top">https://github.com/reactwg/react-18/discussions/37#top</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] router.push와 router.replace]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-router.push%EC%99%80-router.replace</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-router.push%EC%99%80-router.replace</guid>
            <pubDate>Sat, 09 Dec 2023 12:33:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/85bb922f-4537-49db-932c-6645d6ddc132/image.png" alt=""></p>
<p>아무리 &#39;뒤로 가기&#39;버튼을 눌러도 <code>https://www.recordyslow.com/mypage?tab=로그인정보</code>에서 벗어나지지 않는 현상이 발생함</p>
<pre><code>  useEffect(() =&gt; {
    const { tab } = router.query;

    // URL 파라미터에 따라 활성 탭 설정
    if (tab === &quot;장바구니&quot;) {
      setActiveTab(&quot;장바구니&quot;);
    } else if (tab === &quot;로그인정보&quot;) {
      setActiveTab(&quot;로그인 정보&quot;);
    } else if (tab === &quot;기본배송지&quot;) {
      setActiveTab(&quot;기본 배송지&quot;);
    }

    // URL 파라미터가 없을 경우, &quot;로그인정보&quot; 탭으로 설정하고 URL에 파라미터를 추가
    if (!tab) {
      setActiveTab(&quot;로그인정보&quot;);
      router.replace(&quot;/mypage?tab=로그인정보&quot;);
    }
  }, [router.query]);</code></pre><p>이런식으로 <code>tab</code>을 선택하지 않은 상태(마이페이지 버튼을 눌렀을때)는 <strong>&#39;로그인 정보&#39;</strong> 탭으로 가게해놓음.
하지만, 이렇게 하니 뒤로 가기를 아무리 눌러도 <strong>&#39;로그인 정보&#39;</strong> 탭에서 벗어나지지가 않음.</p>
<p>해당 코드를</p>
<blockquote>
</blockquote>
<pre><code>router.replace(&quot;/mypage?tab=로그인정보&quot;);</code></pre><p>이렇게 변경했더니, 이전페이지로 잘 이동이 됨.</p>
<h2 id="routerpush-vs-routerreplace">router.push vs router.replace</h2>
<p>router.push와 router.replace의 주요 차이는 브라우저 히스토리에 새 항목을 추가하느냐 아니냐에 있음.</p>
<h3 id="routerpush">router.push</h3>
<blockquote>
<p>새로운 URL로 이동하면서 브라우저 히스토리에 새로운 항목을 추가함
뒤로가기 버튼을 누르면 이전에 방문한 페이지로 이동하게 됨
새로운 페이지로 이동한 흔적이 브라우저 히스토리에 남음</p>
</blockquote>
<p>-&gt; 보통 상황이면 잘 작동해야되는 것이지만, 해당 경우는 마이페이지 버튼을 눌러서 접근하기 때문에, 마이페이지 버튼을 누르면서 <strong>해당탭(&#39;로그인정보&#39;)</strong>이 이전 기록으로 push되어버리는 현상이 발생함. 그래서 아무리 뒤로가기 버튼을 눌러도 <strong>&#39;로그인 정보&#39;</strong> 탭이 이전 페이지가 되는 현상이 발생하는 거임</p>
<h3 id="routerreplace">router.replace</h3>
<blockquote>
<p>현재 페이지의 URL을 새로운 URL로 교체하면서 브라우저 히스토리에는 새 항목을 추가하지 않음
뒤로가기 버튼을 누르면 현재 페이지 전전의 페이지로 이동
새로운 페이지로 이동한 흔적이 브라우저 히스토리에 추가되지 않음</p>
</blockquote>
<p>설명이 애매할 수 있지만, 결론은 마이페이지 버튼을 통해 해당 탭을 강제로 &#39;로그인 정보&#39;로 지정하는 상황이기 때문에, <strong>router.push</strong>를 사용하면 이전 페이지가 <strong>&#39;로그인 정보&#39;</strong>로 history가 추가되어 뒤로가기 버튼을 눌러도 <strong>&#39;로그인 정보&#39;</strong> 탭에서 벗어나지지 않기 때문에, <strong>router.replace</strong>를 사용하여 대체하고 history에 <strong>&#39;로그인 정보&#39;</strong> 탭을 저장하지 않으면 됨.</p>
<p>.
.
.
끝</p>
<p>🫠</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Next.js_🫠 4]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-4</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-4</guid>
            <pubDate>Thu, 30 Nov 2023 06:49:25 GMT</pubDate>
            <description><![CDATA[<p>들어가기 전에...</p>
<p>지금까지 생겼던 의문들을 정리해보자</p>
<p><strong>Q1. SSR은 빌드시점에 데이터를 다 가져오는게 아닌데 어떻게 SEO 측면에 유리한 걸까?</strong></p>
<blockquote>
<p>SSR(서버 사이드 렌더링)은 각 요청마다 서버 측에서 데이터를 가져와 페이지를 렌더링함. 따라서 SSR은 빌드 시점에 데이터를 미리 가져오지 않음.
SSR은 <strong>초기 로딩 시</strong>에 완전한 HTML 페이지를 제공</p>
</blockquote>
<p><strong>Q2. CSR을 해도 결국 api를 요청하는건 서버에 요청하는거 아닌가? 이게 SSR과 정확히 뭐가 다른거지? SSR도 서버에 요청을하고 CSR도 서버에 요청하잖아</strong></p>
<blockquote>
<p>초기 로딩 시점에 <strong>데이터를 가져오는 위치</strong>가 서버인지 클라이언트인지가 두 방식의 주요한 차이점
<strong>CSR</strong>의 경우, 초기에는 빈 페이지가 로드되고, 이후 JavaScript가 실행되면서 데이터가 가져와지고 페이지가 업데이트됨.
반면에 <strong>SSR</strong>의 경우, 서버가 페이지를 렌더링하면서 필요한 데이터를 미리 가져와서 완전한 페이지를 제공함.</p>
</blockquote>
<p><strong>CSR:</strong>
사용자가 페이지에 접속
페이지는 초기에 빈 상태로 로드
클라이언트 측 JavaScript는 API를 호출하여 데이터를 가져옴
데이터가 성공적으로 불러와지면, 페이지는 해당 데이터를 사용하여 렌더링</p>
<p><strong>SSR:</strong>
사용자가 페이지에 접속
서버는 초기 요청에 대해 페이지를 렌더링하면서 API를 호출하여 데이터를 미리 가져옴
서버는 완전한 형태의 페이지를 사용자에게 제공, 페이지에는 미리 불러온 데이터가 포함되어있음.</p>
<p><strong>Q3. SSG,SSR,CSR 각각 API를 부르는 시점이 어떻게 될까?</strong></p>
<blockquote>
<p><strong>SSG-&gt;SSR-&gt;CSR</strong>
<strong>SSG</strong>은 빌드 시점에 데이터를 불러오므로, 사용자가 페이지에 접속했을 때 가장 빠르게 렌더링됨.
<strong>SSR</strong>은 각 요청마다 서버 측에서 데이터를 가져오므로, SSG보다는 느릴 수 있지만, CSR보다는 빠르게 페이지를 제공함.
<strong>CSR</strong>은 초기에는 빈 페이지가 로드되고, 이후에 클라이언트 측 JavaScript가 실행되면서 데이터를 가져옴.</p>
</blockquote>
<h3 id="✅-ssr-직접사용해보기">✅ SSR 직접사용해보기</h3>
<p>SHOP화면 카테고리 데이터, 제품 데이터를 불러올때 SSR,SSG 중 선택을 해야함.</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/ed99a3f6-47b2-427e-9792-d6d8b9c07899/image.png" alt=""></p>
<p>관리자가가 제품 데이터 하나를 추가했을 경우, 사용자가 내가 추가한 그 제품 데이터를 볼 수 있으려면....</p>
<ul>
<li><p><strong>SSG를 사용할 경우</strong>
<code>getStaticProps</code>에서 <code>revalidate</code> 옵션을 사용해야 함. <code>revalidate</code>을 사용하지 않으면, 정적 생성된 페이지는 빌드된 이후에만 업데이트되며, 새로운 데이터를 반영하려면 명시적으로 개발자가 빌드를 다시 실행해야함.</p>
</li>
<li><p><em>revalidate의 경우 페이지 내용이 변경되었을 때만 새로운 데이터를 가져와서 페이지를 갱신함. 데이터가 변경되지 않았다면 이전에 생성된 정적 페이지를 계속 사용함.*</em></p>
</li>
<li><p><strong>SSR을 사용할 경우</strong>
새로운 데이터를 요청 시에 동적으로 가져와서 페이지를 렌더링할 수 있음.
데이터 업데이트 시에 빌드를 다시 실행할 필요가 없음.</p>
</li>
</ul>
<p><strong>SSR 구현 예시</strong></p>
<pre><code>export async function getServerSideProps() {
  const queryClient = new QueryClient();

  const productQuery = await queryClient.prefetchQuery(
    [QUERYKEYS.LOAD_PRODUCT],
    loadMarketProduct,
  );

  const categoryQuery = queryClient.prefetchQuery(
    [QUERYKEYS.ADMIN_GET_CATEGORY],
    adminGetCategory,
  );

  await Promise.all([productQuery, categoryQuery]);

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}</code></pre><pre><code>  const queryClient = useQueryClient();

  const productData = queryClient.getQueryData([QUERYKEYS.LOAD_PRODUCT]) as {
    data: {
      content: Array&lt;any&gt;;
    };
  };

  const categoryData = queryClient.getQueryData([
    QUERYKEYS.ADMIN_GET_CATEGORY,
  ]) as { data: Array&lt;any&gt; };</code></pre><p>getServerSideProps 함수를 사용하여 서버 측에서 데이터를 가져오고, 그 데이터를 클라이언트로 전달
클라이언트 측에서는 useQueryClient 훅을 사용하여 동일한 쿼리 클라이언트에 접근하고, 이전에 불러온 데이터를 가져옴</p>
<p><strong>이 글을 작성할때까지만 해도 SSR로 구현하려고 했지만, SSG를 사용하기로 결정</strong></p>
<blockquote>
<p>이유 : 관리자는 새로운 제품 데이터는 일주일에 한번 업데이트하고, 카테고리 데이터의 경우는 거의 잘 변하지 않음. 이럴 경우 SSG를 하는게 효율적임.</p>
</blockquote>
<p><strong>SSG 구현</strong></p>
<pre><code>export async function getStaticProps() {
  const queryClient = new QueryClient();

  // Prefetch queries
  await queryClient.prefetchQuery([QUERYKEYS.LOAD_PRODUCT], loadMarketProduct);
  await queryClient.prefetchQuery(
    [QUERYKEYS.ADMIN_GET_CATEGORY],
    adminGetCategory,
  );

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
    revalidate: 10,
  };
}</code></pre><p>아래는 SSR과 동일</p>
<p>끝!...</p>
<p>🫠</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Next.js_🫠 3]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-3</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-3</guid>
            <pubDate>Tue, 07 Nov 2023 12:05:50 GMT</pubDate>
            <description><![CDATA[<h2 id="react-query--nextjs">React-Query + Next.js</h2>
<p>이번 프로젝트는 리엑트 쿼리와 넥스트를 같이 사용하기 때문에 리엑트쿼리 공식문서를 참고했다.</p>
<h3 id="✅-ssr-ssg">✅ SSR, SSG</h3>
<p>react-query는 SSR을 위해 <strong>두 가지 방법</strong>의 데이터 프리패칭을 지원함
서버에서 데이터를 가져와 queryClient에 전달함</p>
<p>🤙 <strong>방법 1 : 데이터를 직접 프리패치하여 initialData로 전달하는 방법</strong></p>
<p><strong>getStaticProps</strong> 나 <strong>getServerSideProps</strong> 에서 원하는 API 를 요청하고 그에 대한 응답을 page 에 props 로 내려주고 그 값을 react-query 에 <strong>initialData</strong> 로 넣어주는 방법</p>
<pre><code>export async function getStaticProps() {
  const posts = await getPosts()
  return { props: { posts } }
}

function Posts(props) {
  const { data } = useQuery({
    queryKey: [&#39;posts&#39;],
    queryFn: getPosts,
    initialData: props.posts,
  })

  // ...
}</code></pre><p>getStaticProps함수로 서버 측에서 Post데이터를 가져옴. 이 데이터는 popsts라는 키 값으로 props에 전달됨. 그 다음 Posts컴포넌트에서 useQuery를 사용하여 posts데이터를 가져오고 초기데이터로 props.posts를 사용하도록 설정</p>
<p>주의점</p>
<ol>
<li>트리 내 더 깊은 컴포넌트에서 useQuery로 데이터를 호출하는 경우 initialData를 그 깊은 곳까지 전달해야됨</li>
<li>동일한 쿼리를 여러 위치에서 useQuery를 호출할 경우 모든 위치에 initialData를 전달해야됨</li>
<li>서버에서 쿼리가 언제 가져와졌는지 판단 불가능</li>
</ol>
<p>🤙 <strong>방법 2 : Hydration</strong></p>
<p>getStaticProps or getServerSideProps에서 prefetch를 통해 데이터 요청
해당 캐시를 dehydrate해서 클라이언트에서 그 데이터를 rehydrate함</p>
<p>여러 쿼리를 사전에 가져와 해당 쿼리들을 queryClient에 저장하는 기능을 지원함. 이는 서버가 페이지를 로드할 때 미리 해당 데이터를 가져와서 마크업에 포함시킬 수 있음을 의미함. 
그리고 이 데이터는 JS가 사용가능해지면 React-query가 이를 다시 가져와 클라이언트에서 해당 쿼리를 업그레이드하거나 Hydration 할 수 있음을 의미함. 이러한 과정에는 서버에서 렌더링된 이후 해당 쿼리가 만료된 경우, 클라이언트가 해당 쿼리를 다시 가져와 새로 고침하는 기능도 포함되어있음.</p>
<h3 id="✅-usequery-vs-asynctrycatch">✅ useQuery vs Async,try/catch</h3>
<p>난 당연히 더 나은 방법인 <strong>Hydration</strong> 방법을 택하기로 했다.</p>
<p>그리고 문득 당연하듯이 쓰던 <code>reat-query</code>의 <code>캐시</code> 기능이 정말 작동을 하는지 궁금해졌다</p>
<p>첫번째 방법은 <strong>일반적인 방식</strong>으로 데이터를 가져와봤고, 두번째에는 <strong>useQuery</strong>를 이용해서 데이터를 불러와봤다.</p>
<pre><code>느린3G 환경에서 동일하게 실험 진행</code></pre><h4 id="🤙-방법-1--일반적인-방식">🤙 방법 1 : 일반적인 방식</h4>
<pre><code>  const getMe = async () =&gt; {
    try {
      const data = await loadMe();
      setData(data);
    } catch (err) {
      console.log(err);
    }
  };
</code></pre><p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/df452c06-b7e3-45b3-ac3f-508b33eb39a6/image.png" alt=""></p>
<p>캐시를 사용하지 않아 데이터를 불러오는 동안 화면에는 데이터를 띄우지 못함</p>
<h4 id="🤙-방법-2--usequery">🤙 방법 2 : useQuery</h4>
<pre><code>const { data } = useQuery([QUERYKEYS.LOAD_ME], loadMe);
</code></pre><p>느린 3G환경임에도 캐시를 사용하기 때문에 페이지 전환 간에 데이터가 사라지지 않음.</p>
<p>잘 적용이 되는 듯 😊 </p>
<h3 id="✅-ssg-직접사용해보기">✅ SSG 직접사용해보기</h3>
<p>SSG라는건 빌드 시점에 서버에서 해당 API를 불러오는 것이기때문에, 개발환경에서 <code>npm run build</code>, <code>npm run export</code>를 하고 생성된 <code>/out</code> 파일에서 해당 컴포넌트 <code>index.html</code>을 실행했을때 <strong>해당 API를 통해 불러온 데이터</strong>가 나와야함.</p>
<p>먼저 getStaticProps를 사용하지 않고 <strong>그냥 데이터를 불렀을때</strong> <code>index.html</code>을 확인해보자</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/77280c08-f442-46af-961e-bafdd39b3a31/image.png" alt=""></p>
<p><strong>getStaticProps를 사용하여 데이터를 가져온 경우</strong> <code>index.html</code>을 확인해보자</p>
<pre><code>export async function getStaticProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery([QUERYKEYS.LOAD_PRODUCT], () =&gt;
    loadMarketProductPaging({ size: 4, visible: true }),
  );

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}</code></pre><p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/a0237558-c390-4e4c-90e4-70e2abbd2478/image.png" alt=""></p>
<p>*<em>데이터가 성공적으로 빌드시점에 넘어온 것을 확인해볼 수 있다!!!!!!
*</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Next.js_🫠 2]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-2</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-2</guid>
            <pubDate>Mon, 06 Nov 2023 14:22:26 GMT</pubDate>
            <description><![CDATA[<h2 id="nextjs는-어떻게-동작하는가">Next.js는 어떻게 동작하는가</h2>
<blockquote>
<p>내장된 <code>코드분할</code> 기능을 통해 동작. <code>/page</code> 디렉토리 내의 각 파일은 빌드 단계에서 자체 자바스크립트 번들로 자동분할됨</p>
</blockquote>
<p><strong>이게 무슨말이냐면...</strong></p>
<ul>
<li>Next.js에서 페이지는 <code>/page</code> 디렉토리에 위치함. 이 디렉토리 내의 각 파일은 해당 페이지에 대한 기능과 로직을 포함함.</li>
<li><code>/page</code>디렉토리 내부에 <code>/login</code>,<code>/shop</code>과 같은 파일이 있고, 이 파일들은 각각 개별적으로 자체 자바스크립트 번들로 빌드되고, 이것들은 그 페이지가 필요할때만 개별적으로 로드가 됨.</li>
</ul>
<p><strong>이게 뭐가 좋냐면...</strong></p>
<ul>
<li>이렇게 되면 사용자가 특정 페이지로 이동할 때 해당 페이지에 대한 자바스크립트 코드만 로드가 되므로, 애플리케이션의 초기 로딩 속도가 향상됨.</li>
<li>각 페이지가 독립적으로 번들링되므로 코드의 유지보수와 관리가 용이해짐. (로그인 페이지에서 오류가 발생해도 shop페이지는 성공적으로 로드가 가능해진다는 말)</li>
</ul>
<p><strong>프로젝트에 Next.js를 적용하려는 이유</strong></p>
<blockquote>
<p>쇼핑몰 프로젝트이므로, 보다 강력한 SEO 기능이 필요했음</p>
</blockquote>
<h2 id="이를-위한-이점으로-사용할-nextjs의-기능">이를 위한 이점으로 사용할 Next.js의 기능</h2>
<h3 id="✅-route-preloading">✅ Route preloading</h3>
<p><code>예시코드</code></p>
<pre><code>import Link from &#39;next/link&#39;;
export default function Navigation() {
  return (
    &lt;nav&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;Link href=&quot;/about&quot;&gt;
            &lt;a&gt;About&lt;/a&gt;
          &lt;/Link&gt;
        &lt;/li&gt;
        &lt;li&gt;
          &lt;Link href=&quot;/contact&quot;&gt;
            &lt;a&gt;Contact&lt;/a&gt;
          &lt;/Link&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/nav&gt;
  );
}
</code></pre><p>About, Contact 링크위에 마우스를 올리면 Next.js는 자동으로 <code>/about</code>, <code>/contact</code> 페이지의 자바스크립트 번들을 프리로드하기 시작함.</p>
<p><strong>필요하지 않은 리소스를 로드하여 성능에 부정적인 영향을 끼치진 않을까?</strong></p>
<blockquote>
<p>Next.js가 페이지를 프리로드하는 시점은 링크가 뷰포트에 나타날때임 + 브라우저가 유휴 상태일 때까지 기다림
-&gt; 성능 저하 X, 사용자에게 더 부드러운 네비게이션 경험 제공</p>
</blockquote>
<h3 id="✅-서버-측-렌더링ssr">✅ 서버 측 렌더링(SSR)</h3>
<p>SSR은 웹 페이지를 브라우저에 표시하기 전에 서버에서 렌더링하는 방식을 말함. 사용자가 페이지에 처음 접근할 때 서버가 해당 페이지의 내용을 HTML로 렌더링하여 브라우저에 보내주는 것을 말함.</p>
<p><code>예시</code> : 사용자가 블로그 포스트 목록이 잇는 페이지에 접속한다고 가정. 이 페이지는 최신 블로그 포스트 목록을 보여줘야 함.</p>
<p><strong>SSR을 사용하는 경우</strong>, 서버는 사용자 요청에 따라 최신 블로그 포스트 데이터를 가져와 HTML로 렌더링한 후 이를 브라우저에 전송
<strong>CSR을 사용하는 경우</strong>, 서버는 초기 요청에 대해 빈 HTML페이지를 제공함. 그 다음 클라이언트는 이 HTML을 받고 JS를 사용하여 데이터를 가져와 페이지를 렌더링함. -&gt; 사용자는 초기 로딩시간동안 로딩 상태를 봐야함, 페이지가 완전히 로드된 후에야 상호작용 가능</p>
<p>생성된 HTML페이지는 클라이언트에 의해 수화(hydration)과정을 통해 상호작용 가능한 페이지로 변환됨
<code>Hydration이란?</code> : 클라이언트 측의 Js코드가 서버에서 받은 정적인 HTML페이지를 가져와 동적으로 변환하는 과정을 말함.</p>
<p><strong>그래서 SSR을 하면 SEO에 유리한 이유가 뭔데</strong></p>
<ul>
<li><strong>CSR을 하는 경우</strong>, 초기에 빈 HTML이 로드돼서, 검색 엔진은 초기에 페이지의 완전한 콘텐츠 파악이 어려워 검색 가능성 떨어짐</li>
<li><strong>SSR을 하는 경우</strong>, 초기에 완전한 HTML을 생성하므로, 검색 엔진은 페이지의 콘텐츠와 구조를 쉽게 이해하고, 검색 결과에 해당 페이지를 적절하게 표시할 수 있게 도와줌</li>
</ul>
<h3 id="✅-정적-사이트-생성ssg">✅ 정적 사이트 생성(SSG)</h3>
<p>SSG에서는 페이지가 빌드 시간에 생성되고 각 요청에 재사용됨. 서버가 사전 렌더링된 HTML 페이지를 제공할 수 있으며, 이는 캐싱되어 사용자에게 즉시 제공될 수 있음.</p>
<p><code>예시</code> : 한국의 전통 문화에 관한 정적인 정보를 제공하는 웹 사이트
이 경우 변경 빈도가 낮고 대부분의 콘텐츠가 정적인 경우가 많음. 따라서 개발자는 미리 해당 페이지를 빌드하여 정적 HTML페이지를 생성한 뒤, 여러 사용자에게 재사용함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로젝트] Next.js_🫠 1]]></title>
            <link>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-1</link>
            <guid>https://velog.io/@miin-hyukkk/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Next.js-1</guid>
            <pubDate>Mon, 06 Nov 2023 12:30:59 GMT</pubDate>
            <description><![CDATA[<h2 id="nextjs란">Next.js란?</h2>
<p>React를 이용한 웹 에플리케이션을 만들기 위한 framewrok</p>
<p><strong>React</strong> : ‘A JavaScript <code>library</code> for building user interfaces’ 
<strong>Angular</strong> : &#39;Angular is an application-design <code>framework</code> and development <code>platform</code> for creating efficient and sophisticated single-page apps.&#39;</p>
<ol>
<li><p>React는 경량화된 UI 라이브러리이며, 개발자가 필요한 다른 라이브러리와 함께 사용하여 원하는 방식으로 애플리케이션을 구축할 수 있는 유연성을 제공</p>
</li>
<li><p>그러나 프로젝트가 커지고 엔터프라이즈 환경으로 발전함에 따라 특정한 도구와 구조의 필요성이 더욱 중요해짐</p>
</li>
<li><p>이때, React를 보다 구조화된 형태로 제공하고 다양한 문제들을 해결하기 위해 Next.js와 같은 프레임워크가 도입됨</p>
</li>
<li><p>Next.js는 React 애플리케이션을 구축할 때 발생할 수 있는 다양한 문제들을 해결하고, 프로젝트를 보다 쉽게 구축하고 유지보수할 수 있도록 도와. 또한, React 생태계의 다양한 라이브러리와의 호환성 문제를 완화하고, 최신의 Best Practice와 구조를 제공하여 개발자들이 보다 효율적으로 애플리케이션을 개발할 수 있도록 도와줌</p>
</li>
</ol>
<blockquote>
<ul>
<li><strong>Next.js는 React 생태계에서 발생하는 문제를 해결하고, 보다 구조화된 방식으로 애플리케이션을 개발할 수 있도록 도와주는 강력한 도구라고 할 수 있음.</strong></li>
</ul>
</blockquote>
<ul>
<li><strong>Next.js는 단순히 서버 사이드 렌더링(SSR)만을 제공하는 것이 아니라, React 애플리케이션을 보다 구조화된 형태로 제공하고 다양한 문제들을 해결하기 위한 다양한 기능을 제공</strong></li>
</ul>
<p>결국 포인트는 SSR만을 위해서 Next.js가 존재하는게 아니란걸 알고 써야한다는거임. Next.js에서 제공하는 기능 중 하나가 SSR인거일뿐.</p>
<p><a href="https://json.media/blog/ko/proper-understading-of-nextjs">참고한 블로그</a>의 내용에 의하면 기존에 리엑트를 하며 겪었던 고통들이 많이 해결될 것이라고 하니... 사용해보면서 몸소 느껴보자</p>
<p><strong>React</strong> : 기본적으로 사용자 인터페이스를 구축하기 위한 라이브러리
<strong>Next.js</strong> : React 애플리케이션을 위한 구조를 제공하는 완전한 프레임워크</p>
<p><img src="https://velog.velcdn.com/images/miin-hyukkk/post/c70b6d67-d87a-4fe5-89ca-4b454f49021a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조] 질문 모음]]></title>
            <link>https://velog.io/@miin-hyukkk/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%A7%88%EB%AC%B8-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@miin-hyukkk/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%A7%88%EB%AC%B8-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Tue, 26 Sep 2023 06:29:44 GMT</pubDate>
            <description><![CDATA[<p><strong>자료구조와 알고리즘에 대해 설명해주세요.</strong></p>
<blockquote>
<p>자료구조는 데이터를 원하는 규칙 또는 목적에 맞게 저장하기 위한 구조입니다. 알고리즘은 자료구조에 쌓인 데이터를 활용해 어떠한 문제를 해결하기 위한 여러 동작들의 모임입니다.</p>
</blockquote>
<p><strong>시간복잡도와 공간복잡도에 대해서 설명해주세요.</strong></p>
<blockquote>
<p>좋은 알고리즘이란 작은 메모리 공간을 차지하면서 적은시간 내에 주어진 임무를 수행하는 알고리즘입니다. 이렇게 알고리즘이 좋은 알고리즘인지 판단하는데에 있어서 수행시간과 메모리 사용량을 평가 기준으로 둡니다. 이 각각이 시간복잡도와 공간복잡도입니다.</p>
</blockquote>
<p><strong>선형 자로구조와 비선형 자료구조에 대해서 설명해주시고, 각각 어떤 자료구조가 이에 해당하는 지 설명해보세요</strong></p>
<blockquote>
<p>선형 구조는 한 원소 뒤에 하나의 원소만이 존재하는 형태를 말합니다. 자료들이 선형으로 나열되어 있습니다.어레이나 링크드리스트, 스택,큐 자료구조가 이에 해당합니다.
비선형 구조는 원소 간 다대다 관계를 가지는 구조로 계층적 구조나 망형 구조를 표현하기에 적절합니다. 그래프나 트리 자료구조가 이에 해당합니다.</p>
</blockquote>
<p><strong>배열이 무엇인지 설명해보세요</strong></p>
<blockquote>
<p>배열은 연속된 메모리 공간에 순차적으로 저장된 데이터 모음입니다.</p>
</blockquote>
<p><strong>Array를 적용시키면 좋을 데이터의 예를 구체적으로 들어주세요. 구체적 예시와 함께 Array를 적용하면 좋은 이유, 그리고 Array를 사용하지 않으면 어떻게 되는지 함께 설명해주세요.</strong></p>
<blockquote>
<p>주식 차트를 예로 들을 수 있습니다. 데이터가 새롭게 추가되고 삭제되는 정보가 아니고 날짜별로 주식 가격이 차례대로 저장이 되는 데이터이기 때문입니다. 배열을 사용하지 않고 순서가 없는 자료구조를 사용하게 되면 주식 차트에서 주로 이루어지는 탐색 작업을 할때 많은 시간이 소요되어 굉장히 비효율적일 것이라고 생각합니다.</p>
</blockquote>
<p><strong>Array와 ArrayList의 차이점에 대해 설명해주세요.</strong></p>
<blockquote>
<p>array는 크기가 고정적이고 arraylist는 크기가 가변적입니다. array는 초기화 시 메모리에 할당되어 arraylist보다 속도가 빠르다는 특징이 있습니다.</p>
</blockquote>
<p><strong>Array의 가장 큰 특징과 그로 인해 발생하는 장단점을 설명해보세요.</strong></p>
<blockquote>
<p>배열의 가장 큰 특징은 순차적으로 데이터를 저장한다는 점입니다. 데이터에 순서가 있기 때문에 0부터 시작하는 index가 존재하고 그 인덱스를 사용해 특정 요소를 찾고 조작이 가능하다는 것이 배열의 장점입니다. 반면 단점으로는 중간에 요소가 삽입되거나 삭제되어야 하는 경우 그 뒤의 모든 요소들이 한칸식 뒤로 밀리거나 당겨줘야한다는 점입니다. 그리하여 추가와 삭제가 반복되는 경우보다는 탐색이 많은 경우에 배열을 사용하는게 좋습니다.</p>
</blockquote>
<p><strong>Array와 Linked list의 차이점은 무엇인가요?</strong></p>
<blockquote>
<p>둘의 차이점은 크게 세가지 관점에서 볼 수 있습니다. 특정 요소에 접근할 때, 요소를 삽입하거나 삭제할때 그리고 메모리 할당 시에 차이점을 보입니다. 특정요소에 접근할때 배열의 경우 직접 접근하기 때문에 시간복잡도가 O(1)인 반면 링크드 리스트는 순차적으로 검색하며 접근해야되어서 O(n)이 소요됩니다. 삽입,삭제의 경우 배열은 O(n), 링크드 리스트의 경우는 O(1)이 소요됩니다. 마지막으로 메모리 할당 시 배열에서 메모리는 선언 시 컴파일 타임에 할당되고 stack영역에 할당이 이루어지는 반면, 링크드 리스트는 새로운 요소 추가될 때 런타임에 메모리를 할당하고, 힙영역에 할당이 이루어집니다.</p>
</blockquote>
<p><strong>스택과 큐의 차이점은 무엇인가요?</strong></p>
<blockquote>
<p>스택은 먼저 넣은 자료가 마지막에 나오는 구조입니다. 리스트로 구현하면 객체를 제거하는 작업이 필요하지만 배열로 구현하면 index를 줄이고 초기화만 하면되므로, 배열로 구현하는게 좋습니다. 주로 DFS나 재귀에 사용됩니다. 큐는 먼저 들어간 자료가 먼저 나오는 구조입니다. 배열로 구현하면 shift할때 고려해야돼서 연결리스트로 구현하는게 좋습니다. 데이터가 입력시간 순서대로 처리되어야 하는 경우에 사용됩니다. 주로 BFS나 캐시에 사용됩니다.</p>
</blockquote>
<p><strong>스택과 큐의 실사용 예를 들어 간단히 설명해주세요.</strong></p>
<blockquote>
<p>스택은 자바의 스택 메모리 영여에 사용됩니다. 지역변수와 매개변수 데이터 값이 저장되는 공간이고, 메소드 호출 시 메모리에 푸쉬하고 종료되면 pop해서 삭제합니다. 큐는 자원의 할당과 회수를 하는 스캐쥴러 역할을 하는 OS의 스케쥴러에서 쓰입니다.</p>
</blockquote>
<p><strong>트리에 대해 설명해주세요</strong></p>
<blockquote>
<p>비선형 자료구조로 계층적 관계를 표현하는 자료구조입니다. 값을 가진 노드와 그 노드들을 연결해주는 간선으로 이루어져있습니다. 특징으로는 정점이 N개인 트린 반드시 N-1개의 간선을 가져야합니다.</p>
</blockquote>
<p><strong>그래프와 트리의 차이점이 무엇인가요?</strong></p>
<blockquote>
<p>둘 다 노드와 간선으로 구성된 자료 구조이지만, 사이클 여부, 루트 정의 여부, 간선이 단방향이냐 양방향이냐, 부모 자식관계, 레벨과 깊이의 개념 유무 등등에서 차이를 보입니다. 트리를 그래패의 특수한 형태라고 생각하시면 될 것 같습니다.</p>
</blockquote>
<p><strong>이진트리와 이진탐색트리에 대해 설명해주세요.</strong></p>
<blockquote>
<p>이진트리는 각 정점이 최대 2개의 자식을 가지는 트리로, 루트 노드를 중심으로 두개의 서브 트리로 나뉩니다.
종류로는 완전 이진 트리, 포화 이진 트리 , 편향 이진 트리가 있습니다. 이진탐색트리는 이진 탐색과 연결 리스트를 결합한 자료구조입니다. 왼쪽 트리의 모든 값은 부모 노드보다 작고, 오른쪽은 모두 부모 노드보다 크다는 특징을 가집니다. 탐색, 삽입, 삭제의 시간 복잡도는 높이의 영향을 받아 O(h)입니다.</p>
</blockquote>
<p><strong>이진탐색트리의 한계점에 대해 설명해보세요.</strong></p>
<blockquote>
<p>트리 모양이 한쪽으로 치우친 편향 트리 구조가 되면 트리 탐색의 장점인 O(logN) 시간복잡도가 O(N)에 가까워집니다. 배열보다 많은 메모리를 사용하여 데이터를 저장했는데 탐색에 필요한 시간복잡도가 베열과 같아져버려서 비효율적이게 됩니다. 그래서 이런 편향트리가 되지 않게 해주는 rebalancing 기법을 써서 BBST를 구현해야합니다.</p>
</blockquote>
<p><strong>Balanced Binary Search Tree와 그 종류에 대해 설명해주세요.</strong></p>
<blockquote>
<p>편향 트리가 되지 않게 rebalancing기법을 사용하여 균형잡힌 이진 탐색 트리를 구현한 것이 bbst입니다. 
red-black tree와 avl 트리가 대표적인 bbst입니다.</p>
</blockquote>
<p><strong>Red-Black-Tree에 대해 설명해주세요</strong></p>
<blockquote>
<p>BST를 기반으로 하는 트리 형식의 자료구조이며, 탐색, 삽입, 삭제에 O(logN)의 시간복잡도가 소요됨.
동일한 노드의 개수일 때, depth를 최소화하여 시간 복잡도를 줄이는 것이 핵심 아이디어임
BST의 특성을 유지하며 삽입,삭제를 진행하며, Java Collection의 ArrayList 그리고 HashMap에서도 쓸정도로 효율이 좋고 중요한 자료구조임</p>
</blockquote>
<p><strong>힙에 대해서 설명해보세요</strong></p>
<blockquote>
<p>힙은 완전 이진 트리의 일종으로 반정렬 상태를 유지하여 최대값이나 최소값을 빠르게 반환할 수 있는 자료구조입니다. 루트가 가장 큰 값이 되는 최대 힙과 루트가 가장 작은 값이 되는 최소 힙이 있습니다. 주로 우선순위 큐를 구현하기 위해 사용됩니다.</p>
</blockquote>
<p><strong>힙의 삽입,삭제 방식에 대해 설명하고, 왜 이진탐색트리와 달리 편향이 발생하지 않는지 설명해주세요.</strong></p>
<blockquote>
<p>삽입은 맨 마지막 자리에 요소를 삽입 후 힙의 속성에 맞을 때까지 부모,자식간의 교환을 진행합니다. 마찬가지로 삭제도 이루어진 후 힙의 속성에 맞을 때까지 부모, 자식간의 교환을 진행합니다. 
이진탐색트리와 달리 편향이 발생하지 않는 이유는 데이터를 삽입하고 삭제할때 특별한 규칙에 따라 트리를 조정하기 때문입니다.</p>
</blockquote>
<p><strong>PriorityQueue에 대해 설명해주세요.</strong></p>
<blockquote>
<p>우선순위 큐는 들어간 순서에 상관없이 우선순위가 높은 데이터를 먼저 꺼내기 위해 고안된 자료구조입니다. 우선순위 큐를 구현할 떄 배열, 링크드 리스트, 힙을 사용할 수 있지만 그 중 힙 방식이 O(logN)을 보장하기 때문에 일반적으로 완전 이진 트리 형태의 힙을 이용해 구현합니다.</p>
</blockquote>
<p><strong>힙 정렬의 시간복잡도는 어떻게 되나요? Stable 한가요?</strong></p>
<blockquote>
<p>데이터를 힙으로 구성하는데 O(n)이 소요되고, 힙을 재조정하는 작업을 반복해야해서 O(nlogn)시간이 소요됨
stable한지 안한지는 동일한 값들의 상대적인 순서가 정렬 전후에도 유지되냐안되냐를 말하는데, 힙정렬은 보다시피 원래 배열의순서를 무시하고 힙을 구성하기 때문에 , Stable하다고 할 수 없음</p>
</blockquote>
<p><strong>Hash 자료구조에 대해 설명해주세요.</strong></p>
<blockquote>
<p>데이터를 효율적으로 관리하기 위해, 임의의 길이 데이터를 고정된 길이의 데이터로 매핑하는 것입니다. 그래서 데이터가 많아지면 다른 데이터가 같은 해시 값으로 충돌나는 현상이 발생합니다.</p>
</blockquote>
<p><strong>해시값이 충돌했을 때, 어떤 방식으로 처리할 수 있을까요?</strong></p>
<blockquote>
<p>크게 두가지 방법이 있습니다. 체이닝과 개방주서법입니다. 체이닝은 연결리스트로 중복된 값을 제거하는 방법입니다. 그리고 개방주소법은 충돌이 발생한 경우, 다른 빈 슬롯을 찾아 데이터를 저장하는 방법입니다. 선형 탐사, 제곱 탐사, 더블 해싱 등의 방법이 있습니다. 주로 구현이 간단한 체이닝 방법을 많이 사용합니다.</p>
</blockquote>
<p><strong>해시 맵과 해시테이블의 차이점에 대해 설명해주세요.</strong></p>
<blockquote>
<p>동기화 지원 여부와 null값 허용 여부에서 차이를 보입니다. 자원의 동기화를 고려햐아 하는 상황이라면 해시 테이블을 사용해야 하며, 해시테이블은 널값을 허용하지 않습니다. 반면 해시 맵의 경우는 병렬처리를 하지않고 동기화도 고려하지 않는 경우에 사용합니다. null값을 허용하며 thread-safe하지 않습니다.</p>
</blockquote>
<p><strong>B-tree와 B+Tree를 비교하여 설명해주세요.</strong></p>
<blockquote>
<p>B-tree는 이진 트리를 확장해서 더 많은 수의 자식을 가질 수 있게 일반화 시킨 것입니다. B+트리는 B트리의 변형 구조로 인덱스 역할만 하는 비단말 노드가 추가로 있습니다. b+트리의 경우 모든 키가    리프노드에 있어서 검색이 빠르고 정확하며, 삭제 또한 b-tree보다 쉽습니다.</p>
</blockquote>
<p><strong>Trie에 대해 설명해주세요</strong></p>
<blockquote>
<p>트라이는 문자열을 저장하고 효율적으로 탐색하기 위한 트리 형태의 자료구조입니다.</p>
</blockquote>
<p><strong>그래프 자료구조에 대해 설명해보세요</strong></p>
<blockquote>
<p>그래프는 정점과 간선으로 이루어진 자료구조입니다. 사실 트리도 그래프의 일종인데 그래프는 트리와 달리 정점마다 간선이 존재하지 않을 수 있으며, 루트노드, 부모,자식 노드개념이 존재하지 않습니다.</p>
</blockquote>
<p><strong>그래프를 구현할 수 있는 두 방법에 대해서 설명해주세요</strong></p>
<blockquote>
<p>인접행렬과 인접리스트가 있습니다. 인접행렬은 메모리가 많이 드는 대신 탐색이 빠릅니다. 간선이 많을때 주로 사용합니다 인접리스트는 메모리는 많이 들지 않지만 탐색이 느립니다.</p>
</blockquote>
<p><strong>정점의 개수가 N개, 간선의 개수가 N^3개라면, 어떤 방식으로 구현하는게 효율적일까요?</strong></p>
<blockquote>
<p>간선의 개수가 많은 경우는 매우 밀집된 그래프입니다. 이렇게 밀집된 그래프일 경우 일반적으로 연결 리스트로 구현하는게 더 효율적입니다. 연결리스트는 공간효율성과 간선 추가 및 삭제에 있어서 효율적이기 때문입니다.</p>
</blockquote>
<p><strong>사이클이 없는 그래프는 모두 트리인가요? 아니라면 예시를 들어주세요</strong></p>
<blockquote>
<p>그래프가 되려면 사이클이 없는 것 뿐더러, 간선의 방향성이 존재해야합니다. 사이클은 없지만, 간선의 방향성이 존재하지 않는 그래프는 트리가 아닙니다.</p>
</blockquote>
<p><strong>그래프에서 최단거리를 구하는 방법에 대해 설명해주세요</strong></p>
<blockquote>
<p>그래프에서 최단거리 알고리즘으로는 다익스트라 알고리즘, 벨만-포드 알고리즘, BFS 등이 있습니다. bFS는 가중치가 모두 없거나 모두 같은 경우, 다익스트라나 밸만포드 알고리즘의 경우는 가중치가 있는 그래프에서 최단거리를 구할때 용이합니다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] 질문모음]]></title>
            <link>https://velog.io/@miin-hyukkk/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%A7%88%EB%AC%B8%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@miin-hyukkk/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%A7%88%EB%AC%B8%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Tue, 19 Sep 2023 06:49:31 GMT</pubDate>
            <description><![CDATA[<p><strong>OSI 7계층에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>국제 표준화 기구에서 정의한 표준으로 컴퓨터 네트워크에서 데이터 통신의 과정을 일곱 개의 계층으로 나눈 개념 모델입니다. 각각의 계층은 특정한 기능을 수행하고, 데이터 흐름을 조정하며, 통신에 필요한 서비스를 제공합니다. 7계층은 최하위부터 최상위 계층까지 물리 계층, 데이터 링크 계층, 네트워크 계층, 전송 계층, 세션 계층, 표현 계층, 응용 계층으로 이루어져있습니다.</p>
</blockquote>
<p><strong>OSI를 7계층으로 나눈 이유가 뭔가요?</strong></p>
<blockquote>
<p>OSI를 7계층으로 나눔으로써 새로운 기술이나 서비스가 새로 도입되었을때 유연성과 확장성을 제공합니다. 새로운 기능이나 서비스는 해당하는 계층에 추가가 되고, 기존 계층의 수정 없이 독립적으로 구현이 가능하게 됩니다.</p>
</blockquote>
<p><strong>OSI 7계층의 각 계층에 대해 아는대로 설명해주세요</strong></p>
<blockquote>
<p>최하위 계층인 물리 계층부터 최상위 계층인 응용 계층 순서로 설명드리겠습니다. 물리 계층은 7계층 중 최하위 계층으로 데이터를 전기 신호로 바꿔주는 역할을 하며, 데이터의 단위는 비트입니다. 다음 데이터링크 계층은 데이터의 물리적인 전송과 흐름 제어를 담당하고 있으며, 데이터의 단위는 프레임입니다. 다음 네트워크 계층은 패킷의 경로 선택 및 라우팅을 담당합니다. 그다음 전송 계층은 양 종단 간의 신뢰성 있는 정보를 전달하며, TCP와 UDP 프로토콜이 이 계층에서 동작합니다. 데이터의 단위는 세그먼트입니다. 그리고 세션 계층은 연결설정을 담당하고 표현 계층은 데이터 암호화,복호화를 담당합니다. 마지막으로 최상위 계층인 응용 계층은 사용자에게 통신을 위한 서비스를 제공하는 인터페이스 역할을 합니다. </p>
</blockquote>
<p><strong>TCP/IP 계층이란 무엇인가요? 이는 OSI 7계층과 무엇이 다른가요?</strong></p>
<blockquote>
<p>TCP/IP 계층은 OSI 모델을 기반으로 상업적으로 이용될 수 있도록 단순화한 모델입니다. 한마디로 네트워크 전송 시 데이터 표준을 정리한 것을 OSI 7계층, 그리고 이 이론을 실제로 상업적, 실무적으로 사용하는 인터넷 표준이 TCP/IP 계층이라고 생각하시면 될것 같습니다.</p>
</blockquote>
<p><strong>라우팅이란 무엇인가요?</strong></p>
<blockquote>
<p>데이터를 목적지까지 전달하기 위한 모든 일련의 과정을 말합니다. 데이터가 전달되는 과정에서 여러 네트워크들을 통과해야하는 경우가 생기는데, 이 네트워크들의 연결을 담당하고 있는 라우팅 장비에게 데이터의 목적지가 어디인지 확인하고 빠르고 정확하게 길을 찾아 전달해주는 과정이 라우팅입니다.</p>
</blockquote>
<p><strong>정적 라우팅과 동적 라우팅의 차이에 대해 설명해보세요</strong></p>
<blockquote>
<p>정적 라우팅은 수동으로 라우팅 테이블을 만드는 방법을 말합니다. 라우터 간의 데이터 교환이 없어 대역폭 절약과, 보안에는 강하지만 정해진 경로에 장애가 발생할 경우 네트워크 전체에 장애가 발생할 수 있습니다. 반면 동적 라우팅은 접하는 라우터들끼리 라우팅 정보를 서로 교환하여 라우팅 테이블을 자동으로 만듭니다. 대역폭 소비가 크지만, 자동으로 라우팅 테이블을 만들고 갱신까지 하기때문에 규모가 큰 네트워크에 적합합니다.</p>
</blockquote>
<p><strong>라우터와 스위치의 차이점에 대해 설명해보세요</strong></p>
<blockquote>
<p>라우터는 네트워크 계층에 속하며, 여러 네트워크를 연결하는 장치로 IP주소가 사용됩니다. 스위치는 데이터 링크 계츠에 속하며, 여러 장치를 동시 연결하는 장치로 mac주소가 사용됩니다. 라우터 같은 경우는 목적지가 불분명한 데이터가 들어오면 폐기시키지만, 쉬위치는 브로드케스트를 통해 해결한다는 차이점이 있습니다.</p>
</blockquote>
<p><strong>TCP/IP 흐름제어가 필요한 이유에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>TCP/IP 프로토콜에서 흐름제어가 필요한 이유는 효율적인 데이터 전송을 보장하기 위함입니다. 예를 들어 송신자가 데이터를 빠른 속도로 보내고, 수신자는 느린 속도로 데이터를 처리하는 경우, 수신자의 버퍼가 넘칠 수 있습니다. 이럴 때 TCP 흐름 제어를 통해 송신자가 더이상 데이터를 못보내게 해서 데이터 전송 속도를 조절합니다.</p>
</blockquote>
<p><strong>흐름제어 방법 2가지에 대해서 설명해보세요</strong></p>
<blockquote>
<p>stop and wait과 sliding window 방법이 있습니다. Stop and wait은 데이터 전송 후 매번 ack을 통해 잘 도착했음을 확인하고 다음 데이터를 보내는 방식입니다. Sliding window는 버퍼가 사용되어서 window크기만큼 ack 없이 데이터를 보낼 수 있는 방식입니다.</p>
</blockquote>
<p><strong>혼잡제어란 무엇인가요?</strong></p>
<blockquote>
<p>만약에 한 라우터에 데이터가 몰릴 경우, 그 하나의 라우터는 모든 데이터를 다 처리할 수가 없데 되고 그러면 송신자는 계속해서 전송을 하게되고 결국 오버플로우나 데이터 손실이 발생하게 되는 상황을 혼잡 현상이라고 하는데, 이러한 혼잡을 피하기 위해서 송신측에서 보내는 데이터의 전송속도를 강제로 줄이는데 이것을 혼잡 제어라고 합니다.</p>
</blockquote>
<p><strong>혼잡제어와 흐름제어의 차이점에 대해서 설명해보세요</strong></p>
<blockquote>
<p>흐름제어는 송신측과 수신측 사이의 전송속도를 다루는 반면, 혼잡제어는 호스트와 라우터를 포함한 보다 넓은 관점에서 전송 문제를 다룹니다. 혼잡제어가 좀 더 큰 개념이라고 보시면 될 것 같습니다.</p>
</blockquote>
<p><strong>혼잡제어 방법 2가지에 대해 설명해보세요</strong></p>
<blockquote>
<p>후..</p>
</blockquote>
<p><strong>TCP/IP란 무엇인가요?</strong></p>
<blockquote>
<p>컴퓨터 네트워크에서 데이터 통신을 위한 프로토콜 스택 중 하나입니다. TCP와 IP 이 두가지 프로토콜로 구성되어있습니다. 간단히 TCP는 신뢰성있는 연결, IP는 신속한 연결을 해준다고 생각하면 될 것 같습니다.</p>
</blockquote>
<p><strong>TCP와 UDP의 차이점을 설명해보세요.</strong></p>
<blockquote>
<p>TCP는 연결지향형 프로토콜이고 UDP는 비연결형 프로토콜입니다. TCP는 신뢰성을 중시하지만 이로 인해 속도는 UDP에 비해 좀 느립니다. 반면 UDP는 신뢰성보다는 단순한 데이터 전송을 목적으로 하여, 신뢰성은 낮지만 속도는 빠릅니다.</p>
</blockquote>
<p><strong>3way handshake와 4wayhandshake에 대해 설명해보세요</strong></p>
<blockquote>
<p>TCP는 신뢰성을 중시하는 연결 지향형 프로코롤입니다. TCP는 3way로 연결을 설정하고 4way로 연결을 해제합니다. 3way부터 간단히 말씀드리면 클라이언트가 서버에게 연결 요청을 보냅니다. 그리고 서버는 그 요청을 받고 연결을 수락할 준비를 하고 그 사실을 클라이언트에게 알립니다. 클라이언트는 서버의 응답을 받고 연결을 확정합니다. 다음 연결을 해제할때 사용하는 4way는 마찬가지로 연결을 종료한다는 메시지를 주고 받습니다. 하지만 이 과정에서 서버는 클라이언트에게 받은 연결 종료 요청에 대한 응답메세지를 보내는 것 외에 서버의 모든 데이터를 보낸 후 연결을 종료하는 fin패킷도 보냅니다. 그리하여 연결 종료할때는 한번의 통신이 더 일어나는 것입니다.</p>
</blockquote>
<p><strong>HTTP 프로토콜에 대해 설명해보세요</strong></p>
<blockquote>
<p>HTTP란 하이퍼텍스트 이동 프로토콜의 줄임말입니다. 인터넷 상에서 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규약이라고 생각하면 될것같습니다. 이전상태를 기억하지 않는 stateless와 connectionless 특징을 가지고 있습니다.</p>
</blockquote>
<p><strong>stateless와 connectionless의 명확한 개념에 대해서 설명해주세요.</strong></p>
<blockquote>
<p>먼저 stateless는  서버가 클라이언트의 상태를 저장하지 않는 것을 말합니다. 이를 통해 서버의 확장성을 높일 수 있습니다. connectionless는 비연결성을 말하며,  통신 프로토콜이 연결을 설정한 후 이를 유지하지 않고 데이터를 주고 받는 것을 의미합니다. 각 패킷은 독립적으로 처리되며, 연결을 설정하고 해제하는 오버헤드가 없습니다.</p>
</blockquote>
<p><strong>HTTP와 HTTPS의 차이점에 대해 설명해보세요</strong></p>
<blockquote>
<p>HTTP는 텍스트 교환이므로, 누군가 네트워크에서 신호를 가로채면 내용이 노출될 수 있는 보안 이슈가 존재합니다. 이런 보안문제를 해결해주는 프로토콜이 HTTPS입니다. 인터넷 상에서 정보를 암호화하는 SSL 프로토콜을 사용합니다. </p>
</blockquote>
<p><strong>http 1.0과 1.1이후의 차이점은 무엇인가요?</strong></p>
<blockquote>
<p>기존 1.0버전은 메서드 종류가 3가지 뿐이고, 1.1부터는 메서드의 종류가 7가지입니다. HTTP 1.0은 하나의 요청을 보내면 요청에 대한 응답이 돌아올때까지 기다려야했지만 1.1은 파이프라이닝이 추가되어 앞에 보냈던 요청에 대한 응답을 기다리지 않고 계속 요청을 보낼 수 있다는 게 가장 큰 차이점입니다.</p>
</blockquote>
<p><strong>대칭키 암호와와 비대칭키 암호화에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>대칭키는 클라이언트와 서버가 동일한 키를 사용해 암호화와 복호화를 진행합니다. 그래서 키가 노출되면 굉장히 위험하지만 연산속도는 빠릅니다. 반대로 비대칭키는 1개의 쌍으로 구성된 공개키와 개인키를 사용합니다. 키가 노출되어도 비교적 안전하지만 연산속도가 느립니다.</p>
</blockquote>
<p><strong>HTTP 메소드의 종류와 역할에 대해 설명해보세요</strong></p>
<blockquote>
<p>HTTP메소드는 GET, POST, PUT, DELETE, HEAD, CONNECT, OPTIONS 이렇게 총 7가지가 있습니다.
get은 데이터 조회, post는 데이터 생성, put은 데이터 수정 그리고 delete는 데이터 삭제를 할때 사용합니다. head는 서버가 정상적으로 작동되고 있는지 확인할 때 사용되고, connect는 ssl 통신을 할때 사용하며, options는 서버가 지원하는 메소드를 확인할때 사용합니다.</p>
</blockquote>
<p><strong>HTTPS 동작 방식에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>https는 대칭키 암호화와 비대칭키 암호화를 모두 사용하여 빠른 연산 속도와 안정성을 모두 제공합니다. https는 처음 연결 성립 시에는 비대칭키를 사용하고, 이후에는 빠른 연산 속도를 위해 대칭키를 사용합니다.</p>
</blockquote>
<p><strong>GET과 POST의 차이점을 설명해보세요</strong></p>
<blockquote>
<p>GET은 데이터 조회할 떄 사용하는 메소드입니다. 데이터를 파라미터를 통해 전송하기 때문에 HTTP 요청 메시지의 BODY부분이 비어있습니다. 반면 POST는 데이터를 생성할때 쓰는 메소드로 데이터 전송 시 HTTP 요청 메세지의 BODY 부분에 데이터를 저장하여 전송합니다.</p>
</blockquote>
<p><strong>로드밸런싱이 필요한 이유는 무엇인가요?</strong></p>
<blockquote>
<p>로드 밸런싱은 여러 대의 서버를 두고 서비스를 제공하는 분산 처리 시스템에서 필요한 기술입니다. 증가하는 트래픽에 대처하기 위한 방법으로  scale-up 방식과 scale-out 방식이 있는데, 이 중 scale-out의 경우에는 여러 대의 서버로 트래픽을 균등하게 분산하기 위해 로드 밸런싱이 반드시 필요합니다.</p>
</blockquote>
<p><strong>L4로드밸런서와 L7로드밸런서의 차이에 대해서 설명해보세요</strong></p>
<blockquote>
<p>L4로드밸런서는 전송 계층에서 부하를 분산하는 방식으로 IP주소, 포트번호, MAC주소 등에 따라 트래픽을 나누고 분산처리합니다. 반면면 L7로드밸런서는 애플리케이션 계층에서 부하를 분산하는 방식으로, HTTP 헤더, 쿠키와 같은 사용자의 요청을 기준으로 트래픽을 분산처리합니다.</p>
</blockquote>
<p><strong>Blocking &amp; Non-Blocking I/O의 차이점에 대해 설명해보세요</strong></p>
<p><strong>웹 서버의 구조에 대해 설명해보세요.</strong></p>
<blockquote>
<p>www, 월드 와이드 웹에는 html, url, http라는 세가지 기술이 사용됩니다.
html은 www를 통해 볼 수 있는 문서를 만들 때 사용하는 프로그래밍 언어이고, url은 인터넷에서 파일 위치를 지정하기 위해 기술된 주소이다. </p>
</blockquote>
<p><strong>DNS란 무엇인가요?</strong></p>
<blockquote>
<p>DNS는 도메인 주소를 IP 주소로 변환해 주는 시스템입니다. 저희가 접하고 있는 구글 닷컴이나 네이버 주소 같은 것들이 도메인 주소라고 생각하시면 될 것 같습니다. DNS는 그런 도메인 주소들을 IP 주소로 변환해줍니다.</p>
</blockquote>
<p><strong>네트워크 애플리케이션 구조 2가지에 대해서 설명해보세요</strong></p>
<blockquote>
<p>클라이언트 서버 구조와 P2P 구조가 있습니다. 클라이언트 서버 구조는 요청을 보내고 응답을 기다리는 클라이언트와 받은 요청에 대한 응답 결과를 보내주는 서버로 이루어져 있습니다. p2p 구조는 서버에 의존하지 않고 호스트끼리 직접 통신하여 호스트 각각이 서버와 클라이언트 둘 다 될 수 있습니다.</p>
</blockquote>
<p><strong>IP와 PORT의 차이점이 무엇인가요?</strong></p>
<blockquote>
<p>IP는 목적지 서버를 찾는 것이고, 그 목적지 서버 안에서 애플리케이션을 구분하는게 포트라고 생각하시면 됩니다. 8080,8090 같이 ip주소 뒤에 붙는 것들이 port번호들입니다.</p>
</blockquote>
<p><strong>인터넷 계층에서 이미 데이터 전송의 역할을 맡았는데 트랜스포트 계층은 왜 필요한건가요?</strong></p>
<blockquote>
<p>IP는 데이터 전송만 담당할 뿐, 순서 등을 고려하지 않는 비신뢰성 연결인데, 트랜스포트 계층에서는 데이터 분실을 방지하고 순서를 보장해주는 등 신뢰성있는 연결을 보장해주기 떄문에 필요합니다.</p>
</blockquote>
<p><strong>IP주소는 무엇이며, 어떤 기능을 하나요?</strong></p>
<blockquote>
<p>IP 주소는 인터넷 프로토콜에서 사용되는 주소로, 네트워크 상에서 호스트를 식별하고, 목적지 서버를 찾는데 사용됩니다. IP는 비신뢰성, 비연결형인 최선형 전송 서비스입니다.</p>
</blockquote>
<p><strong>IP와 mac 주소의 차이점에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>mac주소는 네트워크 인터페이스 계층에서 사용된는 전송 주소로 물리적으로 할당된 고유 주소입니다. 로컬네트워크에서 기기들을 구분하는데 사용됩니다. 반면 IP 주소는 인터넷 프토로콜에서 사용되는 논리적인 주소로 네트워크 상에서 호스트들을 구분하고 통신하는데 사용됩니다.</p>
</blockquote>
<p><strong>쿠키와 세션의 차이점에 대해 설명해보세요</strong></p>
<blockquote>
<p>쿠키는 사용자의 컴퓨터에 저장하는 작은 기록 정보 파일입니다. HTTP에서 클라이언트의 상태 정보를 PC에 저장했다가 필요할때 꺼내서 사용 가능합니다. 세션은 일정 시간동안 같은 사용자로부터 들어오는 요청들을 하나의 상태로 보고 그 상태를 저장하는 기술입니다.쿠키는 클라이언트 측에 저장되는 반명 세션은 웹서버에 저장됩니다.</p>
</blockquote>
<p><strong><a href="http://www.naver.com%EC%97%90">www.naver.com에</a> 접속할때 생기는 과정에 대해 설명해보세요</strong></p>
<blockquote>
<p>먼저 사용ㅇ자가 브라우저에 URL을 입력합니다. 그러면 DNS 서버에서 도메인 이름을 통해 서버의 IP 주소를 찾아냅니다. 그리고 찾아낸 IP주소로 웹 서버에 3way handshake로 연결을 설정합니다. 그러면 이제 클라이언트는 웹 서버로 HTTP 요청메시지를 보내서 웹서버로부터 응답메시지를 받습니다. 도착한 응답메시지는 웹 페이지 데이터로 변환되고, 웹 브라우저에 의해 출력됩니다.</p>
</blockquote>
<p><strong>세션 방식과 토큰 방식의 차이점에 대해서 설명해보세요.</strong></p>
<blockquote>
<p>세션 방식의 경우 서버에 클라이언트 상태를 유지하지만, 토큰 방식은 클라이언트에 토큰이 저장되어 있습니다. 그래서 세션 방식은 보안에는 강하지만 DB 과부하가 올 수 있고, 반대로 토큰 방식은 서버 부담이 줄어들지만, 토큰이 한번 탈취 당하면 토큰 만료 전까지 보안에는 조금 취약하다는 특징이 있습니다. 그럼에도 토큰이 확장성이 뛰어나 대부분 토큰 방식을 많이 사용합니다.</p>
</blockquote>
<p><strong>인증과 인가에 대해서 설명해주새요</strong></p>
<blockquote>
<p>인증은 쉽게 말해 로그인입니다. 클라이언트가 자기 자신이라고 주장하고 있는 사용자가 맞는지를 검증하는 과정입니다. 인가는 유저의 요청에 대한 권한을 확인하고 허가 해주는것입니다.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>