<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>1abme</title>
        <link>https://velog.io/</link>
        <description>제가 이해하고 있는게 맞나요...?</description>
        <lastBuildDate>Mon, 09 Feb 2026 00:34:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>1abme</title>
            <url>https://velog.velcdn.com/images/1aba_can_opener/profile/1260fc11-5f24-4200-9fed-1ec4210453ac/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 1abme. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/1aba_can_opener" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ㄴ]]></title>
            <link>https://velog.io/@1aba_can_opener/%E3%84%B4-4nq0p0wc</link>
            <guid>https://velog.io/@1aba_can_opener/%E3%84%B4-4nq0p0wc</guid>
            <pubDate>Mon, 09 Feb 2026 00:34:16 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Proxy]]></title>
            <link>https://velog.io/@1aba_can_opener/Proxy</link>
            <guid>https://velog.io/@1aba_can_opener/Proxy</guid>
            <pubDate>Wed, 07 Jun 2023 02:17:04 GMT</pubDate>
            <description><![CDATA[<h2 id="라이브-데이터">라이브 데이터</h2>
<hr>
<p>실제 서비스가되는 상용 앱을 운영하면 클라이언트 뒤의 서버와 연결어 있는 DB에 라이브 데이터 (live data)가 쌓인다.</p>
<p>라이브 데이터는 실제 서비스되고 있는 앱의 데이터베이스 (Data Base, DB)에 적재되고 있는 데이터를 말하며 유저 및 상품, 결제 등 민감성이 높은 데이터들이 대부분이다.</p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/dbc50030-555b-45de-9e4b-0ac238bf502a/image.png" alt=""></p>
<p>이러한 라이브데이터의 보안성을 위해서는 CORS 설정을 통해 특정 도메인만을 허용하도록 구현하는 방법과 Proxy 기능을 사용한 방법이 있다.</p>
<h2 id="cors-cross-origin-resource-sharing">CORS (Cross-Origin Resource Sharing)</h2>
<hr>
<p>SOP(Same-Origin Policy) 브라우저에서 API를 요청할 때에, 브라우저의 현재 주소와 API의 주소의 도메인이 일치해야만 데이터를 접근할 수 있는 정책으로 인해 다른 도메인에서 API를 요청해 사용할 수 있게끔 하기 위해 CORS(교차 출처 리소스 공유) 정책이 나왔다.</p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/a08d587f-3fe3-49e6-ad58-1806d6a10a45/image.png" alt=""></p>
<p>프론트엔드에서 개발한 React앱에 CORS 설정을 적용한다면</p>
<ul>
<li>프론트엔드에서 개발한 React 앱에서 브라우저 쪽으로 요청을 보낸다.</li>
<li>브라우저는 백엔드, 서버 쪽으로 리소스를 요청한다. </li>
<li>백엔드 서버는 정상적으로 200 OK응답을 브라우저에게 보낸다.</li>
<li>브라우저는 받은 리소스 및 응답과 함께 출처가 같은지 확인한다.</li>
<li>출처가 다르다면 응답을 파기 (CORS Error) 한다.</li>
<li>출처가 같다면 받은 응답을 프론트 엔드쪽으로 보낸다. </li>
</ul>
<h2 id="proxy">Proxy</h2>
<hr>
<p>React 라이브러리, 혹은 Webpack Dev Server에서 제공하는 Proxy 기능을 사용하면 CORS정책을 우회할 수 있다. </p>
<p>별도의 응답 헤더를 받지않고 브라우저는 React 앱으로 데이터를 요청, 해당 요청을 백엔드로 전달한다. 여기서 React 앱이 서버로부터 받은 응답 데이터를 다시 전달해 브라우저는 CORS 정책을 위반했는지 모르게 된다. 일종의 브라우저를 Proxy 기능을 통해 속이는 셈이다.</p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/86a52e6f-b499-4452-9e42-3faf979f8842/image.png" alt=""></p>
<p>프론트엔드에서 개발한 React앱에 proxy 적용한다면</p>
<ul>
<li>React 앱에서 브라우저를 통해 API를 요청할 때 Proxy를 통해 백엔드 서버로 요청을 위회해 보낸다.</li>
<li>백엔드 서버는 응답을 React 앱으로 보낸다.</li>
<li>React 앱은 받은 응답을 백엔드 서버 대신 브라우저에게 전달한다.<ul>
<li>이렇게 되면 출처가 같아져 브라우저는 접근을 허용하게 된다.</li>
</ul>
</li>
</ul>
<h2 id="proxy-사용법">Proxy 사용법</h2>
<hr>
<p>React에서 Proxy를 사용하는 방법은 크게 두가지가 있다.</p>
<ul>
<li>Webpack dev server proxy</li>
<li>React Proxy</li>
</ul>
<h3 id="webpack-dev-server-proxy">Webpack dev server proxy</h3>
<hr>
<p>webpack dev server에서 제공하는 proxy 기능을 사용하는 방법이다.</p>
<p>webpack dev server의 proxy 사용시 </p>
<ul>
<li><p>브라우저 API를 요청할 때 백엔드 서버에 직접적으로 요청이 아닌, 현재 개발서버의 주소로 우회 요청</p>
</li>
<li><p>웹팩 개발 서버에서 해당 요청을 받아 그대로 백엔드 서버로 전달</p>
</li>
<li><p>백엔드 서버에서 응답한 내용을 다시 브라우저 쪽으로 반환</p>
</li>
</ul>
<p>이러한 웹팩 개발서버의 proxy 설정은 웹팩 설정을 통해서 적용 한다. </p>
<p>하지만 CRA를 통해 만든 리액트 프로젝트에서는 package.json 에서 &quot;proxy&quot; 값을 설정하여 쉽게 적용할 수 있도록 구성되어 있다.</p>
<pre><code class="language-js">...
&quot;browserslist&quot;: {
    &quot;production&quot;: [
      &quot;&gt;0.2%&quot;,
      &quot;not dead&quot;,
      &quot;not op_mini all&quot;
    ],
    &quot;development&quot;: [
      &quot;last 1 chrome version&quot;,
      &quot;last 1 firefox version&quot;,
      &quot;last 1 safari version&quot;
    ]
  },
    &quot;proxy&quot; : &quot;우회할 API 주소&quot;
}</code></pre>
<p>proxy는 보통 맨 밑에 작성을 해 금방 찾을 수 있도록 한다.</p>
<p>그리고 기존의 fetch, 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거한다.</p>
<pre><code class="language-js">export async function getAllfetch() {

    const response = await fetch(&#39;우회할 api주소/params&#39;);
    .then(() =&gt; {
            ...
        })
}

export async function getAllfetch() {

    const response = await fetch(&#39;/params&#39;);
    .then(() =&gt; {
            ...
        })
}</code></pre>
<h3 id="react-proxy">React Proxy</h3>
<hr>
<p>webpack dev server에서 제공하는 proxy는 전역적인 설정이기 때문에, 종종 해당 방법이 충분히 적용되지 않는 경우가 생기기도 한다.</p>
<p>때문에 로 proxy를 적용해줘야 하는 경우가 있는데, 이때는 http-proxy-middleware 라이브러리를 사용해야 한다. </p>
<pre><code class="language-js">npm install http-proxy-middleware --save
</code></pre>
<ul>
<li>위의 명령어로 http-proxy-middleware 라이브러리를 설치</li>
<li>React App의 src파일 안에서 setupProxy.js 파일을 생성</li>
<li>해당 파일에 설치한 라이브러리 파일을 불러온다. </li>
<li>불러온 코드 밑에 아래 코드를 참고해 작성</li>
</ul>
<pre><code class="language-js">const { createProxyMiddleware } = require(&#39;http-proxy-middleware&#39;);

module.exports = function(app) {
  app.use(
    &#39;/api&#39;, //proxy가 필요한 path prameter를 입력합니다.
    createProxyMiddleware({
      target: &#39;http://localhost:5000&#39;, //타겟이 되는 api url를 입력합니다.
      changeOrigin: true, //대상 서버 구성에 따라 호스트 헤더가 변경되도록 설정하는 부분입니다.
    })
  );
};</code></pre>
<ul>
<li>기존의 fetch, 혹은 axios를 통해 요청하던 부분에서 도메인 부분을 제거</li>
</ul>
<pre><code class="language-js">export async function getAllfetch() {

    const response = await fetch(&#39;우회할 api주소/params&#39;);
    .then(() =&gt; {
            ...
        })
}

export async function getAllfetch() {

    const response = await fetch(&#39;/params&#39;);
    .then(() =&gt; {
            ...
        })
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CI / CD ]]></title>
            <link>https://velog.io/@1aba_can_opener/CI-CD</link>
            <guid>https://velog.io/@1aba_can_opener/CI-CD</guid>
            <pubDate>Mon, 05 Jun 2023 04:41:31 GMT</pubDate>
            <description><![CDATA[<h2 id="ci--cd">CI / CD</h2>
<hr>
<h3 id="ci-continuous-intergration">CI (Continuous Intergration)</h3>
<p>CI/CD의 CI는 개발자를 위한 자동화 프로세스인 지속적인 통합(Continuous Intergration)을 의미한다. </p>
<p>CI를 성공적으로 구현하면 애플리케이션에 대한 새로운 코드 변경사항이 정기적으로 빌드 및 테스트되어 공유 레포지토리에 통합되어 여러 명의 개발자가 동시에 애플리케이션 개발 코드 작업을 할 경우 충돌할 수 있는 문제를 해결할 수 있다.</p>
<h3 id="cd-continuous-delivery--deployment">CD (Continuous Delivery / Deployment)</h3>
<p>CI/CD의 CD는 지속적인 서비스 제공 (Continuous Delivery) 및/또는 지속적인 배포 (Continuous Deployment)를 의미한다. 이 두 용어는 상호 교환적으로 사용된다.</p>
<p>두가지 의미 모두 파이프라인의 추가 단계에 대한 자동화를 뜻하지만 얼마나 많은 자동화가 이루어지고 있는지 설명하기 위해 별도로 사용되기도 한다.</p>
<h2 id="cicd의-단계">CI/CD의 단계</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/9f336140-7310-42c7-98d7-a63b1535aad8/image.png" alt=""></p>
<p>위는 일반적인 앱의 개발및 유지보수 단계이다. 이 과정에서 지속적 통합 및 지속적 전달을 단계별로 나눌 수 있다. </p>
<h3 id="지속적-통합-continuous-integration-ci">지속적 통합 (Continuous Integration, CI)</h3>
<p>개발자를 위한 자동화 프로세스라고 할 수 있으며 Code - Build - Test 단계에서 실행된다.</p>
<ul>
<li>Code : 개발자가 코드를 원격 코드 저장소 (ex. github repository)에  push 하는 단계</li>
<li>Build : 원격 코드 저장소로부터 코드를 가져와 유닛 테스트 후 빌드하는 단계 </li>
<li>Test : 코드 빌드의 결과물이 다른 컴포넌트와 잘 통합되는지 확인하는 과정</li>
</ul>
<p>이 과정에서 개발자는 코드를 잦게 원격 코드 저장소에 push하고 테스트 및 빌드를 해 빌드의 성공여부와 통합 테스트 결과를 통해 개선 방안을 찾는다. </p>
<p>이러한 과정으로 개발자는 버그를 일찍 발견할 수 있고 테스트가 완료된 코드를 빠른 전달, 지속적인 배포가 가능해진다. </p>
<p>지속적 통합은 모든 코드 변화를 하나의 레포지토리에서 관리하는 것 부터 시작이며 모든 개발팀이 코드 변화를 확인 할 수 있어 투명히 문제점을 파악할 수 있다. </p>
<p>또한 잦은 풀 리퀘스트 (pull request)와 머지 (merge)로 코드를 자주 통합하며 이때 기본적인 테스트도 작동시킬 수 있어 지속적 통합을 통해 개발팀은 각자의 코드를 이른 시점에 합치고 자주 테스트 해볼 수 있다.</p>
<p>지속적 통합이 적용된 개발팀은 코드를 머지하기 전, 이미 빌드 오류나 테스트 오류를 확인하여 훨씬 더 효율적인 개발을 할 수 있다. </p>
<h3 id="지속적-배포-coninuous-deliverydeploment-cd">지속적 배포 (Coninuous Delivery/Deploment, CD)</h3>
<p>지속적인 서비스 제공 및 지속적인 배포를 의미하며 상호 교환적으로 사용되는 이 부분은 Release - Deploy - Operate 단계에서 실행된다.</p>
<ul>
<li>Release : 배포 가능한 소프트웨어 패키지를 작성</li>
<li>Deploy : 프로비저닝을 실행하고 서비스를 사용자에게 노출하는 실질적 배포 부분</li>
<li>Operate : 서비스 현황을 파악하고 생길 수 있는 문제를 감지</li>
</ul>
<p>지속적 배포의 경우 코드 변경 사항의 병합부터 프로덕션에 적합한 빌드 제공에 이르는 모든 단계로 테스트 자동화와 코드 배포 자동화가 포함된다. </p>
<p>이 프로세스를 완료시 프로덕션 준비가 완료된 빌드를 코드 리포지토리에 자동으로 배포할 수 있기 때문에 운영팀이 보다 빠르고 쉽게 애플리케이션을 프로덕션으로 배포할 수 있다.</p>
<p>최근에는 클라우드 기술 발전과 맞물려 지속적 통합과 지속적 배포가 빠른 속도로 진행되어 CI/CD를 하나로 묶어 다루는 경우가 증가하고 있다. </p>
<p>예를 들어 이전엔 배포 자체가 오래걸리고 힘들기에 배포 이전 단계에서 많은 고민을 했다. 서버를 전부 재시작하거나 일부 기능을 제공하지 못하는 경우도 많았기 때문이다. 요즘은 고객의 피드백을 빨리 받기 위함과 서비스를 중단하지 않기 위해서라도 릴리즈만 잘 기록해 두고 바로 배포하는 사례가 증가하고 있다.</p>
<h4 id="지속적-배포-사례">지속적 배포 사례</h4>
<p>지속적 배포의 가장 흔한 사례는 Github Page이다. 지정해 둔 디렉토리에 정해진 방식에 따라 커밋하면 Github Page 가 알아서 해당 index.html 파일과 해당 디렉토리에 있는 파일을 번들링해 Github Page 서버에 업로드한다. 이렇게 자동으로 인터넷에 배포되고 만든 결과물을 쉽게 공유 할 수 있다. 그렇게 공유된 결과물에 대해 피드백도 받을 수 있으므로 지속적 배포라고 할 수 있다.</p>
<h2 id="cicd의-영역">CI/CD의 영역</h2>
<hr>
<p>CI/CD는 지속적 통합 및 <a href="https://www.redhat.com/ko/topics/devops/what-is-continuous-delivery">지속적 제공</a> 의 구축 사례만을 지칭할 때도 있고 지속적 통합, 지속적 제공, 지속적 배포 모두를 의미할 때도 있다.</p>
<p>혹은 지속적 서비스 제공이 지속적 배포의 과정까지 포함하는 방식으로 사용되기도 한다.</p>
<p>결과적으로 CI/CD는 파이프라인으로 표현되는 실제 프로세스를 의미하고 애플리케이션 개발에 지속적인 자동화 및 모니터링을 추가하는 것을 의미한다. 이는 사례별로 CI/CD 파이프라인에 구현된 자동화 수준 정도에 따라 그 의미가 달라지낟. </p>
<p>대부분의 기업에서는 CI를 먼저 추가한 다음 <a href="https://www.redhat.com/ko/topics/cloud-native-apps">클라우드 네이티브 애플리케이션</a>의 일부로서 배포 및 개발 자동화를 구현해 나간다. </p>
<h2 id="github-action으로-클라이언트-cicd를-구축한-배포">github action으로 클라이언트 CI/CD를 구축한 배포</h2>
<hr>
<p><a href="https://github.com/1abme/my-agora-states-practice/actions/runs/5173415543/jobs/9319087950">github action으로 클라이언트 CI/CD를 구축한 배포링크</a></p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/02d2873d-1609-467b-aca2-848c8a510a4c/image.png" alt=""></p>
<h3 id="clientyml-파일">client.yml 파일</h3>
<pre><code class="language-yml">name: client
on:
  push:
    branches:
      - reference
jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout source code.
        uses: actions/checkout@v2
      - name: Install dependencies
        run: npm install
        working-directory: ./my-agora-states-client-react
      - name: Build
        run: npm run build
        working-directory: ./my-agora-states-client-react
      - name: SHOW AWS CLI VERSION
        run: |
          aws --version
      - name: Sync Bucket
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_EC2_METADATA_DISABLED: true
        run: |
          aws s3 sync \
            --region ap-northeast-2 \
            build s3://{버킷이름} \
            --delete 
        working-directory: ./my-agora-states-client-react
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 문법]]></title>
            <link>https://velog.io/@1aba_can_opener/TypeScript2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@1aba_can_opener/TypeScript2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 30 May 2023 15:17:06 GMT</pubDate>
            <description><![CDATA[<h2 id="typescript의-열거형enum">TypeScript의 열거형(Enum)</h2>
<hr>
<p>TypeScript의 열거형(Enum)은 특정 값의 집합을 정의할 때 사용한다.</p>
<p>열거형은 숫자형과 문자열형, 혹은 이 둘의 조합으로 정의될 수 있다.</p>
<p>TypeScript에서 열거형은 일반적으로 JavaScript의 상수값 대신 사용된다. 그렇게 사용되는 열거형은 가독성과 안정성을 높여주고 오타와 같은 실수를 방지해준다.</p>
<h2 id="숫자형-열거형-enum">숫자형 열거형 (Enum)</h2>
<hr>
<p>열거형은 디폴트 값으로 숫자형을 사용하며 각 값은 자동으로 0부터 시작해 1씩 증가하며 이를 auto-incrementing 이라고 한다.  </p>
<pre><code class="language-ts">enum Color {
  Red,
  Green,
  Blue,
}</code></pre>
<p>따라서 위의 경우 <code>Red</code> 값은 <code>0</code>, <code>Green</code> 값은 <code>1</code>, <code>Blue</code> 값은 <code>2</code> 가 된다.</p>
<p>또한 수동으로 값을 지정하거나 열거형의 값에 대해 산술 연산을 수행할 수도 있다.</p>
<pre><code class="language-ts">enum Color {
  Red = 1,
  Green = 2,
  Blue = 4,
}

let c: Color = Color.Green;
let greenValue: number = Color.Green;
let blueValue: number = Color.Blue;

console.log(c);          // 출력: 2
console.log(greenValue);  // 출력: 2
console.log(blueValue);   // 출력: 4</code></pre>
<h3 id="역-매핑-reverse-mappings">역 매핑 (Reverse mappings)</h3>
<hr>
<p>숫자형 열거형에만 존재하는 역 매핑은 열거형의 키 (<code>key</code>)로 값 (<code>value</code>)을 얻을 수 있고 값 (<code>value</code>)으로 키 (<code>key</code>)를 얻을 수도 있다. </p>
<pre><code class="language-ts">enum Enum {
    A
}
let a = Enum.A;
let nameOfA = Enum[a]; // &quot;A&quot;</code></pre>
<h2 id="문자형-열거형-enum">문자형 열거형 (Enum)</h2>
<hr>
<p>문자형 열거형은 열거형의 값을 전부 다 특정 문자 혹은 다른 열거형 값으로 초기화 해야한다.</p>
<pre><code class="language-ts">enum Direction {
  Up = &quot;UP&quot;,
  Down = &quot;DOWN&quot;,
  Left = &quot;LEFT&quot;,
  Right = &quot;RIGHT&quot;,
}

let myDirection: Direction = Direction.Up;
console.log(myDirection); // 출력: &quot;UP&quot;</code></pre>
<p>숫자형 열거형의 값은 디버깅시 가끔 불명확한 값이 나올 수 있지만 문자형 열거형은 항상 명확한 값이 나온다. 때문에 문자열 기반의 열거형은 주로 외부에서 가져온 값을 TypeScirpt에서 다룰 때 사용한다. </p>
<h2 id="typescript의-인터페이스interface">TypeScript의 인터페이스(Interface)</h2>
<hr>
<p>TypeScript에서 인터페이스(Interface)는 일반적으로 타입 체크를 위해 사용 된다. </p>
<p>인터페이스는 변수, 함수, 클래스에 사용할 수 있으며, 인터페이스에 선언된 프로퍼티 또는 메서드의 구현을 강제해 일관성을 유지한다. </p>
<p>TypeScript의 예약어인 <code>interface</code>를 사용해 인터페이스를 생성할 수 있다.</p>
<ul>
<li>예약어 (reserved word)<ul>
<li>이미 문법적인 용도로 사용되고 있기 때문에 식별자로 사용할 수 없는 단어</li>
</ul>
</li>
</ul>
<p>이때 인터페이스의 이름은 대문자로 시작해야한다. </p>
<p>다른언어의 경우 interface의 i 를 따와서 이름앞에 i를 붙혀주는 네이밍 컨벤션을 사용하고 있지만 타입스크립트에서는 i를 붙히지 않는것을 네이밍컨벤션으로 권장하고 있다. </p>
<ul>
<li><a href="https://github.com/microsoft/TypeScript/wiki/Coding-guidelines">타입스크립트 네이밍 컨벤션 문서</a> </li>
<li>네이밍 컨벤션<ul>
<li>이름을 짓는 일종의 관례</li>
</ul>
</li>
</ul>
<h3 id="변수와-인터페이스">변수와 인터페이스</h3>
<hr>
<p>TypeScript에서 변수를 선언할 때 인터페이스를 같이 사용하는 경우가 있는데, 객체 (Object) 의 구조를 정의하기 위해 주로 사용된다.</p>
<p>이때 인터페이스를 사용해 선언한 변수는 정의된 프로퍼티를 모두 포함 하고 있어야 한다. 또한 <code>interface</code>로 정의된 속성만 지정할 수 있다.</p>
<p>하지만 <code>?</code>연산자를 사용하면 선택적 프로퍼티를 작성할 수 있다. </p>
<h3 id="함수와-인터페이스">함수와 인터페이스</h3>
<hr>
<p>인터페이스를 사용하면 객체의 프로퍼티 이름과 티입을 정의하고, 함수의 매개변수 타입과 반환 타입도 정의할 수 있다.</p>
<p>이때 인터페이스를 사용해 구현된 함수는 매개 변수의 타입과 반환 타입을 작성하지 않아도 된다.</p>
<h3 id="클래스와-인터페이스">클래스와 인터페이스</h3>
<hr>
<p>클래스에서도 인터페이스 사용이 가능하다. 다만 클래스를 구현할 때 인터페이스에서 정의된 함수나 메서드의 매개변수 타입과 반환값이 일치해야하므로 클래스 내부에서 해당 메서드의 매개변수 타입을 다시한번 명시해주지 않으면 컴파일 에러가 발생한다. </p>
<h2 id="typescript의-타입-별칭type-aliases">TypeScript의 타입 별칭(Type Aliases)</h2>
<hr>
<p>타입 별칭(Type Aliases)은 타입의 새로운 이름을 만드는 것으로 새로운 이름으로 기존의 타입을 참조하는 것을 말하며 키워드 <code>type</code> 타입을 사용해 작성한다.</p>
<pre><code class="language-ts">type MyString = string;

let str1: string = &#39;hello!&#39;;

// string 타입처럼 사용할 수 있습니다.
let str2: MyString = &#39;hello world!&#39;;</code></pre>
<p>타입 별칭을 사용하면 코드를 간결하고 가독성 좋게 만들 수 있다. 또한 복잡한 타입을 간략하게 표현하고 타입 정의를 재사용 하는 등의 가독성을 높일 수 있다. </p>
<p>타입 별칭으로 만들어진 타입을 참조할 시에는 인터페이스와 마찬가지로 내부에 정의된 프로퍼티를 전부 참조해야만 하며 그 외에 다른 프로퍼티를 더 작성하게 되면 컴파일 에러가 발생한다.</p>
<h2 id="typescript의-타입-추론type-inference">TypeScript의 타입 추론(Type Inference)</h2>
<hr>
<p>타입 추론(Type Inference)은 변수나 함수의 타입을 선언하지 않아도 TypeScript가 자동으로 유추하는 기능이다. </p>
<h3 id="최적-공통-타입-best-common-type">최적 공통 타입 (Best common type)</h3>
<hr>
<p>TypeScript는 여러 표현식에서 타입 추론이 발생할 때, 해당 표현식의 타입을 사용하여 &quot;최적 공통 타입&quot;을 계산한다.</p>
<h3 id="문맥상의-타이핑contextual-typing">문맥상의 타이핑(Contextual Typing)</h3>
<hr>
<p>타입스크립트에서 타입을 추론하는 또 하나의 방식은 문맥상으로 타입을 결정한다.</p>
<h3 id="타입-추론의-장단점">타입 추론의 장단점</h3>
<hr>
<h4 id="장점">장점</h4>
<ul>
<li><p>코드의 가독성 향상</p>
<ul>
<li>명시적으로 타입을 지정하지 않아도 코드에서 변수의 타입을 알 수 있어 가독성이 향상된다.</li>
</ul>
</li>
<li><p>개발 생산성 향상</p>
<ul>
<li>명시적으로 타입을 지정하지 않아도 자동으로 타입을 추론하기 때문에 코드 작성 시간이 단축된다. </li>
</ul>
</li>
<li><p>오류 발견 용이성</p>
<ul>
<li>변수나 함수의 타입을 추론하여 타입 검사를 수행하기 때문에 오류 발견이 쉽다.</li>
</ul>
</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li><p>타입 추론이 잘못되어 오류가 발생할 수 있다.</p>
<ul>
<li>TypeScript가 자동으로 수행하기 때문에 추론이 잘못되어 코드 오류가 발생할 수 있다. </li>
</ul>
</li>
<li><p>명시적인 타입 지정이 필요한 경우가 있다. </p>
<ul>
<li>복잡한 함수나 객체등 타입 추론만으로는 부족해 명시적인 타입 지정이 필요한 경우가 있다.</li>
</ul>
</li>
</ul>
<h2 id="typescript에서의-클래스class">TypeScript에서의 클래스(Class)</h2>
<hr>
<p>TypeScript의 클래스는 JavaScript의 클래스와 비슷하지만 몇 가지 추가된 기능이 있다.</p>
<p>일단 TypeScript에서는 클래스의 속성과 메서드에 대한 타입을 명시할 수 있다. </p>
<pre><code class="language-ts">class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I&#39;m ${this.age} years old.`);
  }
}

// 클래스를 사용한 객체 생성
const person = new Person(&#39;Alice&#39;, 30);
person.greet(); // &quot;Hello, my name is Alice and I&#39;m 30 years old.&quot;</code></pre>
<p>TypeScript에서 클래스를 정의할 때, <code>constructor</code> 를 이용하여 초기화하는 멤버들은 전부 상단에서 정의해줘야 한다. </p>
<p>또한 <code>constructor</code> 내 인자로 받을 때도 정확히 타입을 명시해야한다.</p>
<h3 id="클래스와-상속inheritance">클래스와 상속(Inheritance)</h3>
<hr>
<p>TypeScript의 클래스(class)는 <code>extends</code> 키워드를 사용해 기존에 존재하던 클래스를 상속받아 확장하여 새로운 클래스를 만들 수 있다.</p>
<h3 id="public-private-키워드">public, private 키워드</h3>
<hr>
<p>기본적으로 클래스 내에 선언된 멤버는 외부로 공개되는 것이 디폴트 값이다. 이와 관련되어 타입스립트에는 <code>public</code> 키워드와 <code>private</code> 키워드가 존재한다.</p>
<ul>
<li><h4 id="public-키워드">public 키워드</h4>
<p><code>public</code> 키워드를 사용하면 공개된다고 명시적으로 표시할 수 있다. </p>
</li>
<li><h4 id="private-키워드">private 키워드</h4>
<p>외부에 드러내지 않을 멤버가 있다면 <code>private</code> 키워드로 명시해 주면 된다.</p>
</li>
</ul>
<h3 id="readonly-키워드">readonly 키워드</h3>
<hr>
<p><code>readonly</code> 키워드를 사용하면 프로퍼티를 읽기 전용으로 만들 수 있다. 이때 읽기 전용 프로퍼티들은 선언 또는 생성자에서 초기화해야 한다.</p>
<p><code>readonly</code> 로 명시되어 있으면 재할당으로 값을 변경할 수 없다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 환경 구성 & 기본 타입]]></title>
            <link>https://velog.io/@1aba_can_opener/TypeScript1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@1aba_can_opener/TypeScript1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 30 May 2023 06:36:11 GMT</pubDate>
            <description><![CDATA[<h2 id="🛠️-typescript-프로젝트-환경-구성법">🛠️&nbsp; TypeScript 프로젝트 환경 구성법</h2>
<hr>
<h4 id="1nbsp-프로젝트-폴더-생성">1.&amp;nbsp 프로젝트 폴더 생성</h4>
<p>먼저 프로젝트 폴더를 생성한다.</p>
<pre><code class="language-js">mkdir (폴더명)
cd (폴더명)</code></pre>
<h4 id="2nbsp-새로운-프로젝트를-초기화">2.&amp;nbsp 새로운 프로젝트를 초기화</h4>
<p>프로젝트 폴더 생성하고 난 뒤 프로젝트 폴더 안으로 이동해 
<code>npm init -y</code> 
명령어를 실행해 새로운 프로젝트를 초기화한다.</p>
<h4 id="3nbsp-typescipt-설치">3.&amp;nbsp TypeScipt 설치</h4>
<p>프로젝트 내부에 npm을 사용할 준비가 되었으므로 
<code>npm install typescript --save-dev</code> 
명령어를 실행해 TypeScript를 설치한다. </p>
<h4 id="4nbsp-tsconfigjson-파일-생성">4.&amp;nbsp tsconfig.json 파일 생성</h4>
<p>프로젝트 루트 디렉토리 <code>tsconfig.json</code> 파일을 생성 한후 내부에 밑의 코드를 작성한다.</p>
<pre><code class="language-js">//tsconfig.json
//compilerOptions 내의 속성은 자유롭게 커스텀 할 수 있다.
{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;es6&quot;, // ECMAScript 6를 대상으로 컴파일
    &quot;module&quot;: &quot;commonjs&quot;, // 컴파일된 모듈은 CommonJS 스타일로 생성
    &quot;sourceMap&quot;: true, // 소스 맵 파일을 생성 (디버깅에 도움)
    &quot;outDir&quot;: &quot;./dist&quot; // 컴파일된 JavaScript 파일의 출력 디렉토리 (&quot;./dist&quot; 폴더에 생성)
  },
  &quot;include&quot;: [
    &quot;src/**/*&quot;  // 컴파일할 소스 파일의 경로 패턴을 지정 (&quot;src&quot; 폴더 내의 모든 파일과 하위 디렉토리의 파일)
  ]
}</code></pre>
<h4 id="5nbsp-typescript-파일-작성">5.&amp;nbsp TypeScript 파일 작성</h4>
<p>컴파일할 소스 파일의 경로 패턴을 <code>&quot;src/**/*&quot;</code> 로 지정해주었으므로 <code>src</code> 폴더를 만든다. 
그 후 <code>src</code> 폴더 내부에 <code>파일명.ts</code> 로 TypeScript 파일을 생성하고 작성하면 된다.</p>
<h2 id="💿nbspeslint--prettier">💿&amp;nbspESLint &amp; Prettier</h2>
<hr>
<h3 id="eslint">ESLint</h3>
<p>Lint는 보푸라기라는 뜻으로 프로그래밍 쪽에서는 에러가 있는 코드에 표시를 달아놓는 것을 의미한다. ESLint는 자바스크립트 문법 중 에러가 있는 곳에 표시를 달아놓는 도구로 코드를 분석해 문법적인 오류나 안티 패턴을 찾아주고 일관된 코드 스타일을 유지(포맷팅)하여 개발자가 쉽게 읽도록 코드를 만들어준다.</p>
<h3 id="prettier">Prettier</h3>
<p>Prettier는 자동으로 코드 정리를 해줘 코드가 깔끔하게 정렬된다.세미콜론이 빠진 곳에는 세미콜론이 자동으로 추가되고, 작은따옴표/큰따옴표/탭 간격 등을 설정할 수 있는 등 유용한 확장 프로그램이다.</p>
<p>이를 사용하면 협업을 하는 과정/규칙을 정하는데 있어 많은 도움이 된다</p>
<h2 id="⚙️nbsp-typescript-eslint--prettier-설정">⚙️&amp;nbsp TypeScript ESLint &amp; Prettier 설정</h2>
<hr>
<p>VSCode 에서 TypeScript ESLint &amp; Prettier 설정하는 방법이다.</p>
<h4 id="1nbsp-확장-프로그램인-eslint-설치">1.&amp;nbsp 확장 프로그램인 ESLint 설치</h4>
<ul>
<li>확장프로그램 설치 창에서 ESLint를 찾아 확장 프로그램 을 설치해준다.</li>
</ul>
<h4 id="2nbsp-vscode-에디터에-설정-코드를-작성">2.&amp;nbsp VSCode 에디터에 설정 코드를 작성</h4>
<ul>
<li>기본설정: 사용자 설정열기 (JSON) / Preferences: Open User Settings (JSON) 에 들어간다.</li>
<li>setting.json 파일에 아래 코드를 입력해준다.<pre><code class="language-js">{
// ... 
&quot;editor.codeActionsOnSave&quot;: {
    &quot;source.fixAll.eslint&quot;: true
},
&quot;eslint.alwaysShowStatus&quot;: true,
&quot;eslint.workingDirectories&quot;: [
    {&quot;mode&quot;: &quot;auto&quot;}
],
&quot;eslint.validate&quot;: [
    &quot;javascript&quot;,
    &quot;typescript&quot;
],
}</code></pre>
만약 작성되어있는 코드들이 있다면 그 밑에 바로 내용을 넣어준다.</li>
</ul>
<h4 id="3nbsp-format-on-save-가-해제-되어-있는지-확인">3.&amp;nbsp <code>format on save</code> 가 해제 되어 있는지 확인</h4>
<ul>
<li><code>cmd + ,</code> 를 사용해 VSCode 에디터 설정으로 이동한다. </li>
<li><code>format on save</code> 를 찾아 해제 되어 있는지 확인한다.</li>
</ul>
<h4 id="4nbsp-확장-프로그램인-prettier-설치">4.&amp;nbsp 확장 프로그램인 Prettier 설치</h4>
<ul>
<li><p>확장프로그램 설치 창에서 Prettier 를 찾아 확장 프로그램 을 설치해준다.</p>
<h4 id="5nbsp-프리셋-라이브러리-설치">5.&amp;nbsp 프리셋&amp; 라이브러리 설치</h4>
</li>
<li><p>터미널에 명령어를 통해 몇 가지 필요한 프리셋과 라이브러리를 설치한다.</p>
<pre><code>npm i -D @babel/core @babel/preset-env @babel/preset-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint prettier eslint-plugin-prettier </code></pre></li>
<li><p><code>@babel/core</code></p>
<ul>
<li>Babel의 핵심 패키지</li>
<li>최신 JavaScript 코드를 구식 브라우저와 호환되는 이전 버전의 JavaScript 코드로 변환하기 위해 사용</li>
</ul>
</li>
<li><p><code>@babel/preset-env</code></p>
<ul>
<li>Babel의 환경 프리셋 패키지</li>
<li>프로젝트의 대상 환경에 필요한 Babel 플러그인과 설정을 자동으로 결정하여 자동으로 최적의 변환 설정을 제공</li>
</ul>
</li>
<li><p><code>@babel/preset-typescript</code></p>
<ul>
<li>TypeScript 코드를 JavaScript로 변환하기 위한 Babel 프리셋 패키지</li>
</ul>
</li>
<li><p><code>@typescript-eslint/eslint-plugin</code></p>
<ul>
<li>TypeScript 프로젝트에서 ESLint를 사용하기 위한 플러그인</li>
</ul>
</li>
<li><p><code>@typescript-eslint/parser</code></p>
<ul>
<li>TypeScript 코드를 정적으로 분석하기 위한 ESLint 파서</li>
<li>TypeScript 코드를 분석하고, AST(Abstract Syntax Tree)를 생성</li>
</ul>
</li>
<li><p><code>eslint-plugin-prettier</code></p>
<ul>
<li>ESLint와 Prettier를 통합하여 ESLint 규칙과 Prettier의 포맷팅 규칙이 충돌하는 부분을 해결</li>
</ul>
</li>
</ul>
<h4 id="6nbsp-eslintrcjs-파일-생성--작성">6.&amp;nbsp .eslintrc.js 파일 생성 &amp; 작성</h4>
<ul>
<li>프로젝트 폴더 밑에 <code>.eslintrc.js</code> 파일을 만들고 이하 내용을 입력한다.</li>
</ul>
<pre><code class="language-js">module.exports = {
  root: true, // 프로젝트의 루트 디렉토리에서 이 설정 파일을 찾는 것을 나타낸다.
  env: {
    browser: true, // 브라우저 환경에서의 전역 변수 사용을 허용
    node: true, // Node.js 환경에서의 전역 변수 사용을 허용
    jest: true, // Jest 테스트 환경에서의 전역 변수 사용을 허용
  },
  extends: [
    &#39;plugin:@typescript-eslint/eslint-recommended&#39;, // @typescript-eslint/eslint-plugin의 권장 설정을 확장
    &#39;plugin:@typescript-eslint/recommended&#39;, // @typescript-eslint/eslint-plugin의 추가적인 권장 설정을 확장
  ],
  plugins: [&#39;prettier&#39;, &#39;@typescript-eslint&#39;], // 프로젝트에 사용할 ESLint 플러그인을 지정
  rules: { // rules 내부 내용들은 옵션이다.
    &#39;prettier/prettier&#39;: [
      &#39;error&#39;,
      {
        singleQuote: true, // 작은따옴표를 사용하여 문자열을 표시
        tabWidth: 2, // 들여쓰기에 사용되는 탭의 너비 2
        printWidth: 80, // 줄 바꿈을 할 때 최대 줄 폭 80
        bracketSpacing: true, // 중괄호({}) 앞뒤에 공백을 추가
        arrowParens: &#39;avoid&#39;, // 화살표 함수에서 매개변수 괄호를 생략가능한 상황일 때는 생략
      },
    ],
    &#39;@typescript-eslint/no-explicit-any&#39;: &#39;off&#39;, // any 타입 사용 허용
    &#39;@typescript-eslint/explicit-function-return-type&#39;: &#39;off&#39;, // 명시적인 함수 반환 타입을 요구하지 않는다.
    &#39;prefer-const&#39;: &#39;off&#39;, // let을 사용 허용
  },
  parserOptions: {
    parser: &#39;@typescript-eslint/parser&#39;, // TypeScript 파싱을 위해 @typescript-eslint/parser를 사용
  },
};</code></pre>
<p>해당 파일 내부에는 <code>prettier</code>와 <code>typescript-eslint</code>에 대한 설정이 되어 있으며, 리액트를 위한 설정도 일부 첨가되어 있다. </p>
<p><code>rules</code> 내에 작성이 되어 있는 내용들은 옵션으로 전부 작성할 필요 없이 작성해도 되고, 작성하지 않아도 상관없다.</p>
<h2 id="🗂️nbsptypescript의-타입">🗂️&amp;nbspTypeScript의 타입</h2>
<hr>
<p>타입스크립트는 자바스크립트와 거의 동일한 데이터 타입을 지원한다.</p>
<h3 id="boolean-불리언-타입">Boolean (불리언) 타입</h3>
<hr>
<p><code>boolean</code> 값이라고 불리는 참(<code>true</code>) , 거짓 (<code>false</code>) 값이다.</p>
<pre><code class="language-ts">let isShow: Boolean = true;
let isDone: Boolean = false;</code></pre>
<h3 id="number-숫자-타입">Number (숫자) 타입</h3>
<hr>
<p>정수와 실수의 구분 없이 Number타입 하나로 표기하며 이 외에 <code>bigint</code>도 지원한다.</p>
<pre><code class="language-ts">let number1: number = 5;
let number2: number = 0.7;</code></pre>
<h3 id="string-문자열-타입">String (문자열) 타입</h3>
<hr>
<p>큰따옴표 (<code>”</code>), 작은따옴표(<code>’</code>) 를 사용해 문자열 데이터를 표현할 수 있다. 
템플릿 리터럴을 사용해 여러 줄에 걸쳐 문자열을 작성할 수도 있다.</p>
<pre><code class="language-ts">let firstName: string = “coding”;
let lastName: string = ‘kim’;
let longString: string = `Kimcoding is a developer.
He is 20 years old.`</code></pre>
<h3 id="array-배열-타입">Array (배열) 타입</h3>
<hr>
<p>값들을 배열로 다룰 수 있게 할 수 있으며 두가지 방법으로 배열 타입을 선언할 수 있다.</p>
<h4 id="방법-1">방법 1</h4>
<p>배열의 요소들을 나타내는 타입 뒤에 배열을 나타내는 <code>[]</code> 을 쓰는 방식이다. </p>
<pre><code class="language-ts">let items: string[] = [“apple”, “banana“, “grape”];</code></pre>
<h4 id="방법-2">방법 2</h4>
<p>제네릭 배열 타입을 사용하는 방식이다. </p>
<pre><code class="language-ts">let numberList: Array&lt;number&gt; = [4, 7, 100];</code></pre>
<p><code>Array</code> 를 먼저 작성한뒤, <code>&lt;&gt;</code> 안에 배열의 요소들을 나타내는 타입을 작성한다.
배열 타입은 기본적으로 하나의 타입만 작성할 수 있으며 타입을 혼용해서 작성하는 것은 불가하다.</p>
<h3 id="tuple-튜플-타입">Tuple (튜플) 타입</h3>
<hr>
<p>튜플타입을 사용하면 요소의 타입과 개수가 고정된 배열을 표현할 수 있다. </p>
<pre><code class="language-ts">let user: [string, number, boolean] = [“kimcoding”, 20, true];</code></pre>
<p>배열의 index 마다 타입이 정해져 있어 정확한 index에 접근해야한다.</p>
<p>( JavaScript에서도 튜플 타입을 지원한다. TypeScript와 마찬가지로 여러개의 값을 가진 배열을 나타내는 데에 사용하지만 튜플 타입을 명시적으로 선언할 수 없어 개발자가 직접 튜플의 각 요소의 타입을 확인하고 유추해야해 타입에러 발생 확률이 높아진다. )</p>
<h3 id="object-객체-타입">Object (객체) 타입</h3>
<hr>
<p>원시 타입이 아닌 타입을 나타내는 <code>object</code> 타입은 모든 객체를 수용하는 타입으로, 객체의 프로퍼티 타입들이 <code>any</code> 로 지정되어 어떠한 프로퍼티라도 추가할 수 있다. 하지만 이는 타입 안정성을 보장하지 않기에 권장하지 않는 방법이다. </p>
<p>그렇기에 객체의 프로퍼티 타입들을 각기 명시해 주는 것이 좋다.</p>
<pre><code class="language-ts">let user: {name: string, age: number} = {
    name: “kimcoding”,
    age: 20
}</code></pre>
<p>이렇게 <code>key-value</code>에 구체적인 타입까지도 지정할 수 있다.</p>
<h3 id="any-타입">Any 타입</h3>
<hr>
<p>클라이언트에서 유저로부터 받은 데이터 및 서드파티 라이브러리에서 들어오는 값인 경우 알지 못하는 타입일 수 있는 등의 알지 못하는 타입을 표현해야 할 때, <code>any</code> 타입을 사용 할 수 있다.</p>
<pre><code class="language-ts">let maybe: any = 4;</code></pre>
<p><code>any</code>타입을 사용하면 변수에 값을 재할당할 시 타입에 구애받지 않고 값을 재할당할 수 있다.</p>
<p>또한 엄격한 타입 검사를 진행하지 않아 실제 할당된 값이 가지지 않는 메서드및 프로퍼티로 접근해도 에러가 나지 않지만 실제 할당된 값이 가지지 않는 메서드 및 프로퍼티이기에 <code>undefined</code> 값이 반환된다.</p>
<p><code>any</code> 타입은 타입의 일부만 알고, 전체는 알지 못할 때에 유용하게 사용할 수 있다. </p>
<h2 id="📝-nbsp-typescript의-함수">📝 &amp;nbsp TypeScript의 함수</h2>
<hr>
<p>TypeScript의 함수는 JavaScript와 마찬가지로 기명 함수(named function) 와 화살표 함수 (arrow function) 등으로 만들 수 있다.</p>
<pre><code class="language-ts">// named function
function add(x: number, y: number) : number {
    return x + y;
}

// arrow function
let add = (x: number, y: number) : number =&gt; {
    return x + y;
}</code></pre>
<p>타입추론 기능을 활용하지 않는다고 가정했을 때, TypeScript에서 함수를 표현할 때는 매개변수의 타입과 반환 타입을 명시해야한다.  </p>
<p>만일 함수에 리턴값이 없다면 <code>void</code>를 사용하여 작성할 수 있다.</p>
<pre><code class="language-ts">let printAnswer = (): void =&gt; {
    console.log(“yes”);
}</code></pre>
<p>또한 매개변수의 개수에 맞춰 전달인자를 전달해야 한다. </p>
<p>전달인자를 전달하지 않거나 <code>undefined</code>를 전달했을 때 할당될 매개변수의 값을 정해놓을 수 있으며 JavaScript의 <code>default parameter</code>와 같은 동작을 한다. </p>
<pre><code class="language-ts">let greeting = (firstName: string, lastName=“kim”): string =&gt; {
    return `hello, ${firstName} ${lastName}`;
}

// 정상적으로 작동한다.
greeting (‘coding’, undefined);</code></pre>
<p>선택적 매개변수를 원한다면 매개변수의 이름 끝에 <code>?</code>를 붙이면 된다.</p>
<pre><code class="language-ts">let greeting = (firstName: string, lastName?: string): string =&gt; {
    return `hello, ${firstName} ${lastName}`;
}

// 정상적으로 작동한다. 
greeting(‘coding’)</code></pre>
<p>이때, 뒤의 매개변수는 <code>undefined</code>로 반환된다. </p>
<h2 id="📚-nbsp-typescript의-연산자-활용-타입">📚 &amp;nbsp TypeScript의 연산자 활용 타입</h2>
<hr>
<p>TypeScript는 연산자를 이용해 타입을 정할 수 있다. <code>|</code> 연산자를 이용한 타입을 유니온 (Union) 타입, <code>&amp;</code>연산자를 이용한 타입은 인터섹션 (Intersection) 타입이라고 부른다.</p>
<h2 id="📕-nbsp-유니온-union-타입">📕 &amp;nbsp 유니온 (Union) 타입</h2>
<hr>
<p>유니온 타입은 <code>|</code> 연산자를 이용하며 둘 이상의 타입을 합쳐 <code>number | string</code> 같은 형식으로 사용한다. 자바스크립트의 OR 연산자와 같이 “A 이거나 B 이다.” 라는 의미의 타입이다. </p>
<pre><code class="language-ts">function printValue (value: number|string): void {
    if (typeof value === “number”) {
        console.log(`The value is a number: ${value}`);
    } else {
        console.log(`The value is a string: ${value}`);
    }
}

printValue(10); // The value is a number: 10
printValue(“hello”); // The value is a string: hello</code></pre>
<h3 id="유니온-union-타입의-장점">유니온 (Union) 타입의 장점</h3>
<hr>
<ul>
<li><p>타입을 추론할 수 있어 타입에 관련된 API를 쉽게 자동완성으로 얻어낼 수 있다. </p>
</li>
<li><p>코드의 가독성을 높일 수 있다.</p>
</li>
</ul>
<h3 id="유니온-union-타입-사용시-유의할-점">유니온 (Union) 타입 사용시 유의할 점</h3>
<hr>
<ul>
<li>유니온에 있는 모든 타입에 공통인 멤버들에만 접근할 수 있다.</li>
<li>나머지 프로퍼티에도 접근하고 싶다면 타입 가드를 사용해야한다.<ul>
<li>타입가드(Type Guard) <ul>
<li>TypeScript 에서 타입을 보호하기 위해 사용되는 기능중 하나 </li>
<li>특정 코드 블록에서 타입의 범위를 제한해 해당 코드 블록 안에서 타입 안정성을 보장해 준다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-ts">function askSomeone(someone: Developer | Person) {
    if (‘skill’ in someone) {
        console.log(someone.skill);
    }
    if (‘age’ in someone) {
        console.log(someone.age);
    }
}</code></pre>
<p>위의 코드는 타입를 사용해 작성된 코드이다.
TypeScript 에서는 <code>in</code> 연산자를 사용해 객체의 속성이 존재하는 지 여부를 검사할 수 있다. </p>
<h2 id="📗-nbsp-인터섹션-intersection-타입">📗 &amp;nbsp 인터섹션 (Intersection) 타입</h2>
<hr>
<p>인터섹션 (Intersection) 은 <code>&amp;</code> 연산자를 사용해 표현하며 둘 이상의 타입을 결합해 새로운 타입을 만드는 방법이다. </p>
<pre><code class="language-ts">interface Developer {
    name: string;
    skill: string;
}

interface Person {
    name: string;
    age: number;
}

function askSomeone (someone: Developer &amp; Person) {
    console.log(someone.age);
    console.log(someone.name);
    console.log(someone.skill);
}</code></pre>
<p>인터섹션 타입을 사용해 <code>Developer</code> 와 <code>Person</code> 을 하나의 타입으로 묶어 타입가드가 없어도 <code>askSomeone</code> 함수 내부에서 <code>Developer</code> 와 <code>Persone</code>의 프로퍼티에 전부 접근 할 수 있다.</p>
<p>그러나 인터섹션 타입은 <code>Developer</code> 와 <code>Person</code>이라는 새로운 합집합을 만들어 내는 것이기 때문에 전달인자를 전달할 때 모든 프로퍼티를 전부 보내줘야 한다. </p>
<pre><code class="language-ts">askSomeone({name: ‘김코딩’ , skill: ‘웹 개발’, age: 20});</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[State 끌어올리기]]></title>
            <link>https://velog.io/@1aba_can_opener/State-%EB%81%8C%EC%96%B4%EC%98%AC%EB%A6%AC%EA%B8%B0</link>
            <guid>https://velog.io/@1aba_can_opener/State-%EB%81%8C%EC%96%B4%EC%98%AC%EB%A6%AC%EA%B8%B0</guid>
            <pubDate>Mon, 01 May 2023 23:28:52 GMT</pubDate>
            <description><![CDATA[<h2 id="역방향-데이터-흐름-추가">역방향 데이터 흐름 추가</h2>
<hr>
<p>단방향 데이터 흐름이라는 원칙에 따라, 하위 컴포넌트는 상위 컴포넌트로부터 전달받은 데이터의 형태 혹은 타입이 무엇인지말 알 수 있다. 데이터가 어떻게 입력되었는지는 알지 못한다. 그러므로 하위 컴포넌트에서의 어떤 이벤트로 인한 상위 컴포넌트의 상태 변경은 마치 &quot;역방향 데이터 흐름과&quot; 같이 들릴 수 있다. </p>
<h2 id="상태-끌어올리기-state-lifting-up">상태 끌어올리기 (state-lifting up)</h2>
<hr>
<p>React는 기본적으로 단방향 데이터 흐름이라는 원칙을 가진다. 상위 컴포넌트에서 하위로는 이동할 수 있지만 반대로는 불가하다. 그러나 종종 동일한 데이터에 대한 변경사항을 여러 컴포넌트에 반영할 필요가 생긴다. </p>
<p>이 때, state 끌어올리기 개념으로 데이터 변경사항을 상위 컴포넌트로 전달할 수 있다. 데이터를 직접 상위로 전달하는 것과는 다르게, state를 직접 전달하는 것이 아닌 state 갱신 함수를 전달 받아 해당 함수를 실행시키는 원리이다. 이는 React가 제시하는 &quot;역방향 데이터 흐름&quot;과 같은 흐름을 보이면서도 여전히 &quot;단방향 데이터 흐름&quot;의 원칙에 부합하는 해결 방법이다. </p>
<blockquote>
<p><strong>state-lifting up</strong>
상위 컴포넌트의 &quot;상태를 변경하는 함수&quot; 그 자체를 하위 컴포넌트로 전달하고, 이 함수를 하위 컴포넌트가 실행한다. </p>
</blockquote>
<p>만약 동일한 데이터에 대한 변경사항을 여러 컴포넌트에 반영해야할 필요가 있을땐 가장 가까운 공통 조상(컴포넌트)에서 상태 끌어올리기를 하는 것을 권장한다.</p>
<pre><code class="language-javascript">// state-lifting up의 예시

import React, { useState } from &quot;react&quot;;

const currentUser = &quot;김코딩&quot;;

function Twittler() {
  const [tweets, setTweets] = useState([
    {
      uuid: 1,
      writer: &quot;김코딩&quot;,
      date: &quot;2020-10-10&quot;,
      content: &quot;안녕 리액트&quot;
    },
    {
      uuid: 2,
      writer: &quot;박해커&quot;,
      date: &quot;2020-10-12&quot;,
      content: &quot;좋아 코드스테이츠!&quot;
    }
  ]);

  const addNewTweet = (newTweet) =&gt; {
    setTweets([...tweets, newTweet]);
  }; // 이 상태 변경 함수가 NewTweetForm에 의해 실행되어야 합니다.

  return (
    &lt;div&gt;
      &lt;div&gt;작성자: {currentUser}&lt;/div&gt;
      &lt;NewTweetForm onButtonClick = {addNewTweet} /&gt;
      &lt;ul id=&quot;tweets&quot;&gt;
        {tweets.map((t) =&gt; (
          &lt;SingleTweet key={t.uuid} writer={t.writer} date={t.date}&gt;
            {t.content}
          &lt;/SingleTweet&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}

function NewTweetForm({ onButtonClick }) {
  const [newTweetContent, setNewTweetContent] = useState(&quot;&quot;);

  const onTextChange = (e) =&gt; {
    setNewTweetContent(e.target.value);
  };

  const onClickSubmit = () =&gt; {
    let newTweet = {
      uuid: Math.floor(Math.random() * 10000),
      writer: currentUser,
      date: new Date().toISOString().substring(0, 10),
      content: newTweetContent
    };
    // TDOO: 여기서 newTweet이 addNewTweet에 전달되어야 합니다.
    onButtonClick(newTweet)
  };

  return (
    &lt;div id=&quot;writing-area&quot;&gt;
      &lt;textarea id=&quot;new-tweet-content&quot; onChange={onTextChange}&gt;&lt;/textarea&gt;
      &lt;button id=&quot;submit-new-tweet&quot; onClick={onClickSubmit}&gt;
        새 글 쓰기
      &lt;/button&gt;
    &lt;/div&gt;
  );
}

function SingleTweet({ writer, date, children }) {
  return (
    &lt;li className=&quot;tweet&quot;&gt;
      &lt;div className=&quot;writer&quot;&gt;{writer}&lt;/div&gt;
      &lt;div className=&quot;date&quot;&gt;{date}&lt;/div&gt;
      &lt;div&gt;{children}&lt;/div&gt;
    &lt;/li&gt;
  );
}

export default Twittler;</code></pre>
<br>
위의 예시 코드는 

<ol>
<li><p><code>NewTweetForm</code>    에서 Props를 <code>{ onButtonClick }</code>    으로 받아온다.</p>
</li>
<li><p><code>onClick</code> 이벤트가 발생시 <code>onClickSubmit</code> 함수가 실행된다.</p>
</li>
<li><p><code>newTweet</code>을 <code>tweets</code> 형식에 맞는 객체로 세팅한다.</p>
</li>
<li><p><code>NewTweetForm</code> 에서 props로 받은 <code>onButtonClick</code> 의 전달인자로 <code>newTweet</code>을 넘겨 실행해준다.</p>
</li>
<li><p><code>Twittler</code>에 <code>onButtonClick = {addNewTweet}</code> 의 <code>addNewTweet</code>    함수가 실행된다.</p>
</li>
<li><p><code>addNewTweet</code>에서 <code>onButtonClick</code> 의 전달인자 <code>newTweet</code>을 사용해  <code>setTweets</code>    함수를 실행한다.</p>
</li>
<li><p><code>tweet</code>이 <code>[...tweets, newTweet]</code>으로 갱신되어 <code>SingleTweet</code> 에 props가 전달된다.</p>
</li>
<li><p><code>SingleTweet</code> 의 <code>&lt;li&gt;</code>가 값이 채워진채 리턴된다.</p>
<br>

</li>
</ol>
<p>이렇게 진행되는 코드이며 몇 부분을 생략하고 아주 간단하고 비슷한 느낌만 나게끔 익숙한 javascript문법을 이용해 내 식대로 써보자면
<br></p>
<pre><code class="language-javascript">function onButtonClick (newTweet) { // 4. `onButtonClick` 내부 함수의 전달인자로 넘기고 넘겨서 
  addNewTweet (newTweet) {
    setTweets(newTweet) {
      return tweets = [...tweets, newTweet] // 5. `tweets` 를 `newTweet` 을 포함한 배열로 리턴
    }
  }
}

btn.eventListener(onclick, function () { // 1. `onClick`    이벤트 발생시, 함수(== onClickSubmit) 실행
    let newTweet = { // 2. `newTweet` 을 생성한뒤
      ...생략
    };
    onButtonClick(newTweet) // 3. `onButtonClick` 함수에 전달인자로 `newTweet` 을 넘기고 실행
  };
)</code></pre>
<p>이렇게 된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 표준 & 웹 접근성]]></title>
            <link>https://velog.io/@1aba_can_opener/%EC%9B%B9-%ED%91%9C%EC%A4%80%EC%9D%98-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@1aba_can_opener/%EC%9B%B9-%ED%91%9C%EC%A4%80%EC%9D%98-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Wed, 26 Apr 2023 07:27:35 GMT</pubDate>
            <description><![CDATA[<h2 id="인터넷">인터넷</h2>
<hr>
<p>많이들 웹이라고 하면 인터넷을 떠올린다. 하지만 인터넷은 웹 기반으로 작동하는 것이 아니다. 인터넷이 웹보다 좀 더 포괄적인 개념으로 &#39;전 세계적으로 연결되어 있는 컴퓨터 네트워크 통신망&#39;을 의미하며 웹, 온라인게임, 모바일 앱, 이메일 등 네트워크를 사용하는 다양한 서비스들을 모두 포함하므로 웹과 인터넷을 혼동하지 않도록 주의해야한다. </p>
<h2 id="웹">웹</h2>
<hr>
<p>웹이란 &#39;공간&#39; 이라는 단어로 정의할 수 있다. 문서, 이미지, 영상 등 다양한 정보를 여러 사람들과 공유할 수 있는 &#39;공간&#39;이다. </p>
<p>대표적인 예로 웹툰의 어원 역시 &#39;Worlds Wide Web + Cartoon&#39; 을 합친 것으로 인터넷만 연결되어 있다면 웹이라는 공간에서 만화를 보고 댓글을 다는등의 행위가 가능하다.</p>
<h2 id="웹-표준">웹 표준</h2>
<hr>
<p>웹 표준이란 W3C(<a href="https://www.w3.org/">World Wide Web Consortium</a>)에서 권고하는 &#39;웹에서 표준적으로 사용되는 기술이나 규칙&#39;으로 사용자가 어떠한 운영체제나 브라우저를 사용하더라도 웹페이지가 동일하게 보이고 정상적으로 작동할 수 있도록 하는 웹 페이지 제작 기법을 담고있다. 웹 개발에 사용되는 언어인 HTML, CSS, JavaScript 등의 기술을 다룬다. </p>
<p>크롬, 엣지, 사파리, 오페라, 파이어폭스 등 최신 웹 브라우저들은 모두 웹 표준을 지원하여 웹 쵸준에 맞춰 웹 페이지를 작성하면 어떤 브라우저든 동일한 결과물을 얻을 수 있다. 따라서 가능한 웹표준을 준수한 웹페이지를 개발하기 위해 노력하는 것이 좋다.</p>
<h3 id="웹-표준-등장배경">웹 표준 등장배경</h3>
<hr>
<p>2000년대에는 웹이라는 공간에서 여러 사람들이 동일한 행위를 하거나 볼 수 있는 일이 쉽지 않았다. 인터넷 익스플로러에서는 작동 되지만 사파리나 파이어폭스 같은 다른 브라우저에서는 작동이 되지 않는 등 브라우저간 호환이 되지 않는 경우가 종종 발생했고 이러한 상황을 막고 웹을 정상적으로 구동시키기 위해서는 개발자들이 각 브라우저마다 따로 개발을 해주어야만 했는데 이런 수고를 없애고 웹 개발의 형식을 통일시킨 것이 바로 웹 표준이다.</p>
<h3 id="웹-표준의-장점">웹 표준의 장점</h3>
<hr>
<h4 id="유지-보수의-용이성">유지 보수의 용이성</h4>
<p>웹 표준으로 HTML, CSS, JavaScript 등의 사용법을 정리하기 이전에는 구조, 표현, 동작이 뒤섞인 코드도 많았고 이 코드의 어느 한 부분을 수정하기 위해서는 전부를 고쳐야하는 경우도 있었다. 하지만 각 영역이 분리되며 유지보수가 용이해졌고 코드가 경량화되면서 트래픽 비용이 감소하는 효과도 생겼다.</p>
<h4 id="웹-호환성-확보">웹 호환성 확보</h4>
<p>웹 사이트가 특정 운영체제나 브라우저에 종속적이라면 그 외 환경에서는 정상적으로 사용이 불가한 문제점이 발생한다. 하지만 웹 표준을 준수하여 제작할 시 웹 브라우저의 종류나 버전, 운영 체제나 사용기기 에 상관 없이 항상 동일한 결과가 나오도록 할 수 있다.</p>
<h4 id="검색-효율성-증대">검색 효율성 증대</h4>
<p>웹 표준에 맞춰 웹 사이트를 작성하는 것만으로도 검색 엔진에서 더 높은 우선 순위로 노출될 수 있다. 적절한 HTML 요소의 사용, 웹 페이지에 대한 정확한 정보 작성 등 검색 효율성과 관련된 내용도 웹 표준에서 다루고 있기 때문이다. </p>
<h4 id="웹-접근성-향상">웹 접근성 향상</h4>
<p>브라우저의 종류, 운영체제의 종류, 기기의 종류 등 웹에 접근할 수 있는 환경은 매우 다양하며 웹을 사용하는 사람들 또한 다양하다. 이 모든 환경과 사용자에 맞춰 웹 페이지를 개발하는 일은 쉽지 않다. 하지만 웹 표준에 맞춰 개발함으로 이러한 문제를 해결 할 수 있다.</p>
<h2 id="웹-접근성">웹 접근성</h2>
<hr>
<p>일반적으로 웹 접근성은 장애인, 고령자 등이 웹 사이트에서 제공하는 정보에 비장애인과 등등하게 접근하고 이해할 수 있도록 보장하는 것을 뜻하지만 비장애인도 정보 접근에 제한을 받는 불편함을 겪을 수 있다. 따라서 웹 접근성의 궁극적인 목적은 어떤 상황이든, 어떤 사람이든 정보를 제공받지 못하는 경우가 없도록 하는 것이다. </p>
<h3 id="웹-접근성-실태">웹 접근성 실태</h3>
<hr>
<p>안타깝게도 우리나라의 웹 접근성 수준은 높지 않다. 2021년 기준, 일반 국민의 정보화 수준을 100이라고 할 때, 장애인, 고령층 등 디지털 취약 계층의 정보화 지수는 75.4점, 국내 웹 사이트들의 웹 접근성 평균 점수는 60.8점이었다.</p>
<p>이러한 문제점은 국내 온라인 쇼핑몰 사이트를 보아도 쉽게 찾을 수 있다. 상품의 상세 정보가 이미지로 올라와 있는 경우가 많기 때문이다. 이미지 속 글자를 인식하여 텍스트로 변환해 스크린 리더가 읽을 수 있게 만드는 기능을 제공하는 사이트도 있지만 변환 과정에서 시간이 소요되기에 정보 접근에 시간이 오래 걸린다. </p>
<h3 id="웹-접근성을-갖추면-얻을-수-있는-효과">웹 접근성을 갖추면 얻을 수 있는 효과</h3>
<hr>
<h4 id="사용자층-확대">사용자층 확대</h4>
<p>웹 접근성 확보시 장애인, 고령자 등 정보 소외 계층도 웹 사이트를 자유롭게 이용할 수 있어 사이트의 이용자를 늘릴 수 있고 새로운 고객층을 확보 할 수 있게 된다. 실제로 웹 접근성 향상을 통해 매출이 증가한 해외 쇼핑몰 사례도 있으며 국내 온라인 쇼핑몰에서도 노년층의 매출이 증가 추세를 보이고 있기에 고려해야할 점이다.</p>
<h4 id="다양한-환경-지원">다양한 환경 지원</h4>
<p>소외 계층이 아니어도 운전중이라 화면을 보기 어렵거나 마우스를 사용할 수 없는 상황 등 정보에 접근하기 어려운 상황은 충분히 있을 수 있다. 때문에 웹 접근성 향상시 다양한 환경, 다양한 기기에서의 웹 사이트 사용이 자유롭게되어 서비스의 사용 범위가 확대되면 서비스의 이용자 수 증가를 기대할 수 있다.</p>
<h4 id="사회적-이미지-향상">사회적 이미지 향상</h4>
<p>웹 접근성 확보를 통해 기업이 정보 소외 계층을 위한 사회 공헌 및 복지 향상에 힘쓰고 있을을 보여준다면 기업의 사회적 이미지가 향상, 그만큼 이용자 수 증가와 충성 고객 확보로 이어질 가능성이 높아진다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Effect Hook]]></title>
            <link>https://velog.io/@1aba_can_opener/Effect-Hook-y3oyns1g</link>
            <guid>https://velog.io/@1aba_can_opener/Effect-Hook-y3oyns1g</guid>
            <pubDate>Mon, 24 Apr 2023 16:36:20 GMT</pubDate>
            <description><![CDATA[<h2 id="🪝-react-hook">🪝 React Hook</h2>
<hr>
<p>React에서 Hook이란, 함수형 컴포넌트에서 사용되는, state와 관련된 기술들을 모아서 일컫는 말이며 Hook은 class를 작성하지 않고도 state와 다른 React의 기능들을 사용할 수 있게 해준다. 대표적으로 <code>useState()</code> 와 <code>useEffect()</code> 가 있다. </p>
<blockquote>
<p>Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수입니다. Hook은 class 안에서는 동작하지 않습니다. 대신 class 없이 React를 사용할 수 있게 해주는 것입니다.</p>
</blockquote>
<h3 id="⚠️-hook을-쓸-때-주의할-점">⚠️ Hook을 쓸 때 주의할 점</h3>
<ul>
<li>최상위 (at the Top Level)에서만 Hook을 호출한다.<ul>
<li>반복문, 조건문 혹은 중첩된 함수 내에서는 Hook을 호출 할 수 없다. </li>
<li>조건부로 effect를 실행하기를 원한다면, 조건문을 Hook 내부에 넣어야 한다.</li>
<li>Early return이 실행되기 전에 항상 React 함수의 최상위에서 Hook 을 호출해야 한다.</li>
<li>이를 따라야 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출되는 것이 보장된다.</li>
</ul>
</li>
<li>React 함수 내에서 Hook 을 호출한다.<ul>
<li>Hook 을 일반적인 Javascript함수에서 호출 하면 안된다.</li>
<li>Custom Hook에서의 Hook호출은 가능하다.</li>
</ul>
</li>
</ul>
<h2 id="😶🌫️-componentdidxxx">😶‍🌫️ componentDidXxx()</h2>
<hr>
<p>React Hook 이 나오기전 클래스 컴포넌트의 <code>componentDidMount ()</code> 나 <code>componentDidUpdate ()</code> 와 같은 Life Cycle Hook 함수를 사용해 Side Effect를 처리했다. </p>
<pre><code class="language-javascript">// Hook 등장 전의 Side Effect 처리

import React, { Component } from &quot;react&quot;;

class UserListClass extends Component {
  state = {
    loading: true,
    users: [],
  };

  componentDidMount() {
    fetch(&quot;https://jsonplaceholder.typicode.com/users&quot;)
      .then((response) =&gt; response.json())
      .then((users) =&gt; this.setState({ users, loading: false }));
  }

  render() {
    const { loading, users } = this.state;
    if (loading) return &lt;div&gt;Loading...&lt;/div&gt;;
    return (
      &lt;ul&gt;
        {users.map((user) =&gt; (
          &lt;li key={user.id}&gt;{user.name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }
}</code></pre>
<p>예시를 살펴보자면 외부 API 연동을 통해 사용자 목록을 조회하는 React 컴포넌트가 있다. 이 클래스 컴포넌트는 로딩 여부와 사용자 목록을 <code>this.state</code> 필드의 <code>loading</code>과 <code>users</code> 속성에 각각 저장하고 있다. </p>
<p>이 컴포넌트가 최초 렌더링될 때는 <code>loading</code> 의 초기 값이 <code>true</code> 라서 <code>Loading...</code> 이라는 메시지가 화면에 나타난다. 하지만 곧 <code>componentDidMount()</code> 함수가 호출되면 API가 호출되어 그 응답 결과가 <code>users</code>  속성에 할당되고 <code>loading</code> 이 <code>false</code> 로 업데이트 된다. 따라서 화면에 있던 <code>Loading...</code> 메시지는 사라지고, 대신 사용자 이름들이 나타나게 된다. </p>
<p>이런 클래스 기반 컴포넌트는 함수 기반 컴포넌트에 비해 복잡하고 따라서 오류가 발생하기 쉽고 유지 보수가 힘들기 때문에 많은 React 개발자들은 이렇게 간단한 Side Effect 구현 조차도 클래스 기반 컴포넌트로 작성해야 한다는 점에 대해서 불평했고 때문에 React Hook의 <code>useEffect</code> 가 나오게 되었다. </p>
<h2 id="✨-useeffect">✨ useEffect()</h2>
<hr>
<p>useEffect() 함수는 React component가 렌더링 될 때마다 특정 작업(Sied effect)을 실행할 수 있도록 하는 리액트이며 이를 사용하면 함수형 컴포넌트에서도 클래스형 컴포넌트에서 사용했던 생명주기 메서드를 사용할 수 있게 되었다. </p>
<h3 id="useeffect-함수-불러오기">useEffect 함수 불러오기</h3>
<blockquote>
<p>import React, { useEffect } from &quot;react&quot;;</p>
</blockquote>
<p>useState와 마찬가지로 함수 불러오기를 통해 함수를 불러와야만 사용이 가능하다.</p>
<h3 id="기본-형태">기본 형태</h3>
<hr>
<blockquote>
<p>useEffect(function, deps)</p>
</blockquote>
<h4 id="function">function</h4>
<p>실행하고자 하는 함수</p>
<h4 id="deps-dep1-de2-">deps ([dep1, de2, ...])</h4>
<p>배열형태, fuction을 실행시킬 조건</p>
<ul>
<li>deps 에 특정값을 넣게되면 컴포넌트가 mount 될 때, 지정한 값이 업데이트 될 때 useEffect를 실행한다.</li>
</ul>
<h3 id="첫번째-인자-function">첫번째 인자 (function)</h3>
<hr>
<p><code>useEffect</code>의 첫번째 인자는 함수이다. 해당 함수내에서 side effect를 실행하면 되며 실행 조건이 있다.</p>
<h4 id="실행-조건">실행 조건</h4>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/e3d8f12f-7a66-4b9f-ae93-9c1c043d4932/image.png" alt=""></p>
<ul>
<li>컴포넌트 생성 후 처음 화면에 렌더링</li>
<li>컴포넌트에 새로운 props가 전달되며 렌더링</li>
<li>컴포넌트에 상태 (state)가 바뀌며 렌더링</li>
</ul>
<p>새롭게 컴포넌트가 렌더링 될 때 Effect Hook이 실행된다고 볼 수 있다.</p>
<h3 id="두번째-인자-deps">두번째 인자 (deps)</h3>
<hr>
<p><strong>조건부 effect 발생</strong>을 실행시키기 위해 필요한 <code>useEffect</code> 의 두번째 인자는 배열이다. <strong>이 배열은 조건을 담고 있는데</strong> 여기서 조건은 boolean형태의 표현식이 아니라 <strong>어떤 값의 변경이 일어날 때를 의미</strong>한다. 배열엔 <strong>어떤 값의 목록이 들어가며 종속성 배열 (dependency array)</strong> 이라고 부른다. </p>
<p>이 때문에 <code>useEffect</code>는 <strong>화면에 첫 렌더링될 때</strong>, 그리고 <strong>종속성 배열의 <code>value</code> 값이 바뀔 때</strong> 라는 실행조건을 가지게 된다. 따라서 모든 state가 아닌 <strong>특정 state에 관해서만 Side effect를 실행</strong>시킬 수 있다. </p>
<h3 id="useeffect-사용법">useEffect 사용법</h3>
<hr>
<p><code>useEffect</code> 에 대해서 익혔으니 이제 이를 응용해 여러 경우에서의 사용법을 알아보자.</p>
<h4 id="컴포넌트가-mount-되었을-때-나타날-때">컴포넌트가 mount 되었을 때 (나타날 때)</h4>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;렌더링 될 때마다 실행&quot;);
});</code></pre>
<p>deps 부분을 생략시 해당 컴포넌트가 렌더링 될 때마다 <code>useEffect</code> 가 실행된다. </p>
<h4 id="컴포넌트가-한번만-실행되었으면-할-때-처음-생성시에만">컴포넌트가 한번만 실행되었으면 할 때 (처음 생성시에만)</h4>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;맨 처음 렌더링될 때 한번 만 실행&quot;);
},[]);</code></pre>
<p>deps 부분에 빈배열을 넣을시 해당 컴포넌트가 처음 생성시에만 <code>useEffect</code> 가 실행된다.</p>
<h4 id="컴포넌트가-update-되었을-때-props-state-변경">컴포넌트가 update 되었을 때 (props, state 변경)</h4>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(name);
  console.log(&quot;name이라는 값이 업데이트 될 때만 실행&quot;);
},[name]);</code></pre>
<p>특정값이 업데이트 될 때만 실행하고 싶을 땐 deps위치의 배열안에 실행조건을 넣어주어야한다. 업데이트뿐만 아니라 마운터 될 때도 실행되므로 업데이트 될 때만 실행된다. </p>
<h4 id="컴포넌트가-update-되었을-때만-실행되었으면-할-때">컴포넌트가 update 되었을 때만 실행되었으면 할 때</h4>
<pre><code class="language-javascript">const mounted = useRef(false);
useEffect(() =&gt; {
  if (!mounted.current) {
    mounted.current = true;
  } else {
    console.log(name);
    console.log(&quot;업데이트 될 때만 실행&quot;);
  };
},[name]);</code></pre>
<p><code>useRef</code> 는 리렌더링 하지 않고 컴포넌트의 속성만 조회&amp;수정한다. 이를 이용해 컴포넌트 안의 변수를 관리하면 리렌더링을 막을 수 있다.</p>
<h4 id="컴포넌트가-upmount-되었을-때-사라질-때--update-되기-직전에">컴포넌트가 upmount 되었을 때 (사라질 때) &amp; update 되기 직전에</h4>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;컴포넌트 나타남&quot;);
  console.log(name);
  return () =&gt; {
    console.log(&quot;cleanUP 함수&quot;);
  };
});</code></pre>
<p><code>useEffect</code> 는 함수를 반환할 수 있는데 이 함수를 <code>cleanUP</code>이라고 한다. 만약 unmount 될 때만 <code>cleanUp</code> 함수를 실행시키고 싶다면 deps에 빈배열을 넣으면 된다. 만약 특정 값이 업데이트되기 직전에 cleanUP 함수를 실행시키고 싶다면 deps에 해당 값을 넣어주면 된다.</p>
<pre><code class="language-javascript">// 예시
import React, { useEffect, useState } from &quot;react&quot;;

function UseEffect() {
  const [name, setName] = useState(&quot;초기 닉네임&quot;);

  useEffect(() =&gt; {
    console.log(&quot;컴포넌트 나타남&quot;);
    console.log(name);
    return () =&gt; {
      console.log(&quot;cleanUp 함수&quot;);
    };
  });

  const onClick = () =&gt; {
    setName(&quot;닉네임 변경&quot;);
  };
  return (
    &lt;div&gt;
      {name} &lt;button onClick={onClick}&gt;변경&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default UseEffect;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux]]></title>
            <link>https://velog.io/@1aba_can_opener/Redux</link>
            <guid>https://velog.io/@1aba_can_opener/Redux</guid>
            <pubDate>Mon, 24 Apr 2023 04:58:42 GMT</pubDate>
            <description><![CDATA[<h2 id="flux-패턴">Flux 패턴</h2>
<hr>
<p>Flux 패턴은 2014페이스북 F8 컨퍼런스에서 발표된 아키텍쳐로 Client-Side 웹 애플리케이션을 만들기 위해 사용하는 디자인 패턴이다.</p>
<h3 id="등장배경">등장배경</h3>
<p>페이스북이 Flux 패턴을 발표, 도입한 이유는 대규모 애플리케이션에서 데이터 흐름을 일관성 있게 관리함으로써 프로그램의 예측가능성(Predictability)을 높이기 위함이다. </p>
<p>기존 애플리케이션들이 보편 적으로 사용한던 MVC 패턴은, Model, View, Controller의 약자로 Model에 데이터를 저장하고, Controller를 이용하여 Model의 데이터를 관리(CRUD)해, Model의 데이터가 변경되면 View로 전달되어 사용자에게 보여진다. 또한 사용자가 View를 통해 데이터를 입력하면 View 역시 Model을 업데이트할 수 있다는 점을 통해 데이터가 양방향으로 흐른다는 것을 알 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/905253a9-1b60-4e42-9748-029443e3e822/image.png" alt=""></p>
<p>MVC 패턴의 애플리케이션의 규모가 커진다면 다음과 같은 구조를 가지게 된다. View 가 다양한 상호작용을 위해 여러 개의 Model을 동시에 업데이트하고 Model 역시 여러개의 View에 데이터를 전달하는 상황이 발생한다. 한 Model이 업데이트되면 그에 따라 View 가 업데이트되고, 업데이트된 View가 또 다른 Model을 업데이트 하는 식의 흐름이 되어 버리는 것이다. 이렇게 많은 의존성을 가지면 Model의 개수가 많아질 수록 각 Model 에서 발생한 이벤트가 애플리케이션 전체로 퍼져나갈 때 예측이 힘들어진다. </p>
<p>페이스북은 이 문제의 해결 방안으로 단방향 데이터 흐름을 가지는 Flux 패턴을 고안해 낸 것이다. </p>
<h3 id="flux-패턴이란">Flux 패턴이란</h3>
<p>Flux는 사용자 입력을 기반으로 Action을 만들고 Action을 Dispatcher에 전달하여 Store(Model)의 데이터를 변경한 뒤 View에 반영하는 단방향의 흐름으로 애플리케이션을 만드는 아키텍처이다. </p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/4898bcd5-c0fa-4729-bf5d-cee9a516cda4/image.png" alt=""></p>
<h2 id="redux">Redux</h2>
<hr>
<p>상태 관리 라이브러리중 하나인 Redux는 Flux패턴의 후속 라이브러리로 Reducer 와 Flux를 결합해 나온 이름이다. Flux 패턴에서 몇 가지 제약 조건을 채택해 사용하며 전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있기 때문에 Props Drilling을 방지하기에 매우 효과적이며 React 없이도 사용할 수 있는 상태 관리 라이브러리이다.</p>
<h2 id="redux의-구조">Redux의 구조</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/79dccdee-3863-4226-b26f-38f6f9e3cb39/image.gif" alt=""></p>
<p>Redux는 다음과 같은 순서로 상태를 관리한다.</p>
<ol>
<li><p>상태가 변경되어야 하는 이벤트 발생시 변경될 상태에 대한 정보가 담긴 Action 객체 생성</p>
</li>
<li><p>해당 Action 객체는 Dispatch 함수의 인자로 전달</p>
</li>
<li><p>Dispatch 함수는 Action 객체를 Reducer 함수로 전달</p>
</li>
<li><p>Reducer 함수는 Action 객체의 값을 확인 후 그 값에 따라 전역 상태 저장소 Store의 상태 변경</p>
</li>
<li><p>상태 변경시 React는 화면을 렌더링</p>
</li>
</ol>
<p>Action → Dispatch → Reducer → Store 순서로 데이터가 단방향으로 흐르는 형식이다.</p>
<h3 id="store">Store</h3>
<hr>
<p>Store은 상태가 관리되는 오직 하나뿐인 저장소의 역할을 한다. Redux 앱의 state가 저장되어 있는 공간이며 <code>createStore</code> 메서드를 활용해 Reducer를 연결해서 Store를 생성할 수 있다. </p>
<pre><code class="language-js">import { createStore } from &#39;redux&#39;;

const store = createStore(rootReducer);</code></pre>
<p><a href="https://stackblitz.com/edit/react-jq4f2e?file=src%2FREADME.md">store 실습코드</a></p>
<h3 id="reducer">Reducer</h3>
<hr>
<p>Reducer 는 Dispatch 에게서 전달 받은 Action 객체의 <code>type</code>값에 따라서 상태를 변경시키는 함수다.</p>
<pre><code class="language-js">const count = 1

// Reducer를 생성할 때에는 초기 상태를 인자로 요구합니다.
const counterReducer = (state = count, action) =&gt; {

  // Action 객체의 type 값에 따라 분기하는 switch 조건문입니다.
  switch (action.type) {

    //action === &#39;INCREASE&#39;일 경우
    case &#39;INCREASE&#39;:
            return state + 1

    // action === &#39;DECREASE&#39;일 경우
    case &#39;DECREASE&#39;:
            return state - 1

    // action === &#39;SET_NUMBER&#39;일 경우
    case &#39;SET_NUMBER&#39;:
            return action.payload

    // 해당 되는 경우가 없을 땐 기존 상태를 그대로 리턴
    default:
      return state;
    }
}
// Reducer가 리턴하는 값이 새로운 상태가 됩니다.</code></pre>
<p>이때, Reducer 는 외부 요인으로 인해 기대한 값이 아닌 값으로 상태가 변경되는 일이 없어야하기에 <code>순수함수</code>여야 한다. </p>
<p>만약 여러개의 Reducer를 사용하는 경우, <code>combineRdcuers</code>메서드를 사용해 하나의 Reducer로 합쳐 줄 수 있다.</p>
<pre><code class="language-js">import { combineReducers } from &#39;redux&#39;;

const rootReducer = combineReducers({
  counterReducer,
  anyReducer,
  ...
});</code></pre>
<p><a href="https://stackblitz.com/edit/react-vcpexx?file=src%2FREADME.md">Reducer 실습 코드</a></p>
<h3 id="action">Action</h3>
<hr>
<p>Action 은 어떤 액션을 취할 것인지 정의해 놓은 객체다.</p>
<pre><code class="language-js">// payload가 필요 없는 경우
{ type: &#39;INCREASE&#39; }

// payload가 필요한 경우
{ type: &#39;SET_NUMBER&#39;, payload: 5 }</code></pre>
<p>여기서 <code>type</code> 은 필수로 지정해줘야한다. 해당 Action 객체가 어떤 동작을 하는지 명시해주는 역할을 하기 때문이며 대문자와 Snake Case로 작성한다. 여기에 필요에 따라 <code>payload</code> 를 작성해 구체적인 값을 전달한다.</p>
<p>보통 Action 을 직접 작성하기 보단 Action 객체를 생성하는 함수를 만들어 사용하는 경우가 많으며 이러한 함수를 액션생성자 (Action Creator) 라고 한다.</p>
<pre><code class="language-js">// payload가 필요 없는 경우
const increase = () =&gt; {
  return {
    type: &#39;INCREASE&#39;
  }
}

// payload가 필요한 경우
const setNumber = (num) =&gt; {
  return {
    type: &#39;SET_NUMBER&#39;,
    payload: num
  }
}</code></pre>
<p><a href="https://stackblitz.com/edit/react-heibmq?file=src%2FREADME.md">Action 실습 코드</a></p>
<h3 id="dispatch">Dispatch</h3>
<hr>
<p>Dispatch 는 Reducer 로 Action 을 전달해주는 함수이며 전달인자로 Action 객체가 전달된다. </p>
<pre><code class="language-js">// Action 객체를 직접 작성하는 경우
dispatch( { type: &#39;INCREASE&#39; } );
dispatch( { type: &#39;SET_NUMBER&#39;, payload: 5 } );

// 액션 생성자(Action Creator)를 사용하는 경우
dispatch( increase() );
dispatch( setNumber(5) );</code></pre>
<p>Action 객체를 전달받은 Dispatch 함수는 Reducer를 호출한다.</p>
<h3 id="redux-hooks">Redux Hooks</h3>
<hr>
<p>Redux Hook는 React-Redux에서 Redux를 사용할 때 활용할 수 있는 Hook 메서드를 제공한다. 그중에서 크게 <code>useSelector()</code> , <code>useDispatch</code> 이 두가제 메서드를 사용한다.</p>
<h4 id="usedispatch">useDispatch()</h4>
<p><code>useDispatch</code> 는 Action 객체를 Reducer로 전달해주는 Dispatch 함수를 반환하는 메서드다. 위의 Dispatch 예제코드에서의 dispatch함수도 <code>useDispatch</code> 를 사용한 예제이다.</p>
<pre><code class="language-js">import { useDispatch } from &#39;react-redux&#39;

const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2

dispatch( setNumber(5) )
console.log(counter) // 5</code></pre>
<p><a href="https://stackblitz.com/edit/react-mutcot?file=src%2FREADME.md">useDispatch 실습 코드</a></p>
<h4 id="useselector">useSelector()</h4>
<p><code>useSelector()</code>    는 컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드다</p>
<pre><code class="language-Js">// Redux Hooks 메서드는 &#39;redux&#39;가 아니라 &#39;react-redux&#39;에서 불러옵니다.
import { useSelector } from &#39;react-redux&#39;
const counter = useSelector(state =&gt; state)
console.log(counter) // 1</code></pre>
<p><a href="https://stackblitz.com/edit/react-nrvnzg?file=src%2FREADME.md">useSelctor 실습 코드</a></p>
<h3 id="실습">실습</h3>
<hr>
<p><a href="https://stackblitz.com/edit/react-vdpfak?file=README.md">Redux의 구조 실습 코드</a> </p>
<ul>
<li>Redux의 구조 실습 코드는 index.js에 작성되어 있다. 하지만 한 파일에 다양한 기능의 코드들을 작성하는 것은 코드의 가독성이 매우 나빠져 오류 발생 시 디버깅하기가 매우 어려워지기 때문에 바람직하지 않다. </li>
</ul>
<p><a href="https://stackblitz.com/edit/react-74uaa1?file=README.md">Redux의 구조 리팩토링 실습 코드</a></p>
<ul>
<li>Redux의 구조 실습 코드를 리팩토링한 Redux의 구조 리팩토링 실습 코드 는 리덕스 코드를 역할 별로 나눈 코드이다.</li>
</ul>
<h2 id="redux의-세가지-원칙">Redux의 세가지 원칙</h2>
<hr>
<p>Redux에는 세가지 원칙이 있다.</p>
<h4 id="single-source-of-truth">Single source of truth</h4>
<ul>
<li>동일한 데이터는 항상 같은 곳에서 가지고 와야한다.</li>
<li>Reduxs에는 데이터를 저장하는 <strong>Store</strong>라는 단 하나뿐인 공간이 있음과 연결되는 원칙이다.</li>
</ul>
<h4 id="state-is-read-only">State is read-only</h4>
<ul>
<li>상태는 읽기 전용이다.</li>
<li>React 에서 상태 갱신 함수로만 상태를 변경할 수 있었던 것처럼 Redux의 상태도 직접 변경이 불가하다는 의미이다.</li>
<li><strong>Action</strong> 객체가 있어야만 상태를 변경할 수 있음과 연결되는 원칙이다.</li>
</ul>
<h4 id="changes-are-made-with-pure-functions">Changes are made with pure functions</h4>
<ul>
<li>변경은 순수함수로만 가능하다.</li>
<li>상태가 기대한 값으로만 변경될 수 있도록 순수함수로 작성되어야하는 <strong>Reducer</strong> 와 연결되는 원칙이다.</li>
</ul>
<p>추가적인 정보를 원한다면? <a href="https://redux.js.org/">Redux 공식문서</a> / <a href="https://react-redux.js.org/">React-Redux 공식문서</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Props Drilling]]></title>
            <link>https://velog.io/@1aba_can_opener/Props-Drilling</link>
            <guid>https://velog.io/@1aba_can_opener/Props-Drilling</guid>
            <pubDate>Fri, 21 Apr 2023 05:34:11 GMT</pubDate>
            <description><![CDATA[<h2 id="props-drilling">Props Drilling</h2>
<hr>
<p><code>Props Drilling</code> 은 상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이 컴포넌트들은 props를 전달하는 용도로만 받는 현상을 의미한다. 
<img src="https://velog.velcdn.com/images/1aba_can_opener/post/dd6b50ab-0cb3-4662-8591-327825e49a94/image.png" alt=""></p>
<h3 id="props-drilling의-문제점">Props Drilling의 문제점</h3>
<hr>
<p>Props의 전달횟수가 5회 이내라면 Props Drilling은 큰 문제가 되지 않는다. 하지만 규모가 커지고 구조가 복잡해지면서 Props의 전달 과정이 늘어난다면 문제가 발생한다.</p>
<ul>
<li><p>코드의 가독성이 매우 나빠진다.</p>
</li>
<li><p>코드의 유지 보수가 힘들어 진다.</p>
</li>
<li><p>state 변경시 Props 전달에 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생해 웹 성능에 악영향을 끼칠 수 있다.</p>
</li>
</ul>
<h3 id="해결방법">해결방법</h3>
<hr>
<p>과도한 <code>Props Drilling</code> 을 방지하기 위한 방법은 아래와 같다.</p>
<ul>
<li><p>컴포넌트와 관련 있는 state 는 될 수 있으면 가까이 유지하는 방법</p>
</li>
<li><p>상태관리 라이브러리를 사용하는 방법</p>
<ul>
<li>상태 관리 라이브러리를 사용하기 되면 전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있기 때문에 <code>Props Drilling</code>을 방지하기에 매우 효과적이다. </li>
</ul>
</li>
</ul>
<h4 id="예시-1">예시 1</h4>
<hr>
<p><a href="https://react-bvmiba.stackblitz.io">Props Drilling 예시</a></p>
<ul>
<li>props를 Child 1 Component 에서 Child 4 Component 까지 내려주어야 제대로 작동한다.<pre><code class="language-js">import React, { useState } from &#39;react&#39;;
import styled from &#39;styled-components&#39;;
</code></pre>
</li>
</ul>
<p>const Container = styled.div<code>border: 5px solid green;
  padding: 10px;
  margin: 10px;
  position: relative;</code>;</p>
<p>const Quantity = styled.div<code>text-align: center;
  color: red;
  border: 5px solid red;
  padding: 3px;
  font-size: 1.2rem;</code>;</p>
<p>const Button = styled.button<code>margin-right: 5px;</code>;</p>
<p>const Text = styled.div<code>color: ${(props) =&gt; (props.color ? props.color : &#39;black&#39;)};
  font-size: ${(props) =&gt; (props.size ? props.size : &#39;1rem&#39;)};
  font-weight: ${(props) =&gt; (props.weight ? &#39;700&#39; : &#39;inherit&#39;)};</code>;</p>
<p>export default function App() {
  const [number, setNumber] = useState(1);</p>
<p>  const plusNum = () =&gt; {
    setNumber(number + 1);
  };</p>
<p>  const minusNum = () =&gt; {
    setNumber(number - 1);
  };
  console.log(&#39;Parents&#39;);
  return (
    <Container>
      <Text weight size="1.5rem">
        [Parents Component]
      </Text>
      <Text>
        Child4 컴포넌트에 있는 버튼을 통해
        <br /> state를 변경하려고 합니다.. 🤮
      </Text>
      <Text weight color="tomato">
        Props Driling이 발생!!
      </Text>
      <Quantity>{<code>수량 : ${number}</code>}</Quantity>
      <Child1 plusNum={plusNum} minusNum={minusNum} />
    </Container>
  );
}</p>
<p>function Child1(
  {
    plusNum, minusNum/* props로 전달받은 plusNum, minusNum를 가져오세요 <em>/
  }
) {
  console.log(&#39;Child1&#39;);
  return (
    <Container>
      <Text>[Child 1 Component]</Text>
      {/</em> plusNum, minusNum 함수를 props로 전달해주세요! */}
      <Child2 plusNum={plusNum} minusNum={minusNum}/>
    </Container>
  );
}</p>
<p>function Child2(
  {plusNum, minusNum
    /* props로 전달받은 plusNum, minusNum를 가져오세요 <em>/
  }
) {
  console.log(&#39;Child2&#39;);
  return (
    <Container>
      <Text>[Child 2 Component]</Text>
      {/</em> plusNum, minusNum 함수를 props로 전달해주세요! */}
      <Child3 plusNum={plusNum} minusNum={minusNum}/>
    </Container>
  );
}</p>
<p>function Child3(
  {plusNum, minusNum
    /* props로 전달받은 plusNum, minusNum를 가져오세요 <em>/
  }
) {
  console.log(&#39;Child3&#39;);
  return (
    <Container>
      <Text>[Child 3 Component]</Text>
      {/</em> plusNum, minusNum 함수를 props로 전달해주세요! */}
      <Child4 plusNum={plusNum} minusNum={minusNum}/>
    </Container>
  );
}</p>
<p>function Child4({ plusNum, minusNum }) {
  console.log(&#39;Child4&#39;);
  return (
    <Container>
      <Text>[Child 4 Component]</Text>
      <Button onClick={plusNum}>👍</Button>
      <Button onClick={minusNum}>👎</Button>
    </Container>
  );
}</p>
<pre><code>&lt;br&gt;

[상태관리 라이브러리 Redux 활용 예시](https://react-dky3fz.stackblitz.io) 
- Redux를 사용해 Child 4 Component만 props를 전달받을 수 있도록 했다.
```js
import React, { useState } from &#39;react&#39;;
import styled from &#39;styled-components&#39;;
import { useSelector, useDispatch } from &#39;react-redux&#39;;

const Container = styled.div`
  border: 5px solid green;
  padding: 10px;
  margin: 10px;
  position: relative;
`;

const Quantity = styled.div`
  text-align: center;
  color: red;
  border: 5px solid red;
  padding: 3px;
  font-size: 1.2rem;
`;

const Button = styled.button`
  margin-right: 5px;
`;

const Text = styled.div`
  color: ${(props) =&gt; (props.color ? props.color : &#39;black&#39;)};
  font-size: ${(props) =&gt; (props.size ? props.size : &#39;1rem&#39;)};
  font-weight: ${(props) =&gt; (props.weight ? &#39;700&#39; : &#39;inherit&#39;)};
`;

export default function App() {
  const number = useSelector((state) =&gt; state);
  console.log(&#39;Parents&#39;);
  return (
    &lt;Container&gt;
      &lt;Text weight size=&quot;1.5rem&quot;&gt;
        [Parents Component]
      &lt;/Text&gt;
      &lt;Text&gt;
        Child4 컴포넌트에 있는 버튼을 통해 &lt;br /&gt; state를 변경하려고 합니다. ☺️
      &lt;/Text&gt;
      &lt;Text weight color=&quot;tomato&quot;&gt;
        (Redux를 사용하는 경우)
      &lt;/Text&gt;
      &lt;Quantity&gt;{`수량 : ${number}`}&lt;/Quantity&gt;
      &lt;Child1 /&gt;
    &lt;/Container&gt;
  );
}

function Child1() {
  console.log(&#39;Child1&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 1 Component]&lt;/Text&gt;
      &lt;Child2 /&gt;
    &lt;/Container&gt;
  );
}

function Child2() {
  console.log(&#39;Child2&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 2 Component]&lt;/Text&gt;
      &lt;Child3 /&gt;
    &lt;/Container&gt;
  );
}

function Child3() {
  console.log(&#39;Child3&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 3 Component]&lt;/Text&gt;
      &lt;Child4 /&gt;
    &lt;/Container&gt;
  );
}

function Child4() {
  const dispatch = useDispatch();
  const plusNum = () =&gt; {
    dispatch({ type: &#39;Plus&#39; });
  };

  const minusNum = () =&gt; {
    dispatch({ type: &#39;Minus&#39; });
  };
  console.log(&#39;Child4&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 4 Component]&lt;/Text&gt;
      &lt;Button onClick={plusNum}&gt;👍&lt;/Button&gt;
      &lt;Button onClick={minusNum}&gt;👎&lt;/Button&gt;
    &lt;/Container&gt;
  );
}
</code></pre><h4 id="예시-2">예시 2</h4>
<hr>
<p><a href="https://react-ts-qpgq6d.stackblitz.io">Props Drilling으로 인한 불필요한 리렌더링</a></p>
<ul>
<li>Child6에 있는 👋 버튼을 누르면 Child3에 느낌표가 하나씩 추가된다. 이때, Child3, Child6이 하나의 상태를 공유하기 때문에 최상위 컴포넌트인 App에서 상태를 관리해야 한다. 이 때문에 상태를 변경할 때마다 App 컴포넌트가 리렌더링 되면서 모든 컴포넌트가 리렌더링 된다. </li>
</ul>
<pre><code class="language-js">import * as React from &#39;react&#39;;
import &#39;./style.css&#39;;
import styled from &#39;styled-components&#39;;
import { useState } from &#39;react&#39;;

const Component = styled.div`
  border: 3px solid green;
  border-radius: 10px;
  flex-grow: 1;
  line-height: 30px;
  text-align: center;
  margin: 10px;
  &gt;button{
    margin-left: 10px;
  }
`;

const Container = styled.div`
  display: flex;
  width: 100%;
  justify-contents: center;
`;

export default function App() {
  const [greeting, setGreeting] = useState(&#39;Hello&#39;);

  console.log(&#39;App&#39;);
  return (
    &lt;Container&gt;
      &lt;Component&gt;
        App
        &lt;Container&gt;
          &lt;Child1 greeting={greeting} setGreeting={setGreeting} /&gt;
          &lt;Child2 greeting={greeting} setGreeting={setGreeting} /&gt;
        &lt;/Container&gt;
      &lt;/Component&gt;
    &lt;/Container&gt;
  );
}

function Child1({ greeting, setGreeting }) {
  console.log(&#39;Child1&#39;);
  return (
    &lt;Component&gt;
      Child1
      &lt;Container&gt;
        &lt;Child3 greeting={greeting} setGreeting={setGreeting} /&gt;
        &lt;Child4 /&gt;
      &lt;/Container&gt;
    &lt;/Component&gt;
  );
}

function Child2({ greeting, setGreeting }) {
  console.log(&#39;Child2&#39;);
  return (
    &lt;Component&gt;
      Child2
      &lt;Container&gt;
        &lt;Child5 /&gt;
        &lt;Child6 greeting={greeting} setGreeting={setGreeting} /&gt;
      &lt;/Container&gt;
    &lt;/Component&gt;
  );
}

function Child3({ greeting, setGreeting }) {
  console.log(&#39;Child3&#39;);
  return &lt;Component&gt;Child3 : {greeting} &lt;/Component&gt;;
}

function Child4() {
  console.log(&#39;Child4&#39;);
  return &lt;Component&gt;Child4&lt;/Component&gt;;
}

function Child5() {
  console.log(&#39;Child5&#39;);
  return &lt;Component&gt;Child5&lt;/Component&gt;;
}

function Child6({ greeting, setGreeting }) {
  console.log(&#39;Child6&#39;);
  return (
    &lt;Component&gt;
      Child6
      &lt;button onClick={() =&gt; setGreeting(greeting + &#39;!&#39;)}&gt;👋&lt;/button&gt;
    &lt;/Component&gt;
  );
}
</code></pre>
<br>

<p><a href="https://react-ts-szkjfd.stackblitz.io">Redux의 리렌더링 최적화</a></p>
<ul>
<li>Redux를 활용하여 전역 상태 관리를 할 수 있게 만들어주어 상태의 영향을 받아 화면을 변경해야 하는 컴포넌트만 리렌더링된다.</li>
</ul>
<pre><code class="language-js">import React, { useState } from &#39;react&#39;;
import styled from &#39;styled-components&#39;;

const Container = styled.div`
  border: 5px solid green;
  padding: 10px;
  margin: 10px;
  position: relative;
`;

const Quantity = styled.div`
  text-align: center;
  color: red;
  border: 5px solid red;
  padding: 3px;
  font-size: 1.2rem;
`;

const Button = styled.button`
  margin-right: 5px;
`;

const Text = styled.div`
  color: ${(props) =&gt; (props.color ? props.color : &#39;black&#39;)};
  font-size: ${(props) =&gt; (props.size ? props.size : &#39;1rem&#39;)};
  font-weight: ${(props) =&gt; (props.weight ? &#39;700&#39; : &#39;inherit&#39;)};
`;

export default function App() {
  const [number, setNumber] = useState(1);

  const plusNum = () =&gt; {
    setNumber(number + 1);
  };

  const minusNum = () =&gt; {
    setNumber(number - 1);
  };
  console.log(&#39;Parents&#39;);
  return (
    &lt;Container&gt;
      &lt;Text weight size=&quot;1.5rem&quot;&gt;
        [Parents Component]
      &lt;/Text&gt;
      &lt;Text&gt;
        Child4 컴포넌트에 있는 버튼을 통해
        &lt;br /&gt; state를 변경하려고 합니다.. 🤮
      &lt;/Text&gt;
      &lt;Text weight color=&quot;tomato&quot;&gt;
        Props Driling이 발생!!
      &lt;/Text&gt;
      &lt;Quantity&gt;{`수량 : ${number}`}&lt;/Quantity&gt;
      &lt;Child1 plusNum={plusNum} minusNum={minusNum} /&gt;
    &lt;/Container&gt;
  );
}

function Child1(
  {
    /* props로 전달받은 plusNum, minusNum를 가져오세요 */
  }
) {
  console.log(&#39;Child1&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 1 Component]&lt;/Text&gt;
      {/* plusNum, minusNum 함수를 props로 전달해주세요! */}
      &lt;Child2 /&gt;
    &lt;/Container&gt;
  );
}

function Child2(
  {
    /* props로 전달받은 plusNum, minusNum를 가져오세요 */
  }
) {
  console.log(&#39;Child2&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 2 Component]&lt;/Text&gt;
      {/* plusNum, minusNum 함수를 props로 전달해주세요! */}
      &lt;Child3 /&gt;
    &lt;/Container&gt;
  );
}

function Child3(
  {
    /* props로 전달받은 plusNum, minusNum를 가져오세요 */
  }
) {
  console.log(&#39;Child3&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 3 Component]&lt;/Text&gt;
      {/* plusNum, minusNum 함수를 props로 전달해주세요! */}
      &lt;Child4 /&gt;
    &lt;/Container&gt;
  );
}

function Child4({ plusNum, minusNum }) {
  console.log(&#39;Child4&#39;);
  return (
    &lt;Container&gt;
      &lt;Text&gt;[Child 4 Component]&lt;/Text&gt;
      &lt;Button onClick={plusNum}&gt;👍&lt;/Button&gt;
      &lt;Button onClick={minusNum}&gt;👎&lt;/Button&gt;
    &lt;/Container&gt;
  );
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[전역 상태 관리]]></title>
            <link>https://velog.io/@1aba_can_opener/%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@1aba_can_opener/%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Fri, 21 Apr 2023 04:47:19 GMT</pubDate>
            <description><![CDATA[<h2 id="상태">상태</h2>
<hr>
<p>상태란 변하는 데이터이며 프론트엔드 개발에서는 UI에 동적으로 표현되는 데이터를 의미한다. <img src="https://velog.velcdn.com/images/1aba_can_opener/post/12e9bd06-eea4-4cdf-8e74-642ac88ad4fa/image.png" alt="">
위의 이미지는 쇼핑몰 장바구니화면에서의 상태를 나타낸 것이다. </p>
<ul>
<li>&quot;장바구니에 담기&quot;와 같은 버튼을 눌러, 해당 물품을 장바구니에 추가할 수 있습니다. 동적인 데이터이므로 이것은 상태입니다.</li>
<li>상단에 [일반구매/정기배송]중 현재 선택된 탭이 무엇인지 나타내는 상태가 있을 수 있습니다. </li>
<li>상품 선택 여부에 따라 주문 금액이나 배송비가 달라집니다. 선택 여부는 변할 수 있으므로 상태입니다.</li>
<li>상품 수량도 상태입니다.</li>
<li>이를 컴포넌트로 분리해 컴포넌트 사이에 어떤 상태를 공유하고 주고 받는지도 생각해보길 바란다.</li>
</ul>
<h2 id="side-effect">Side Effect</h2>
<hr>
<p>상태를 다룰 때에 주요 고려 대상인 Side Effect는 함수의 입력 외에도 함수의 결과에 영향을 미치는 요인으로 대표적으로 네트워크 요청, API호출이 있다.</p>
<h3 id="side-effect-최대한-배제하기">side Effect 최대한 배제하기</h3>
<p>컴포넌트를 만들시에는 Side Effect를 최대한 배제하고 컴포넌트를 만들어야한다. 더욱 자세히 말해보자면 입력 데이터가 가짜 데이터라 할지라도 컴포넌트는 표현(presentation)할 수 있어야하며 이러한 컴포넌트를 presentation 컴포넌트라고 부른다. </p>
<h3 id="불가피한-side-effect와-상태">불가피한 Side Effect와 상태</h3>
<p>Side Effect를 최대한 배제하고 컴포넌트를 만들어야하지만 불가피하게 생기는 경우가 있을 수 있다. 예를들어 &quot;로딩 중&quot; 을 나타내는 상태는 데이터 전송 여부에 달려있기 때문에 이 상태는 Side Effect 에 의존적이라고 할 수 있다. </p>
<h2 id="상태의-두가지-구분">상태의 두가지 구분</h2>
<hr>
<p>상태를 구분하는 데에 절대적인 기준이나 법칙은 없지만 로컬 상태, 전역 상태로 나눠서 접근해 볼 수 있다. 이 두 상태를 간단히 설명해보자면 아래와 같다.</p>
<ul>
<li><p>로컬상태 : 특정 컴포넌트 안에서만 관리되는 상태</p>
</li>
<li><p>전역상태 ; 프로덕트 전체 혹은 여러가지 컴포넌트가 동시에 관리되는 상태</p>
</li>
</ul>
<h3 id="로컬상태">로컬상태</h3>
<hr>
<p>로컬상태는 보통 컴포넌트 내에서만 영향을 끼치는 상태를 일컫는다. 대표적으로 다른 컴포넌트와 데이터를 공유하지 않는 폼(form) 데이터는 대부분 로컬상태이다. input box, select box 등과 같이 입력값을 받는 경우가 이에 해당한다.</p>
<h3 id="전역상태">전역상태</h3>
<hr>
<p>전역상태는 다른 컴포넌트와 상태를 공유하고 영향을 끼치는 상태이다. JavaScript에서 전역변수를 남용하는 것을 좋지 않지만 경우에 따라서는 전역상태가 필요하다. </p>
<p>우선 서로 다른 컴포넌트가 사용하는 상태의 종류가 다르다면 꼭 전역상태일 필요없이 서로 다른 출처 (source)가 있어도 상관없다. 예를들어 장바구니 물품과 회원정보는 사용하는 상태의 종류가 다르기에 출처가 다르다. </p>
<p>하지만 서로 다른 컴포넌트가 동일한 상태를 다룬다면 이 출처는 오직 한곳이어야 한다. 만일 출처의 사본을 사용하는 경우 두 데이터는 서로 동기화(sync)하는 과정이 필요한데 이는 오히려 복잡한 코드를 야기할 수 있다. 때문에 한곳에서만 상태를 저장하고 접근할필요가 있다. 여기서 &#39;하나의 출처&#39;는 다른말로 이야기하자면 &#39;전역공간&#39;이라고 볼 수 있다. </p>
<h3 id="전역상태에서의-데이터-무결성">전역상태에서의 데이터 무결성</h3>
<hr>
<p>데이터 무결성이란 데이터의 정확성을 보장하기 위해 데이터의 변경이나 수정 시 제한을 두어 안정성을 저해하는 요소를 막고 데이터 상태들을 항상 옳게 유지하는 것이다.</p>
<p>이 무결성을 위한 방법론은 &quot;Single source of truth&quot;(신뢰할 수 있는 단일출처)로 &#39;동일한 데이터는 항상 같은 곳에서 데이터를 가지고 온다.&#39;를 원칙으로 하고 있다.</p>
<h3 id="전역상태-관리의-예">전역상태 관리의 예</h3>
<hr>
<p>전역으로 상태를 관리해야 하는 경우의 예중 하나로 다크모드를 떠올려볼 수 있다. 요즈음 여러 사이트에서 다크 모드 기능을 지원하고 있는데 이 경우 모든 페이지, 모든 컴포넌트에 다크모드 혹은 라이트 모드가 적용 되어야 하기 때문에 이러한 테마 설정상태를 전역으로 관리해야 한다. </p>
<p>국제화(Globalization) 설정도 마찬가지이다. 사용자가 사용하는 브라우저나 운영체제가 특정 언어사용을 인지하고 UI에 필요한 텍스트 리소스를 따로 저장한 후 전역 상태로 관리하기도 한다. 이 기능의 경우 모든 컴포넌트에서 사용자의 언어로 표현이 되어야 하기 때문에 전역에서 상태 관리가 필요하다.</p>
<p>조금 더 복잡 한 예를 생각해보자면 포토샵이나 일러스트레이터에는 히스토리 기능과 Undo/Redo를 지원한다. Undo/Redo, 히스토리 기능의 작동 원리는 이렇다. 화면에 표시되는 모든 내용을 전부 상태 객체로 만들어 저장해버린다면 원하는 특정 상태를 바탕으로 컴포넌트르 표현할 수도 있다. </p>
<h3 id="상태관리-툴">상태관리 툴</h3>
<hr>
<ul>
<li>React Context</li>
<li>Redux</li>
<li>MobX</li>
</ul>
<h3 id="상태-관리-라이브러리-사용시-장점">상태 관리 라이브러리 사용시 장점</h3>
<hr>
<ul>
<li><p>전역상태를 위한 저장소 제공</p>
</li>
<li><p>props drilling 문제를 해결</p>
<ul>
<li>예를들어 <code>&lt;A&gt;</code> 라는 컴포넌트에 상태가 있고 <code>&lt;I&gt;</code> 라는 컴포넌트가 해당상태를 사용한다고 하면 그중간에 존재하는 <code>&lt;C&gt;</code>, <code>&lt;G&gt;</code> 등은 굳이 name 이라는 상태가 필요하지 않음에도 컴포넌트에 props 를 만들어 자식  컴포넌트에 넘겨 주어야했다. 이를 props drrilling 문제라고 부른다. </li>
</ul>
</li>
</ul>
<p>상태관리 툴이 반드시 필요한 것은 아니다. React 공식문서의 <a href="https://ko.legacy.reactjs.org/docs/thinking-in-react.html">React로 사고하기</a> 만 잘 참고하여 사용해도 대부분의 문제를 해결할 수 있기에 장단점을 분명히 인지하고 상태관리 툴 사용 여부를 결정하기 바란다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useRef]]></title>
            <link>https://velog.io/@1aba_can_opener/useRef</link>
            <guid>https://velog.io/@1aba_can_opener/useRef</guid>
            <pubDate>Tue, 18 Apr 2023 18:02:01 GMT</pubDate>
            <description><![CDATA[<h2 id="useref">useRef</h2>
<hr>
<p>DOM 엘리먼트의 주소값을 활용해야 하는 경우인</p>
<ul>
<li><p>focus</p>
</li>
<li><p>text selection</p>
</li>
<li><p>media playback</p>
</li>
<li><p>애니메이션 적용</p>
</li>
<li><p>d3.js, greensock 등 DOM 기반 라이브러리 활용</p>
</li>
</ul>
<p>등의 상황일 때 <code>useRef</code> 로 DOM 노드, 엘리먼트, 그리고 React 컴포넌트 주소값을 참조할 수 있다.</p>
<pre><code class="language-js">const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
    &lt;div&gt;
      &lt;input ref={주소값을_담는_그릇} type=&quot;text&quot; /&gt;
        {/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
        {/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
        {/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
    &lt;/div&gt;);</code></pre>
<p>이 주소값은 컴포넌트가 re-render 되더라도 바뀌지 않습니다. 이 특성을 활용하여 아래의 제한된 상황에서 <code>useRef</code> 를 활용할 수 있다.</p>
<pre><code class="language-js">function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () =&gt; {
    inputEl.current.focus();
  };
  return (
    &lt;&gt;
      &lt;input ref={inputEl} type=&quot;text&quot; /&gt;
      &lt;button onClick={onButtonClick}&gt;Focus the input&lt;/button&gt;
    &lt;/&gt;);
}</code></pre>
<p>하지만 제시된 상황을 제외한 대부분의 경우 기본 React 문법을 벗어나 useRef를 남용하는 것은 부적절하고, React의 특징이자 장점인 선언형 프로그래밍 원칙과 배치되기 때문에, 조심해서 사용해야 한다.</p>
<h2 id="useref-예제">useRef 예제</h2>
<hr>
<p>아래 예제들은 useRef를 사용할 수 있는 대표적인 상황들이다. 그런데, 잘 살펴보면 예제가 의도대로 작동하지 않고 있음을 알 수 있다. 예제를 분석해 보면서 useRef가 어떻게 활용되고 있는지 확인해 보고, 예제가 제대로 작동할 수 있도록 코드를 수정해 보자.</p>
<h3 id="예제-1--focus">예제 1 : focus</h3>
<pre><code class="language-js">// 예제 코드

import React, { useRef } from &quot;react&quot;;

const Focus = () =&gt; {
  const firstRef = useRef(null);
  const secondRef = useRef(null);
  const thirdRef = useRef(null);

  const handleInput = (event) =&gt; {
    console.log(event.key, event);
    if (event.key === &quot;Enter&quot;) {
      if (event.target === firstRef.current) {
        secondRef.current.focus();
        event.target.value = &quot;&quot;;
      } else if (event.target === secondRef.current) {
        thirdRef.current.focus();
        event.target.value = &quot;&quot;;
      } else if (event.target === thirdRef.current) {
        firstRef.current.focus();
        event.target.value = &quot;&quot;;
      } else {
        return;
      }
    }
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;타자연습&lt;/h1&gt;
      &lt;h3&gt;각 단어를 바르게 입력하고 엔터를 누르세요.&lt;/h3&gt;
      &lt;div&gt;
        &lt;label&gt;hello &lt;/label&gt;
        &lt;input ref={firstRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label&gt;world &lt;/label&gt;
        &lt;input ref={secondRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label&gt;codestates &lt;/label&gt;
        &lt;input ref={thirdRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Focus;
</code></pre>
<pre><code class="language-js">// 수정코드
import React, { useRef } from &quot;react&quot;;

const Focus = () =&gt; {
  const firstRef = useRef(null);
  const secondRef = useRef(null);
  const thirdRef = useRef(null);

  const handleInput = (event) =&gt; {
    console.log(event.key, event);
    if (event.key === &quot;Enter&quot;) {
      const currentValue = event.target.value.trim();
      if (event.target === firstRef.current) {
        if (currentValue === &quot;hello&quot;) secondRef.current.focus();
      } else if (event.target === secondRef.current) {
        if (currentValue === &quot;world&quot;) thirdRef.current.focus();
      } else if (event.target === thirdRef.current) {
        if (currentValue === &quot;codestates&quot;) firstRef.current.focus();
      } else {
        return;
      }
    }
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;타자연습&lt;/h1&gt;
      &lt;h3&gt;각 단어를 바르게 입력하고 엔터를 누르세요.&lt;/h3&gt;
      &lt;div&gt;
        &lt;label&gt;hello &lt;/label&gt;
        &lt;input ref={firstRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label&gt;world &lt;/label&gt;
        &lt;input ref={secondRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;label&gt;codestates &lt;/label&gt;
        &lt;input ref={thirdRef} onKeyUp={handleInput} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Focus;
</code></pre>
<h3 id="예제-2--media-playback">예제 2 : media playback</h3>
<pre><code class="language-js">// 예제 코드
import { useRef } from &quot;react&quot;;

export default function App() {
  const videoRef = useRef(null);

  const playVideo = () =&gt; {
    videoRef.current.play();
    console.log(videoRef.current);
  };

  const pauseVideo = () =&gt; {
    videoRef.current.pause();
    videoRef.current.remove();
  };

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;div&gt;
        &lt;button onClick={playVideo}&gt;Play&lt;/button&gt;
        &lt;button onClick={pauseVideo}&gt;Pause&lt;/button&gt;
      &lt;/div&gt;
      &lt;video ref={videoRef} width=&quot;320&quot; height=&quot;240&quot; controls&gt;
        &lt;source
          type=&quot;video/mp4&quot;
          src=&quot;https://player.vimeo.com/external/544643152.sd.mp4?s=7dbf132a4774254dde51f4f9baabbd92f6941282&amp;profile_id=165&quot;
        /&gt;
      &lt;/video&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<pre><code class="language-js">// 수정 코드
import { useRef } from &quot;react&quot;;

export default function App() {
  const videoRef = useRef(null);

  const playVideo = () =&gt; {
    videoRef.current.play();
    console.log(videoRef.current);
  };

  const pauseVideo = () =&gt; {
    videoRef.current.pause();
    //videoRef.current.remove();
  };

  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;div&gt;
        &lt;button onClick={playVideo}&gt;Play&lt;/button&gt;
        &lt;button onClick={pauseVideo}&gt;Pause&lt;/button&gt;
      &lt;/div&gt;
      &lt;video ref={videoRef} width=&quot;320&quot; height=&quot;240&quot; controls&gt;
        &lt;source
          type=&quot;video/mp4&quot;
          src=&quot;https://player.vimeo.com/external/544643152.sd.mp4?s=7dbf132a4774254dde51f4f9baabbd92f6941282&amp;profile_id=165&quot;
        /&gt;
      &lt;/video&gt;
    &lt;/div&gt;
  );
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Storybook]]></title>
            <link>https://velog.io/@1aba_can_opener/Storybook</link>
            <guid>https://velog.io/@1aba_can_opener/Storybook</guid>
            <pubDate>Tue, 18 Apr 2023 17:19:05 GMT</pubDate>
            <description><![CDATA[<h2 id="storybook">Storybook</h2>
<hr>
<p>Component Driven Development 가 트렌드로 자리 잡게 되면서 이를 지원하는 도구 중 하나인 Component Explorer (컴포넌트 탐색기)가 등장했다. Component Explorer에는 많은 UI 개발 도구가 다양하게 있는데 그중 하나가 <a href="https://storybook.js.org/">Storybook</a>이다.</p>
<h3 id="storybook이란">Storybook이란?</h3>
<p>Storybook은 각각의 컴포넌트들을 따로 볼 수 있게 구성해 주어 한 번에 하나의 컴포넌트에서 작업할 수 있다.복잡한 개발 스택을 시작하거나, 특정 데이터를 데이터베이스로 강제 이동하거나, 애플리케이션을 탐색할 필요 없이 전체 UI를 한눈에 보고 개발할 수 있다. </p>
<p>Storybook은 재사용성을 확대하기 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화하여 시뮬레이션할 수 있는 다양한 테스트 상태를 확인할 수 있다. 이를 통해 버그를 사전에 방지할 수 있도록 도와준다. 또한 테스트 및 개발 속도를 향상하는 장점이 있으며, 애플리케이션 또한 의존성을 걱정하지 않고 빌드할 수 있다.</p>
<h3 id="storybook과-같은-ui-개발-도구를-사용하는-이유">Storybook과 같은 UI 개발 도구를 사용하는 이유</h3>
<p>Storybook은 기본적으로 독립적인 개발 환경에서 실행되기에 개발자는 애플리케이션의 다양한 상황에 구애받지 않고 UI 컴포넌트를 집중적으로 개발할 수 있다. 회사의 내부 개발자들을 위해 문서화(documentation)를 하여 회사의 UI 라이브러리로써 사용하거나, 외부 공개용 디자인 시스템(Design System)을 개발하기 위한 기본 플랫폼으로 사용할 수도 있다. </p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/b1cd4712-bc6f-44c2-8cc7-69362753a180/image.png" alt=""></p>
<h3 id="storybook에서-지원하는-주요-기능">Storybook에서 지원하는 주요 기능</h3>
<ul>
<li><p>UI 컴포넌트들을 카탈로그화하기</p>
</li>
<li><p>컴포넌트 변화를 Stories로 저장하기</p>
</li>
<li><p>핫 모듈 재 로딩과 같은 개발 툴 경험을 제공하기</p>
</li>
<li><p>리액트를 포함한 다양한 뷰 레이어 지원하기</p>
</li>
</ul>
<h3 id="storybook으로-컴포넌트들을-문서화해서-관리하는-방법">Storybook으로 컴포넌트들을 문서화해서 관리하는 방법</h3>
<p>우선 Create React App을 활용해서 리액트 프로젝트 생성해야한다.</p>
<ul>
<li><code>npx create-react-app storybook-practice</code></li>
</ul>
<p>폴더가 생성되면, 폴더 안에서 Storybook을 설치한다.</p>
<ul>
<li><p><code>npx storybook@latest init</code></p>
<ul>
<li>이 명령어는 <code>package.json</code> 을 보고 사용 중인 프론트엔드 라이브러리에 맞는 Storybook 사용 환경을 알아서 만들어주기 때문에, 꼭 React가 아니더라도 다양한 프론트엔드 라이브러리에서 사용할 수 있다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/53d7e14c-45d0-435b-aacb-298595c72651/image.png" alt=""></p>
<p>Storybook 설치가 완료되면, /.storybook 폴더와 /src/stories 폴더가 생성된 것을 확인할 수 있다. /.storybook 폴더에는 Storybook 관련 설정 파일이, /src/stories 폴더에는 Storybook 예시 파일들이 들어있다.</p>
<p>이제 터미널 창에서 Storybook을 실행한다.</p>
<ul>
<li><code>npm run storybook</code></li>
</ul>
<p>명령어를 입력하면 localhost:6006으로 접근하여 Storybook을 실행시킨다. </p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/f2f0d76d-caa0-45f1-878d-753b9972e3f3/image.png" alt=""></p>
<p>Storybook을 실행하면 /src/stories 폴더 안에 있던, Storybook에서 만들어놓은 예시 스토리를 확인할 수 있다. 이렇게 Storybook을 사용하면 애플리케이션을 실행하고 이벤트를 통해 상태를 변경하는 과정을 거치지 않아도 상태 변화에 따른 컴포넌트의 변화를 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Styled Components]]></title>
            <link>https://velog.io/@1aba_can_opener/Styled-Components</link>
            <guid>https://velog.io/@1aba_can_opener/Styled-Components</guid>
            <pubDate>Tue, 18 Apr 2023 14:59:36 GMT</pubDate>
            <description><![CDATA[<h2 id="styled-components">Styled Components</h2>
<hr>
<p>React 환경에서 사용 가능한 Styled Components라는 라이브러리는 CSS를 컴포넌트화 해준다. </p>
<p>Styled Components는 CSS in JS라는 개념이 대두되면서 나온 라이브러리로 기존에 HTML, CSS, JS 파일로 쪼개서 개발하던 방법에서, React 등의 라이브러리의 등장으로 컴포넌트 단위 개발이 주류가 되었지만, CSS는 그렇지 못했다는 점에서 출발한 개념이다. </p>
<p>CSS in JS 라이브러리를 사용하면 CSS도 쉽게 Javascript 안에 넣어줄 수 있으므로, HTML + JS + CSS까지 묶어서 하나의 JS파일 안에서 컴포넌트 단위로 개발할 수 있게 된다. 이런 CSS in JS 라이브러리 중에서 현재 가장 인기 있는 라이브러리가 바로 Styled Components이다.</p>
<h2 id="styled-components-설치">Styled Components 설치</h2>
<hr>
<p>우선<code>npm install --save styled-components</code> 을 터미널에 입력해 설치하면 된다. </p>
<p>그후 Styled Components는 package.json에 다음 코드를 추가하도록 권장하고 있으니 추가하길 바란다. 아래의 코드를 추가하면 여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여준다.</p>
<pre><code class="language-js">// package.json에 추가

{
  &quot;resolutions&quot;: {
    &quot;styled-components&quot;: &quot;^5&quot;
  }
}</code></pre>
<p>그 다음 Styled Components를 사용할 파일로 불러와주면 사용준비가 완료된다.</p>
<pre><code class="language-js">//사용할 파일에 import

import styled from &quot;styled-components&quot;</code></pre>
<h2 id="styled-components-문법">Styled Components 문법</h2>
<hr>
<h3 id="컴포넌트-만들기">컴포넌트 만들기</h3>
<pre><code class="language-js">//Styled Components 문법

const 컴포넌트이름 = styled.태그종류`
    css속성1: 속성값;
    css속성2: 속성값;
`;

//예시

const BlueButton = styled.button`
  background-color: blue;
  color: white;
`;</code></pre>
<p>Styled Components는 따옴표가 아닌 백 틱을 쓰는 ES6의 Templete Literals 문법을 사용한다. </p>
<p>컴포넌트를 선언한 후 <code>styled.태그종류</code>를 할당하고 백 틱 안에 css문법으로 스타일 속성을 작성해주면 된다. 이렇게 만든 컴포넌트를 React컴포넌트를 사용하듯 리턴문 안에 작성해주면 스타일이 적용된 컴포넌트가 렌더 되는 것을 확인할 수 있다.</p>
<pre><code class="language-js">// Styled Components의 예

import styled from &quot;styled-components&quot;;

//Styled Components로 컴포넌트를 만들고
const BlueButton = styled.button`
  background-color: blue;
  color: white;
`;

export default function App() {
  // React 컴포넌트를 사용하듯이 사용하면 된다.
  return &lt;BlueButton&gt;Blue Button&lt;/BlueButton&gt;;
}
</code></pre>
<h3 id="컴포넌트를-재활용해서-새로운-컴포넌트-만들기">컴포넌트를 재활용해서 새로운 컴포넌트 만들기</h3>
<pre><code class="language-js">//컴포넌트를 재활용해서 새로운 컴포넌트를 만드는 법

const 컴포넌트이름 = styled(재활용할 컴포넌트)`
    추가할css속성1 : 속성값;
    추가할css속성2 : 속성값;
`;

//컴포넌트를 재활용해서 새로운 컴포넌트를 만드는 법

const BigBlueButton = styled(BlueButton)`
  padding: 10px;
  margin-top: 10px;
`;
</code></pre>
<p>컴포넌트를 선언하고 <code>styled()</code>에 재활용할 컴포넌트를 전달해준 다음 추가하고 싶은 스타일 속성을 작성해주면 컴포넌트를 재활용한 새로운 컴포넌트를 만들 수 있다.</p>
<pre><code class="language-js">//컴포넌트를 재활용해서 새로운 컴포넌트를 만드는 법의 예

import styled from &quot;styled-components&quot;;

const BlueButton = styled.button`
  background-color: blue;
  color: white;
`;

//만들어진 컴포넌트를 재활용해 컴포넌트를 만들 수 있다.
const BigBlueButton = styled(BlueButton)`
  padding: 10px;
  margin-top: 10px;
`;

//재활용한 컴포넌트를 재활용할 수도 있다.
const BigRedButton = styled(BigBlueButton)`
  background-color: red;
`;

export default function App() {
  return (
    &lt;&gt;
      &lt;BlueButton&gt;Blue Button&lt;/BlueButton&gt;
      &lt;br /&gt;
      &lt;BigBlueButton&gt;Big Blue Button&lt;/BigBlueButton&gt;
      &lt;br /&gt;
      &lt;BigRedButton&gt;Big Red Button&lt;/BigRedButton&gt;
    &lt;/&gt;
  );
}</code></pre>
<h3 id="props-활용">Props 활용</h3>
<p>Styled Component로 만든 컴포넌트도 React컴포넌트처럼 props를 내려줄 수 있다. 내려준 props 값에 따라 컴포넌트를 렌더링 하는 것도 가능하다.</p>
<pre><code class="language-js">// Props 활용법

const 컴포넌트이름 = styled.태그종류`
    css속성: ${(props) =&gt; 함수코드}
`;</code></pre>
<p>Styled Components는 템플릿 리터럴 문법( <code>${ }</code> )을 사용하여 JavaScript 코드를 사용할 수 있다. props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 된다.</p>
<h4 id="props로-조건부-렌더링하기">Props로 조건부 렌더링하기</h4>
<pre><code class="language-js">// Props로 조건부 렌더링하기
const Button = styled.button`
    background: ${(props) =&gt; props.skyblue? &quot;skyblue&quot;:&quot;white&quot;}
`;</code></pre>
<p>위 코드의 경우 삼항 연산자를 활용해 <code>&lt;Button&gt;</code> 컴포넌트에 skyblue 라는 props가 있는지 확인하고 있으면 배경색으로 <code>skyblue</code>를, 없을 땐 <code>white</code>를 지정해주는 코드다. </p>
<pre><code class="language-js">// Props로 조건부 렌더링의 예

import styled from &quot;styled-components&quot;;
import GlobalStyle from &quot;./GlobalStyle&quot;;
//받아온 prop에 따라 조건부 렌더링이 가능합니다.
const Button1 = styled.button`
  background: ${(props) =&gt; (props.skyblue ? &quot;skyblue&quot; : &quot;white&quot;)};
`;

export default function App() {
  return (
    &lt;&gt;
      &lt;GlobalStyle /&gt;
      &lt;Button1&gt;Button1&lt;/Button1&gt;
      &lt;Button1 skyblue&gt;Button1&lt;/Button1&gt;
    &lt;/&gt;
  );
}</code></pre>
<h4 id="props-값으로-렌더링하기">Props 값으로 렌더링하기</h4>
<pre><code class="language-js">// Props 값으로 렌더링하기
const Button = styled.button`
    background: ${(props) =&gt; props.color ? props.color : &quot;white&quot;}
`;</code></pre>
<p>이처럼 props의 값을 통째로 활용해서 컴포넌트 렌더링에 활용할수 있다. <code>props.color</code>가 없다면 <code>white</code>를, <code>props.color</code>가 있다면 props.color의 값을 그대로 가져와서 스타일 속성 값으로 리턴해주고 있는 것을 볼 수 있다. 그 결과 <code>color</code> 라는 이름으로 받은 props의 값으로 배경색이 지정된 것을 확인할 수 있다. </p>
<p>꼭 삼향연산자만 사용해야하는 것은 아니다. JavaScript 코드라면 무엇이든 사용할 수 있으므로 원하는 값을 사용할 수 있도록 함수코드를 만들어 사용하면 된다. 아래 예시와 같은 코드다 활용할 수 있다. props도 원하는 만큼 받아서 사용할 수 있으니 다양한 활용이 가능하다.</p>
<pre><code class="language-js">// Props 값으로 렌더링의 예

import styled from &quot;styled-components&quot;;
import GlobalStyle from &quot;./GlobalStyle&quot;;

//받아온 prop 값을 그대로 이용해 렌더링할 수도 있다
const Button1 = styled.button`
  background: ${(props) =&gt; (props.color ? props.color : &quot;white&quot;)};
`;
//다음과 같은 형식으로도 활용할 수 있다.
const Button2 = styled.button`
  background: ${(props) =&gt; props.color || &quot;white&quot;};
`;

export default function App() {
  return (
    &lt;&gt;
      &lt;GlobalStyle /&gt;
      &lt;Button1&gt;Button1&lt;/Button1&gt;
      &lt;Button1 color=&quot;orange&quot;&gt;Button1&lt;/Button1&gt;
      &lt;Button1 color=&quot;tomato&quot;&gt;Button1&lt;/Button1&gt;
      &lt;br /&gt;
      &lt;Button2&gt;Button2&lt;/Button2&gt;
      &lt;Button2 color=&quot;pink&quot;&gt;Button2&lt;/Button2&gt;
      &lt;Button2 color=&quot;turquoise&quot;&gt;Button2&lt;/Button2&gt;
    &lt;/&gt;
  );
}</code></pre>
<h4 id="전역-스타일-설정하기">전역 스타일 설정하기</h4>
<pre><code class="language-js">import { createGlobalStyle } from &quot;styled-components&quot;;</code></pre>
<p>전역에 스타일을 설정하고 싶을 땐 우선 전역 스타일을 설정하기 위해 Styled Components에서 <code>reateGlobalStyle</code> 함수를 불러온다.</p>
<pre><code class="language-js">const GlobalStyle = createGlobalStyle`
    button {
        padding : 5px;
    margin : 2px;
    border-radius : 5px;
    }
`</code></pre>
<p>그다음 이를 사용해 CSS 파일에서 작성하듯 설정해주고 싶은 스타일을 작성한다.</p>
<pre><code class="language-js">function App() {
    return (
        &lt;&gt;
            &lt;GlobalStyle /&gt;
            &lt;Button&gt;전역 스타일 적용하기&lt;/Button&gt;
        &lt;/&gt;
    );
}</code></pre>
<p>이렇게 만들어진 <code>&lt;GlobalStyle&gt;</code> 컴포넌트를 최상위 컴포넌트에서 사용해 주면 전역에 <code>&lt;GlobalStyle&gt;</code> 컴포넌트의 스타일이 적용된다.</p>
<pre><code class="language-js">// 전역 스타일 설정 예시

import styled, { createGlobalStyle } from &quot;styled-components&quot;;

const Button = styled.button`
  padding: 1rem;
  font-size: 2rem;
  background: powderblue;
  border-radius: 1rem;
  transition: 0.5s;
  &amp;:hover {
    background: cornflowerblue;
    color: white;
    transition: 0.5s;
  }
`;

const GlobalStyle = createGlobalStyle`
    * {
        margin: 0.5rem;
    }
`;

export default function App() {
  return (
    &lt;&gt;
      &lt;GlobalStyle /&gt;
      &lt;Button&gt;Practice!&lt;/Button&gt;
    &lt;/&gt;
  );
}
</code></pre>
<h2 id="vscode-styled-components">vscode-styled-components</h2>
<hr>
<p>Styled Components를 사용할 때, CSS 코드를 템플릿 리터럴을 사용해서 작성하게 되기에 VSCode에서 코드 작성 시 CSS 파일에서 작성하는 것처럼 자동 완성 기능을 사용할 수 없다. vscode-styled-components 익스텐션은 Styled Components를 사용시에도 자동완성 기능을 사용할 수 있도록 해주는 유용한 익스텐션이다.  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Component-Driven Development]]></title>
            <link>https://velog.io/@1aba_can_opener/Component-Driven-Development</link>
            <guid>https://velog.io/@1aba_can_opener/Component-Driven-Development</guid>
            <pubDate>Tue, 18 Apr 2023 08:33:59 GMT</pubDate>
            <description><![CDATA[<h2 id="cddcomponent-driven-development">(CDD)Component-Driven Development</h2>
<hr>
<p>디자인과 개발 단계에서부터 재사용할 수 있는 UI 컴포넌트를 미리 디자인하고 개발하는 방식인 CDD는 부품 단위로 UI 컴포넌트를 만들어 나가는 개발을 진행할 수 있게 한다. </p>
<h2 id="css-구조화">CSS 구조화</h2>
<hr>
<p>인터넷이 만들어진 이후 기술의 발달과 함께 사용자들은 다양한 환경(디바이스)에서 인터넷을 사용하기 시작했고 이에 따라 개발자들의 CSS 작성 방식도 꾸준히 진화해 오고 있다.</p>
<p>프로젝트의 규모나 복잡도가 점점 커지고 함께 작업해야 할 팀원 수도 많아짐에 따라 CSS를 작성하는 일관된 패턴이 없다는 것은 개발자들에게 가장 큰 걸림돌이 되었다. 또한 모바일이나 태블릿을 비롯한 다양한 디바이스들의 등장으로 웹사이트들이 다양한 디스플레이를 커버해야 하기 때문에 CSS는 더 복잡해지게 되었다. </p>
<p>따라서 CSS 작업을 효율적으로 하기 위해 구조화된 CSS의 필요성이 대두되었고, CSS를 구조화하는 방법에 대한 연구가 필요해졌다.</p>
<h3 id="css-전처리기-css-preprocessor">CSS 전처리기 (CSS Preprocessor)</h3>
<hr>
<p>CSS 전처리기(CSS Preprocessor)란 CSS가 구조적으로 작성될 수 있게 도움을 주는 도구이다. </p>
<p>흔히 CSS 문서를 작성할 때는 많은 반복적인 작업을 요구하고 Color 값을 찾는 일, tag를 닫는 일 등 번거로운 작업 역시 포함이 되어 있다. 또한 클래스의 상속과 같은 사항으로 점점 CSS 문서는 양이 많아지고 이로 인해 이후 유지관리에 많은 영향을 끼친다. 이런 CSS의 문제점들을 프로그래밍 개념(변수, 함수, 상속 등)을 활용하여 해결해 나갈 수 있다.</p>
<p>하지만 이 CSS 전처리기(CSS Preprocessor) 자체만으로는 웹 서버가 인지하지 못하기 때문에 각 CSS 전처리기에 맞는 Compiler를 사용해야 하고 컴파일을 하게 되면 실제로 우리가 사용하는 CSS 문서로 변환이 된다. </p>
<p>이를 통해 CSS 파일들을 잘 구조화할 수 있게 되었고, 최소한 CSS 파일을 몇 개의 작은 파일로 분리할 수 있는 방법이 생겼다.</p>
<h3 id="sass">SASS</h3>
<hr>
<p>CSS 전처리기 중 하나인 SASS는 Syntactically Awesome Style Sheets의 약자로 CSS를 확장해 주는 스크립팅 언어로 자바스크립트처럼 특정 속성(ex. color, margin, width 등)의 값(ex. #ffffff, 25rem, 100px 등)을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한 번의 선언으로 여러 곳에서 재사용할 수 있도록 해 주는 등의 기능을 가졌다. 그래서 SASS는 SCSS 코드를 읽어서 전처리한 다음 컴파일해서 전역 CSS 번들 파일을 만들어 주는 전처리기(preprocessor)의 역할을 한다.</p>
<p>하지만 이러한 ‘CSS의 구조화’는 스타일이 겹치는 문제를 해결하기 위해 단순히 계층 구조를 만들어 내는 것에 의지하게 되었고, 그 결과 컴파일된 CSS의 용량은 어마어마하게 커지게 되었다.</p>
<h3 id="css-방법론">CSS 방법론</h3>
<hr>
<p>CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두되었다. </p>
<p>이 세 방법론은 4개의 공통 지향점을 가지고 있다.</p>
<ol>
<li>코드의 재사용</li>
<li>코드의 간결화 (유지 보수 용이)</li>
<li>코드의 확장성</li>
<li>코드의 예측성 (클래스 명을 통한 예측가능)</li>
</ol>
<p>이런 CSS 방법론들 협업시에도 연결되기 때문에 협업시 CSS 작성에 있어서 방법들을 규칙으로 정해두는 것은 매우 중요하다.</p>
<h4 id="bem">BEM</h4>
<p>대표적인 CSS 방법론인 BEM은 Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법이며, Block, Element, Modifier 각각은 <code>—</code> 와 <code>__</code> 로 구분한다. 
클래스명은 BEM 방식의 이름을 여러 번 반복하여 재사용할 수 있도록 하며 HTML/CSS/SASS 파일에서도 더 일관된 코딩 구조를 만들어 준다. </p>
<p>하지만 이는 클래스명 선택자가 정황해지고, 이 때문에 마크업이 불필요하게 커져 재사용시 모든 UI컴포넌트를 명시적으로 확장해야만했다. 또한 언어 로직 상에 진정한 캡슐화의 개념이 없어 개발자들이 유일한 클래스명을 선택하는 것에 의존할 수밖에 없었다.</p>
<ul>
<li>캡슐화(encapsulation) : 객체의 속성과 행위를 하나로 묶고 실제 구현 내용 일부를 외부에 감추어 은닉하는 개념</li>
</ul>
<h2 id="css-in-js">CSS in JS</h2>
<hr>
<p>애플리케이션으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔다. 하지만 CSS는 컴포넌트 기반의 방식을 위해 만들어지지 않았기에 컴포넌트 영역으로 불러들이기 위해서 CSS-in-JS가 탄생했다. 이는 JavaScript코드에서 CSS를 작성하는 방식을 말한다.</p>
<h3 id="styled-component">Styled-Component</h3>
<p> CSS-in-JS에는 대표적으로 Styled-Component가 있다. Styled-Component는 기능적(Functional) 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공한다.</p>
<h2 id="각-css-방법론의-특징과-장-단점">각 CSS 방법론의 특징과 장, 단점</h2>
<hr>
<p> <img src="https://velog.velcdn.com/images/1aba_can_opener/post/49eaeecb-c2c2-4f55-9872-ac50283c5f4c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git 기본 용어 및 명령어]]></title>
            <link>https://velog.io/@1aba_can_opener/Git</link>
            <guid>https://velog.io/@1aba_can_opener/Git</guid>
            <pubDate>Mon, 17 Apr 2023 15:30:45 GMT</pubDate>
            <description><![CDATA[<h2 id="git">Git</h2>
<hr>
<p>Git이란 개발자의 코드를 효율적으로 관리하기 위해 개발된 &#39;분산형 버전 관리 시스템&#39;이다. Git에서는 소스 코드가 변경된 이력을 쉽게 확인할 수 있고, 특정 시점에 저장된 버전과 비교하거나 특정 시점으로 되돌아갈 수도 있다. 통합하자면 소스 코드 기록을 관리하고 추적할 수 있는 버전 관리 시스템이라고 할 수 있다. </p>
<h2 id="github">Github</h2>
<hr>
<p>Github은 Git Repository를 관리할 수 있는 클라우드 기반 서비스로 Git으로 버전을 관리하는 폴더에 대해 Github를 통해 여러 사람들이 공유하고 접근 할 수 있는 것이다. </p>
<h2 id="git-repository">Git repository</h2>
<hr>
<p>내가 작업하는 소스 코드 폴더가 버전 관리를 받게 하기 위해서는 내 폴더를 Git의 관리 아래에 두어야 하는데 이때 이 Git으로 관리되는 폴더를 Git Respository라고 한다. </p>
<p>Git repository 는 Remote Repository와 Local Repository 두 종류의 저장소를 제공한다. 작업할 때는 Local Repository에서 할 수 있고 내가 작업한 코드를 공유하려면 Remote Repository에 업로드해 여러 사람이 함께 공유할 수 있다. 또한 다른 사람이 Remote Repository에 올려놓은 소스 코드를 내 Local Repository 로 가지고 올 수도 있다.</p>
<h2 id="git-기본-용어-및-명령어">Git 기본 용어 및 명령어</h2>
<hr>
<h3 id="fork">Fork</h3>
<p>다른 사람이 Remote Repository에 올려놓은 소스 코드를 내 Remote Repository 로 가지고 올 때의 과정을 Fork 라고 한다. 이렇게 Fork 를 통해 가져온 코드를 수정하기 위해서는 Local Repository로 가져오는 작업이 또 필요하다.</p>
<h3 id="clone">Clone</h3>
<p>fork 를 통해 가져온 코드를 수정하기 위해서는 Local Repository로 가져오는 과정이 필요한데 이를 clone이라고 한다.</p>
<ul>
<li><code>git clone 주소</code> 명령어를 사용한다.</li>
</ul>
<h3 id="commit">Commit</h3>
<p>내 컴퓨터로 가져온 코드를 수정하고 변경하는 작업을 완료했다면 이 내용을 저장해주어야 하는데 이 과정이 commit이다. 이를 통해 내 Local Repository에 저장할 수 있다.</p>
<ul>
<li><code>git commit</code> 명령어를 사용한다.</li>
<li><code>git commit -m &#39;메세지&#39;</code> 명령어를 통해 메세지를 남겨 변경 혹은 추가된 정보를 적을 수 있다.</li>
</ul>
<h3 id="push">Push</h3>
<p>내 Local Repository에 수정된 작업본이 저장되었다면 이를 Remote Repository 로 올려주는 작업이 필요하다. 이 과정을 push 라고 하며 Local Repository에 기록해 놓은 commit을 Remote Repository로 업로드할 수 있다. </p>
<ul>
<li><code>git push Remote repository명 브랜치명</code> 명령어 를 사용한다.</li>
</ul>
<h3 id="pull-request">Pull request</h3>
<p>이렇게 Push를 완료하고 나면 GitHub에 있는 Pull request라는 기능을 사용해 내가 제안한 코드 변경사항에 대해 반영 여부를 요청할 수 있다. </p>
<h3 id="pull">Pull</h3>
<p>Remote Repository에서 변경 사항이 있을 땐 Pull을 통해 Local Repository 로 가져올 수 있다.</p>
<ul>
<li><code>git pull</code> 명령어를 사용한다</li>
</ul>
<h3 id="branch">Branch</h3>
<p>커밋을하며 계속 코드를 짜다보면 새로운 기능을 추가하는 경우가 생길 수 있다. 그럴 때는 원본파일에 코드를 추가하고 커밋하기보단 원본파일은 유지하면서 지금까지의 프로젝트의 복사본을 만들어 먼저 개발해보는 것이 더 좋은 방법이다. </p>
<p>이때 git에서 branch 기능을 이용하면 복사본을 쉽게 만들 수 있다. 또한 협업시에도 이 기능이 상당히 유용하다. 만약 여러 개발자가 동시에 똑같은 소스 코드를 수정하고 저장한다면 상당히 혼란스러운 경우가 일어날 것이다. branch기능을 통해 각자 원본 소스를 복사해 수정후 다시 합치는 방법을 사용한다면 훨씬 안정적으로 개발이 가능하다.</p>
<ul>
<li><code>git branch 브랜치명</code> 명령어를 사용한다.</li>
<li><code>git switch 브랜치이름</code> 명령어를 통해 해당 브랜치로 이동할 수 있다.</li>
</ul>
<h3 id="merge">Merge</h3>
<p>브랜치에서 짰던 코드를 원본코드와 합치고 싶다면 원본코드가 있는 master혹은 main 브랜치에 합치면 된다. 이때 브랜치를 합치는 것을 merge라고 한다. merge가 하고싶다면</p>
<ul>
<li><code>git switch main/master브랜치</code> main 혹은 master 브랜치로 다시 이동하고 </li>
<li><code>git merge 브랜치명</code> 을 입력하면 된다. </li>
</ul>
<p>이때 만약 master/main 브랜치와 새로생성한 브랜치에서 같은 파일, 같은 줄을 수정했을 경우 merger confilct가 발생한다. 이 경우 에디터로 해당 파일을 열어보면 충돌사항이 적혀있다. 이때 둘중 어떤 코드를 적용할 지 골라 원하는 코드만 남기고 지운후 </p>
<ul>
<li><code>git add 파일명</code> 를 터미널에 입력후</li>
<li><code>git commit -m &#39;메세지&#39;</code> 를 통해 새로운 커밋을 생성해주면 된다.</li>
</ul>
<h3 id="git-init">git init</h3>
<p>Local Repository에서 클론이 아닌 새로운 작업을 git을 통해 버전관리하고 싶다면 해당 폴더에서</p>
<ul>
<li><code>git init</code> 명령어를 터미널에 작성하면 된다. </li>
</ul>
<h3 id="git-add">git add</h3>
<p>git을 통해 관리되고 있는 폴더내의 파일의 버전을 생성해주고싶다면 </p>
<ul>
<li><code>git add 파일명.파일확장명</code> 명령어를 터미널에 작성해 실행시키고 </li>
<li><code>git commit -m &#39;메세지&#39;</code> 명령어를 터미널에 작성해주면 된다.</li>
</ul>
<p>작업 폴더 내에서 <code>git add</code> 를 통해 기록을 남기고 싶은 파일을 고른후 <code>git commit</code>을 통해 기록저장소에 옮기는 형식이다. 이때 작업 폴더에서 파일을 고르는 행위를 staging 한다고 하며 파일을 고르면 staging area에 들어가게 되며 <code>git commit</code>시 repository로 옮겨진다. </p>
<ul>
<li><code>git add 파일명1.파일확장명 파일명2.파일확장명</code> 명령어를 사용해 여러 파일을 스테이징 할 수 있다.</li>
<li><code>git add .</code> 명령어를 사용해 모든 파일을 스테이징 할 수 있다.</li>
</ul>
<h3 id="git-status">git status</h3>
<p>어떤 파일들을 스테이징 해놨는지, 수정했는지 등의 상태를 보여준다. </p>
<ul>
<li><code>git status</code> 명령어를 터미널에 작성하면 된다. </li>
</ul>
<h3 id="git-log">git log</h3>
<p>커밋한 로그들을 볼 수 있다.</p>
<ul>
<li><code>git log</code> 명령어를 터미널에 작성하면 된다. </li>
</ul>
<hr>
<p><a href="https://github.com/mingrammer/git-tips#20%EA%B0%9C-%EB%82%B4%EC%99%B8%EC%9D%98-%EB%AA%85%EB%A0%B9%EC%96%B4%EB%A1%9C-git-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0">그 외 다양한 git 명령어 보러가기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[User Flow]]></title>
            <link>https://velog.io/@1aba_can_opener/User-Flow</link>
            <guid>https://velog.io/@1aba_can_opener/User-Flow</guid>
            <pubDate>Wed, 12 Apr 2023 18:17:47 GMT</pubDate>
            <description><![CDATA[<h2 id="user-flow">User Flow</h2>
<hr>
<p>사용자 흐름이라고도 불리는 User Flow는 사용자가 제품에 진입한 시점을 시작으로 취할 수 있는 모든 행동을 뜻하며 보통 다이어그램을 그려 정리한다.
<img src="https://velog.velcdn.com/images/1aba_can_opener/post/e9021461-157c-4fed-8951-528ebe1ba3af/image.png" alt=""></p>
<h3 id="user-flow-다이어그램-작성법">User Flow 다이어그램 작성법</h3>
<hr>
<p>사용자 흐름을 다이어 그램으로 작성시 기본적으로 세가지 요소를 사용한다. 
<img src="https://velog.velcdn.com/images/1aba_can_opener/post/e659f598-7c8c-41e6-8911-0287b42dd49b/image.png" alt=""></p>
<ul>
<li><p>직사각형: 사용자가 보게될 화면</p>
<ul>
<li>ex. 회원 가입 페이지, 로그인 페이지</li>
</ul>
</li>
<li><p>다이아몬드: 사용자가 취하게 될 행동</p>
<ul>
<li>ex. 로그인, 버튼 클릭, 업로드</li>
</ul>
</li>
<li><p>화살표: 직사각형(화면)과 다이아몬드(행동)를 연결시켜주는 화살표</p>
</li>
</ul>
<h3 id="user-flow-다이어그램의-장점">User Flow 다이어그램의 장점</h3>
<hr>
<p>사용자 흐름 다이어 그램의 장점</p>
<ul>
<li><p>사용자 흐름상 어색하거나 매끄럽지 않은 부분을 발견하여 수정할 수 있다.</p>
</li>
<li><p>있으면 좋은 기능을 발견하여 추가하거나 없어도 상관없는 기능을 발견하고 삭제할 수 있다.</p>
</li>
</ul>
<p>그렇기에 User flow 다이어그램을 그리면서 사용자 흐름을 빈틈 없이, 보다 더 편리하게 다듬어 나가는 과정을 거치면 UX를 개선할 수 있습니다.</p>
<h3 id="user-flow-다이어그램-도구">User Flow 다이어그램 도구</h3>
<hr>
<p>User Flow 다이어그램을 편리하게 그릴 수 있는 도구</p>
<ul>
<li><a href="https://miro.com/ko/">Miro</a></li>
<li><a href="https://www.figma.com/figjam/">FigJam</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[좋은 UX를 만드는 요소]]></title>
            <link>https://velog.io/@1aba_can_opener/%EC%A2%8B%EC%9D%80-UX%EB%A5%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@1aba_can_opener/%EC%A2%8B%EC%9D%80-UX%EB%A5%BC-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Wed, 12 Apr 2023 18:08:21 GMT</pubDate>
            <description><![CDATA[<h2 id="좋은-ux를-만드는-요소">좋은 UX를 만드는 요소</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/843a1375-e09d-40ca-9921-96829525ab90/image.png" alt=""></p>
<p>피터 모빌(Peter Morville)의 벌집 모형은 좋은 UX를 만드는 요소에 대한 답을 준다. 이 모형에서는 UX의 7가지 요소를 제시한다.</p>
<h3 id="유용성-useful--사용-가능한가">유용성 (Useful) : 사용 가능한가?</h3>
<p>유용성은 제품이나 서비스가 목적에 맞는 사용가능한 기능을 제공하는지에 대한 요소다. 여기에는 꼭 목적에 맞지 않거나 비실용적이라도 추가적인 기능을 제공하는 지도 관련이 있다. 예를 들어 계산기의 디자인은 계산기의 기능 자체에는 영향을 주지 않지만 심미적 기능을 제공한다고 판단한다.</p>
<h3 id="사용성usable--사용하기-쉬운가">사용성(Usable) : 사용하기 쉬운가?</h3>
<p>사용성은 제품이 본연의 기능을 제공하는 것을 넘어 사용하기 쉬운가에 관한 요소다. 기능이 잘 작동해도 사용하기 어렵다면 좋은 UX를 제공하기 어렵다. 가능한 단순하면서 직관적이고 사용하기 쉬운 제품이나 서비스를 만들어야한다. 이 요소는 UI 디자인 패턴과도 연관이 깊다. 자주 쓰이는 패턴들은 사용자들에게도 친숙할 가능성이 높아 사용성을 높여준다. </p>
<h3 id="매력성desirable--매력적인가">매력성(Desirable) : 매력적인가?</h3>
<p>매력성을 제품이 사용자들에게 매력적인가에 대한 요소이다. 단순히 디자인이 보기에 좋은 지부터 이미지, 브랜딩 등의 여러 요소들이 사용자에게 긍적적 감정을 불러올 수 있는지, 해당 제품이나 서비스를 이용하고 싶어 하는지가 중요하다. 애플이 디자인에 공을 들이고 감성 마케팅을 사용하는 것이 이 요소와 연관이 깊다.</p>
<h3 id="신뢰성credible--신뢰할-수-있는가">신뢰성(Credible) : 신뢰할 수 있는가?</h3>
<p>신뢰성은 사용자가 제품이나 서비스를 믿고 사용할 수 있는가에 관한 요소다. 결함이 있는 제품을 속여 판매하거나 과장하여 홍보한다거나 사용자의 개인정보를 유출하는 등 사용자의 신뢰성을 떨어뜨리는 일이 없어야한다. 장기적으로 믿을 수 있는 브랜드 이미지를 구축하는 것이 좋다.</p>
<h3 id="접근성accessible--접근하기-쉬운가">접근성(Accessible) : 접근하기 쉬운가?</h3>
<p>접근성은 누구든지 제품이나 서비스에 접근할 수 있는가에 관한 요소다. 고 연령대 사용자들을 위한 돋보기 기능이나 시각 장애인들을 위한 음성 안내기능 등 누구라도 비슷한 수준의 정보를 얻을 수 있도록 장치를 구비해놓는 노력등이 접근성을 높인다. </p>
<h3 id="검색-가능성findable--찾기-쉬운가">검색 가능성(Findable) : 찾기 쉬운가?</h3>
<p>검색 가능성은 사용자가 원하는 기능이나 정보를 쉽게 찾을 수 있는가에 관한 요소다. 웹사이트의 경우 사용자가 특정페이지에 접근하고자 할 때 찾기 힘들다면 좋은 UX를 주기 어렵다. 내비게이션 바, 정보 검색 기능을 넣거나 콘텐츠 배치를 직관적으로 하는 것이 검색 가능성을 높인다. 유튜브가 이 요소의 좋은 예시중 하나다.</p>
<h3 id="7-가치성valuable--가치를-제공하는가">7. 가치성(Valuable) : 가치를 제공하는가?</h3>
<p>가치성은 모든 요소들을 총합하여 고객에게 가치를 제공하고 있는가에 관한 요소다. 사용자마다 가치판단 기준과 그 정도는 다 다르다. 예를 들어 접근성에 모든 노력을 기울였다고 해도 사용자가 접근성을 중요히 생각치 않는다면 가치를 제공하지 못할 수도 있다. 따라서 가능한 모든 요소를 고르게 고려하는 것이 좋고 사용자들이 공통적으로 중요히 생ㅇ각하는 요소를 찾아 그 요소에 집중하는 것도 UX를 효율적으로 개선하는 전략이 될 수 있다.</p>
<hr>
<p>피터 모빌의 벌집 모형은 UX를 위해서 고려해야 할 7가지 요소를 제시해 줌과 동시에 그래프를 활용해 UX를 얼마나 고려했는지나 사용자가 얼마나 좋은 UX를 경험했는지 평가하기 위한 척도로도 사용된다. 후에 UX를 개선하고자 할 때, 사용자 설문조사를 통해 개선점을 찾아 낼 수도 있다. 
<img src="https://velog.velcdn.com/images/1aba_can_opener/post/4d3bc1cf-b877-497f-8233-54077f675f0e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/2383272b-031d-4c27-9ab9-7a8d343b8d93/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자주쓰이는 UI 디자인 패턴]]></title>
            <link>https://velog.io/@1aba_can_opener/%EC%9E%90%EC%A3%BC%EC%93%B0%EC%9D%B4%EB%8A%94-UI-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@1aba_can_opener/%EC%9E%90%EC%A3%BC%EC%93%B0%EC%9D%B4%EB%8A%94-UI-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Wed, 12 Apr 2023 17:46:24 GMT</pubDate>
            <description><![CDATA[<h2 id="자주쓰이는-ui-디자인-패턴">자주쓰이는 UI 디자인 패턴</h2>
<hr>
<h3 id="모달-modal">모달 (Modal)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/26464a0b-947b-46ff-a5f8-58b8a6e21044/image.png" alt=""></p>
<p>모달은 기존에 이용하던 화면 위에 오버레이 되는 창을 말한다. 닫기 버튼이나 모달 범위 밖을 클릭시 모달이 닫히는 것이 일반적이며 모달을 닫기 전에는 기존 화면과의 상호작용이 불가능하다. </p>
<p>이는 브라우저 페이지를 여는 팝업창과는 구분된 개념으로 팝업은 브라우저에 의해 강제로 막힐 수 있지만 모달은 브라우저 설정에 영향을 받지 않기에 꼭 전달해야할 내용은 모달사용을 추천한다.</p>
<h3 id="토글-toggle">토글 (Toggle)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/abc19d26-1d89-4fea-895b-ef99cfd606e0/image.png" alt=""></p>
<p>토글은 On/Off 설정시 사용하는 스위치 버튼이다. 색상, 스위치의 위치, 그림자 등의 시각적 효과를 주어 사용자가 토글의 상태를 직관적으로 알 수 있게 만들어야한다. </p>
<p>뿐만아니라 3개 이상의 여러개의 옵션이 있을 때에도 토글을 사용하는 경우가 있으므로 어느 옵션이 선택되어 있는지 직관적으로 알 수 있어야 하며 옵션의 개수가 많다면 탭 사용을 고려하길 바란다.</p>
<h3 id="탭-tab">탭 (Tab)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/8eec8911-0e6a-4d50-a8ad-30fe178349f1/image.png" alt=""></p>
<p>탭은 콘텐츠를 분리해서 보여주고 싶을 대 사용한다. 가로로 한 줄로 배열된 형태가 가장 흔하지만 여러 형태로도 나타낼 수 있다.</p>
<p>탭 사용시에는 각 섹션의 이름이 너무 길지 않아야하며 섹션의 구분이 명확하고 현재 어떤 섹션을 보고 있는지 표시해 주어야한다.</p>
<h3 id="태그-tag">태그 (Tag)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/678d932e-251b-49f8-b74d-c4672931b372/image.png" alt=""></p>
<p>태그는 콘텐츠를 설명하는 키워드를 사용해 라벨을 붙이는 역할을 한다. 사용자들은 자신이 작성한 콘텐츠에 태그를 붙여 콘텐츠를 분류할 수 있고 태그를 사용해 관련 콘텐츠만 검색할 수도 있다.</p>
<p>태그로 사용될 키워드는 사용자가 직접 작성하거나 개발자가 종류를 아예 정해놓으면 된다. 이때 태그의 추가와 제거는 자유롭게 할 수 있어야한다. </p>
<h3 id="자동완성-autocomplete">자동완성 (Autocomplete)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/60eeef9b-7b6c-4ec2-8e75-e4dd2dcf3a54/image.png" alt=""></p>
<p>자동완성은 사용자가 내용일 입력 중일 때 사용자가 입력하고자 하는 내용과 일치할 가능성이 높은 항목을 보여주는 것이다. 사용자가 정보를 직접 입력하는 시간을 줄여주며 정보를 검색할 때 많이 사용한다.</p>
<p>자동 완성 항목은 너무 많은 항목이 나오지 않도록 개수제한을 두는 것이 좋으며 키보드 방향키나 클릭등으로 접근하여 사용할 수 있는 것이 좋다.</p>
<h3 id="드롭다운-dropdown">드롭다운 (Dropdown)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/7018f4fc-d69e-4008-8c57-7eb7316d9e45/image.png" alt=""></p>
<p>드롭다운은 선택할 수 있는 항목들을 숨겨놓았다가 펼쳐지면서 선택할 수 있게 해주는 UI 디자인 패턴이다. </p>
<p>객관식 문제의 선택지와 비슷한 개념으로 보통 화살표 버튼을 누르면 펼쳐지게 만들지만 마우스를 올려놓기만 해도 펼쳐지게 만들 수도 있다. 여기서 중요한것을 펼쳐지는 방식이 아니라 사용자가 자신이 선택한 항목을 정확히 알 수 있게 만드는 것이다. </p>
<h3 id="아코디언-accordion">아코디언 (Accordion)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/afff5de3-6abd-4daf-b6a5-b46ff7da4e54/image.png" alt=""></p>
<p>아코디언은 접었다 폈다 할 수 있는 컴포넌트로 보통 같은 분류의 아코디언을 여러 개 연속해 배치한다. 트리 구조의 콘텐츠를 렌더링 할 때 사용하거나 메뉴바로 사용할 수도 있지만 단순히 콘텐츠를 담아놓기 위한 용도로도 쓰인다. </p>
<p>기본적으로는 화면을 깔끔히 구성하기 위해 사용하며 트리 구조나 메뉴바로 사용시 상하 관계 표현을 위해 사용하는 경우가 많고 콘텐츠를 담는 용도일 때에는 핵심 내용을 먼저 전달하려는 목저을 가질 때가 많다.</p>
<h3 id="캐러셀-carousel">캐러셀 (Carousel)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/11f535b7-2dcc-4359-a2d1-dceb0fab17cd/image.png" alt=""></p>
<p>캐러셀은 컨베이어 벨트, 또는 회전목마라는 뜻으로 돌아가며 콘텐츠를 표시해주는 UI 디자인 패턴이다. 자동으로 돌아가거나 사용자가 옆으로 넘겨야만 넘어가거나 둘중 선택할 수 있도록 만들 수 있다. </p>
<p>사용자가 넘겨야만 넘어가도록 만드는 경우 콘텐츠가 넘어갈 수 있음을 직관적으로 알 수 있어야 하기에 다름 콘텐츠의 일부를 옆에 배치하거나 콘텐츠를 넘길 수 있는 버튼을 배치하기도 한다. </p>
<h3 id="페이지네이션-pagination">페이지네이션 (Pagination)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/e6f7b50d-ffeb-4fbc-a57d-616d7b4ae53c/image.png" alt=""></p>
<p>페이지네이션은 한 페이지에 띄우기에 정보가 너무 많은 경우 번호를 붙여 페이지를 구분해 주는 것을 말한다. 사용자가 원하는 페이지로 바로 접근할 수 있다는 장점이 있지만 페이지를 넘기기 위해 잠시 멈춰야하기에 매끄러운 사용자 경험이라고 보기 어렵다는 단점이 있다.</p>
<h3 id="무한-스크롤-infinite-scroll-continuous-scroll">무한 스크롤 (Infinite Scroll, Continuous Scroll)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/554bf845-359a-4b94-9b96-407b40e9d3fa/image.png" alt=""></p>
<p>무한 스크론을 모든 콘텐츠를 불러올 때까지 무한으로 스크롤을 내릴 수 있는 것을 말하며 한번에 띄우기엔 정보가 너무 많을 때 사용한다. </p>
<p>페이지네이션과 달리 잠시 멈춰서 페이지 선택할 필요가 없기에 보다 더 매끄러운 사용자 경험을 제공한다. 하지만 끝이 어딘지 알 수 없다는 점과 지나친 콘텐츠를 찾기 힘들다는 점등의 단점이 있다.</p>
<p>보통 페이지의 맨 아래에 도달하면 추가 콘텐츠를 로드해오는 방식으로 만든다. 처음부터 모든 콘텐츠를 로드 해온 후 조금씩 보여주는 방식은 무한 스크롤로 보기 어려우므로 주의해야한다.</p>
<h3 id="gnb-global-navigation-bar---lnb-local-navigation-bar">GNB (Global Navigation Bar) &amp;  LNB (Local Navigation Bar)</h3>
<p><img src="https://velog.velcdn.com/images/1aba_can_opener/post/ad6666ab-5c7b-45f5-af26-4870b43c1f76/image.png" alt=""></p>
<p>GNB는 어느 페이지에 들어가든 사용가능한 최상위 메뉴, LNB는 GNB에 종속되는 서브 메뉴나 특정 페이지에서만 볼수 있는 메뉴를 뜻한다. GNB는 어느 페이지에 있든 사용할 수 있도록 항상 동일한 위치에 있어야한다. </p>
<hr>
<p>이 외에도 다양한 종류의 UI 디자인 패턴은 <a href="https://ui-patterns.com/patterns">ui-patterens.com</a> 에서 찾아 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[UI/UX]]></title>
            <link>https://velog.io/@1aba_can_opener/UIUX</link>
            <guid>https://velog.io/@1aba_can_opener/UIUX</guid>
            <pubDate>Wed, 12 Apr 2023 17:45:11 GMT</pubDate>
            <description><![CDATA[<h2 id="ui-user-interface">UI (User Interface)</h2>
<hr>
<p>UI(사용자 인터페이스)는 사람들이 컴퓨터와 상호작용하는 시스템을 의미한다. 화면상의 그래픽요소는 물론 키보드, 마우스 등의 물리적 요소도 컴퓨터와 상호 작용하기 위한 시스템이기에     UI라고 볼 수 있다. 이 중 최근 스마트폰, 컴퓨터, 키오스크, 터치 스크린 안내판 등 현대 사회에서 화면과의 상호 작용을 통해 사용하는 기기들은 점차 늘어감에따라 그래픽 UI, 즉 GUI(Graphical User Interface)의 비중이 높아지며 특히 중요해졌다.</p>
<h3 id="gui-graphical-user-interface">GUI (Graphical User Interface)</h3>
<hr>
<p>GUI(그래픽 사용자 인터페이스)는 사용자가 그래픽을 통해 컴퓨터와 정보를 교환하는 작업환경을 말한다. 우리가 보는 운영체제(Window, Mac OS)의 화면, 혹은 애플리케이션 화면 등이 이에 속한다. 프론트엔트 개발자로서의 UI는 대부분 GUI를 의미한다.</p>
<h2 id="uxuser-experience">UX(User Experience)</h2>
<hr>
<p>UX(사용자 경험)의 사전적 의미는 사용자가 어떤 시스템, 제품, 서비스를 직-간접적으로 이용하며 느끼고 생각하는 총체적 경험이다. 제품, 서비스 그 자체에 대한 경험, 홍보, 접근성, 사후 처리등의 사용자의 총체적경험인 것이다. </p>
<p>UX에 영향을 주는 이 많은 요소 중에 프론트엔드 개발에게 가장 중요한 요소는 UI이다. 따라서 제품이나 서비스의 UI가 사용자로 하여금 가능하면 좋은 UX가질수 있도록, 최소한 나쁜 경험을 하지 않도록 해야한다.</p>
<h2 id="ui와-ux의-관계">UI와 UX의 관계</h2>
<hr>
<p>UX는 UI를 포함한다. 좋은 UX는 좋은 UI를 의미하나 좋은 UI가 좋은 UX를 보장하지는 않는다. 이처럼 UX와 UI는 다르지만 서로를 보완하는 역할을 한다. UX가 좋지 않은 곳을 찾아냄을 UI 개선점을 찾아내거나 UI를 개선함으로 UX가 좋아지는 등의 보완이 되는 것이다. </p>
<h2 id="ui-디자인">UI 디자인</h2>
<hr>
<p>UI 디자인 패턴은 프로그래밍 시 자주 반복되어 나타나는 문제점을 해결하고자 과거의 다른 사람이 해결한 결과물을 재사용하기 좋은 형태로 만든 패턴을 말한다. 쉽게 말하면 자주 사용되는 UI 컴포넌트라고 할 수 있다. </p>
<p>자주 쓰이는 UI 디자인 패턴을 익혀두면 UI 디자인이 보다 쉬워지고 프론트엔드 개발자, 디자이너, PM 과의 의사소통도 원활해져 협업 효율도 높아진다.</p>
<ul>
<li><a href="https://velog.io/@1aba_can_opener/%EC%9E%90%EC%A3%BC%EC%93%B0%EC%9D%B4%EB%8A%94-UI-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4">자주 쓰이는 UI 디자인패턴</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>