<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>denmark-banana.log</title>
        <link>https://velog.io/</link>
        <description>FrontEnd Developer with React, TypeScript</description>
        <lastBuildDate>Tue, 02 Mar 2021 09:42:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>denmark-banana.log</title>
            <url>https://images.velog.io/images/denmark-banana/profile/951e4bc0-2e30-11ea-bee6-3b199617cc88/velog프로필.PNG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. denmark-banana.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/denmark-banana" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[useSWR - Get 요청 시 fetcher 함수에 인자 넣어주기]]></title>
            <link>https://velog.io/@denmark-banana/useSWR-arguments</link>
            <guid>https://velog.io/@denmark-banana/useSWR-arguments</guid>
            <pubDate>Tue, 02 Mar 2021 09:42:17 GMT</pubDate>
            <description><![CDATA[<h2 id="swr---arguments">SWR - Arguments</h2>
<p><img src="https://images.velog.io/images/denmark-banana/post/d3c13e37-c707-47cc-bb68-fb34655ccab4/swr.png" alt=""></p>
<h3 id="1-arguments-🍓">1. Arguments 🍓</h3>
<p>useSWR을 사용하던 중 fetcher에 인자로 데이터를 보내야해서 <a href="https://swr.vercel.app/docs/arguments">공식문서</a>를 참고하였다.</p>
<pre><code class="language-ts">useSWR(&#39;/api/user&#39;, () =&gt; fetcher(&#39;/api/user&#39;))
useSWR(&#39;/api/user&#39;, url =&gt; fetcher(url))
useSWR(&#39;/api/user&#39;, fetcher)

//fetcher
const fetcher = (url: string) =&gt; axios.get(url).then(result);</code></pre>
<p>2번째 인자로 fetcher로 넣을때 위 3개의 expression은 같은 의미를 갖는다.
useSWR은 기본으로 첫번째 인자인 key를 fetcher 인자(url)로 넣어준다.</p>
<h3 id="2-multiple-🥝">2. Multiple 🥝</h3>
<p>인자를 복수개로 넘기려면 어떻게 해야할까? API 요청시에 Auth Token을 넘겨야 하는 상황이다.</p>
<pre><code class="language-ts">const token = &#39;#123&#39;;
useSWR(&#39;/api/user&#39;, url =&gt; fetchWithToken(url, token))

//fetcher
const fetcherWithToken = (url: string, token: string) =&gt;
  axios
    .get(url, {
      headers: {
        Authorization: `Bearer ${data.access_token}`,
      },
    })
    .then(result =&gt; result.data);</code></pre>
<p>이런식으로 넘기면 될듯 하다. 물론 정상적으로 fetcher 함수에 인자는 전달되고 요청은 정상적으로 진행된다. </p>
<p>하지만 컴포넌트에서 token값이 변경된다면? useSWR은 첫번째 인자인 &#39;/api/user&#39; = key값을 기준으로 데이터를 캐싱해둔다. token값이 변경되어도 이전의 token으로 요청한 데이터를 가지고 있을 것이고 이것은 사용자가 예상하는 값이 아니다. 해결 방법이 있을까?</p>
<h4 id="key를-array형태로-변경하는-방법">key를 Array형태로 변경하는 방법</h4>
<pre><code class="language-ts">const token = &#39;#123&#39;;
useSWR([&#39;/api/user&#39;, token], url =&gt; fetchWithToken(url, token))</code></pre>
<p>token이 변경되면 다시 요청할 수 있는 방법은 key를 배열로 사용하면 된다. 이제 key값이 변경되면 해당 요청을 다시 진행한다. (useEffect의 deps와 유사하다..!)</p>
<h3 id="3-passing-object-🍇">3. Passing Object 🍇</h3>
<p>위의 내용들을 이용하면 한 단계 넘어가서 useSWR 요청들끼리의 조건부 실행도 가능할 것 같다. </p>
<pre><code class="language-ts">const { data: user } = useSWR([&#39;/api/user&#39;, token], fetchWithToken)
const { data: orders } = useSWR(user ? [&#39;/api/orders&#39;, user] : null, fetchWithUser)</code></pre>
<p>아래의 &#39;/api/orders&#39;에 대한 요청은 &#39;/api/users&#39; 요청이 성공하여 user가 있을 경우에만 호출된다. user가 stable value인 경우에는 해당 로직은 정상적으로 진행이 된다. </p>
<p>하지만 user가 객체라면? useSWR은 useEffect와 마찬가지로 argument의 변화를 체크할 때 &#39;얕은 비교(shallow compare)&#39;를 사용한다.</p>
<pre><code class="language-ts">const obj1 = { 1: &#39;red&#39;, 2: &#39;yellow&#39; }
const obj2 = { 1: &#39;red&#39;, 2: &#39;yellow&#39; };
console.log((obj1 === obj2) ? &#39;지금은 맞다&#39; : &#39;그때는 틀리다&#39;);
//그때는 틀리다   출력!</code></pre>
<p>그러므로 위의 /api/orders&#39;에 대한 요청은 무한히 이루어지게 된다. (실제 테스트해보니 내 브라우저가 마치 디도스 공격을 하듯이 서버 요청을 연달아서 보냈다...😨)</p>
<h4 id="key로-사용할-인자는-stable-value-여야-한다">key로 사용할 인자는 stable value 여야 한다</h4>
<pre><code class="language-ts">const [name, setName] = useState(&#39;&#39;);
const [phone, setPhone] = useState(0);
const paramData = {
  name,
  phone
};

// 이렇게 요청을 보내면 매 렌더링 시에 paramData 부분은 같지 않다. (무한 요청)
useSWR([&#39;/api/user&#39;, paramData], url =&gt; fetcher(url, paramData));

// stable 변수를 key로 사용하면 정상적으로 한번만 요청 진행
useSWR([&#39;/api/user&#39;, name, phone], (url) =&gt; fetcher(url, paramData));</code></pre>
<p>아래의 예와 같이 array 인자에 state들을 연결시켜주면 name이나 phone 상태가 변경되었을 시에 재요청이 가능하다..!</p>
<h3 id="4-참고자료-🍉">4. 참고자료 🍉</h3>
<p><a href="https://swr.vercel.app/docs/arguments">공식문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 에서 Pre-rendering (SSG, SSR)과 useSWR(CSR) 잘 융합하기]]></title>
            <link>https://velog.io/@denmark-banana/Nextjs-PreRendering-useSWR</link>
            <guid>https://velog.io/@denmark-banana/Nextjs-PreRendering-useSWR</guid>
            <pubDate>Mon, 22 Feb 2021 10:19:49 GMT</pubDate>
            <description><![CDATA[<p>요즈음😁 자주 사용하는 useSWR(Data Fetching 라이브러리)을 통해 페이지를 렌더링 해보았다.
SWR 함수는 1개의 인자를 필수로 받는다. 자세한 사용법과 내용은 코드에 포함되어 있다..!</p>
<h3 id="useswrkey-fetcher-option-함수">useSWR(key, fetcher, option) 함수</h3>
<ol>
<li>key: fetcher에게 전달되는 인자(보통 URL)</li>
<li>fetcher: 데이터 fetch하는 함수 (axios, fetch 등을 넣으면 됨)</li>
<li>option 객체: revalidate, mutate, initialData 등을 넣어줄 수 있으며 자세한 기능은 <a href="https://swr.vercel.app/">공식문서</a> 참고</li>
</ol>
<pre><code class="language-ts">//index.tsx
const fetcher = (url: string) =&gt; axios.get(url);

const Home = ({ homeInitialData }) =&gt; {
  const { datas, error } = useSWR(URL.HOME, fetcher, {
    //initial props로 넘어온 homeInitialData를 swr캐시에 저장
    //swr는 캐시에 데이터가 있기 때문에 component가 최초 렌더링될때 요청을 보내지 않는다. 
    initialData: homeInitialData,
  });

  /**
    * 대신 다른 화면을 갔다와서 포커싱하거나 
    * 혹은 사용자의 설정에 따라 원하는 순간에 revalidate하면
    * swr은 데이터를 재요청하여 캐시에 있는 데이터를 갱신한다..!
    * Client-Side-Rendering
    */

  return &lt;div&gt;{datas.map(data =&gt; &lt;span&gt;{data}&lt;/span&gt;}&lt;/div&gt;
} 

/**
* Pre-Rendering
* 서버에서 API요청을 직접 보낸 후 받은 데이터를 통해 빌드시에     
* html페이지를 만들어서 클라이언트로 보내준다.
*/
export const getStaticProps: GetStaticProps = async () =&gt; {
   const homeInitialData = await fetcher(URL.HOME);
  // [&#39;happy&#39;,&#39;cool&#39;,&#39;so-cool&#39;, ...rest]
   return {
     props: {
       homeInitialData,
     },
   };
};</code></pre>
<p><img src="https://images.velog.io/images/denmark-banana/post/6516b991-1db7-4f82-a8fb-f2b447968878/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.13.45.png" alt="">
이렇게 초기 렌더링에서는 Pre 렌더링이 되어 API를 요청하지 않아도 데이터를 입힌 화면이 그려져있다. (데이터를 입힌 화면 대신 네트워크 요청 정보를 볼 수 있는 화면 사진을 올렸다..😅)</p>
<p><img src="https://images.velog.io/images/denmark-banana/post/021e2382-b452-4712-84df-5a5ab3eb752f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.13.56.png" alt="">
다른 브라우저 창을 갔다가 왔을때는 이렇게 API를 추가로 요청하여 데이터를 자동으로 갱신한다. (useSWR의 CSR 기능)</p>
<h3 id="마무리">마무리</h3>
<p>이렇게 useSWR과 Next의 Pre-rendering를 적절히 활용하면 효과적으로 페이지를 그리는 것이 가능하다. (ServerSideProps도 위와 같은 방법으로 이용 가능하다는 점..!)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nextjs - ServerSideProps에서 Promise.All, Promise.AllSettled 사용하기]]></title>
            <link>https://velog.io/@denmark-banana/Nextjs-SSR-PromiseAllSettled</link>
            <guid>https://velog.io/@denmark-banana/Nextjs-SSR-PromiseAllSettled</guid>
            <pubDate>Mon, 22 Feb 2021 09:54:28 GMT</pubDate>
            <description><![CDATA[<p>홈 화면을 렌더링하기 위해 오래전에 봤었던 Nextjs Document를 다시 보게 되었다.
어떻게 데이터를 렌더링할지 여러 고민을 하게 되었는데,</p>
<p>사용자에 따라 화면이 달리 보여야 하니 SSG를 사용할 수는 없고, SEO를 위해 Server-Side로 페이지 렌더링을 하기로 결정했다. 그러기 위해서 Nextjs에서 제공하는 getServersideProps() 함수를 사용했고, 해당 함수 내에서 백엔드 서버로 API 요청을 보낸다. (서버에서만 실행되는 코드..!) </p>
<p>또한 API 요청이 여러개라면 병렬로 비동기 호출을 진행해야 하며, 모든 결과 값을 기다린 후 html 페이지를 생성하고 클라이언트로 페이지를 보내준다. 위의 방식으로 요청을 보내기 위해 Javascript의 Promise.All 함수를 사용하였다. </p>
<h3 id="promiseall-사용">Promise.All 사용</h3>
<pre><code class="language-ts">export const getServerSideProps = async ctx =&gt; {
  /**
   * Promise All 장점 : 병렬로 요청을 진행함
   * Promise All 단점 : 한 요청이 실패하면 다른 요청들도 reject됨
   */
  const datas = {
    bannerDatas: API.BANNER(&#39;HOM&#39;, &#39;MAN&#39;),
    recommendDatas: API.HOME_PRODUCT(&#39;MAN&#39;, &#39;REC&#39;),
    seasonDatas: API.HOME_PRODUCT(&#39;MAN&#39;, &#39;SEA&#39;),
    instagramDatas: API.INSTAGRAM,
  };
  const keys = Object.keys(datas);
  const values = Object.values(datas);

  try {
    const props: any = {};
    const responses = await Promise.all(values.map(url =&gt; defaultFetcher(url)));
    responses.forEach((item, idx) =&gt; {
      const key = keys[idx];
      props[key] = item;
    });

    return {
      props,
    };
  } catch (error) {
    return {
      props: {},
    };
  }
};</code></pre>
<p>여차저차 구현을 하였는데 테스트 도중 이슈가 생겼다. Promise.All을 사용하면 여러개의 병렬 요청 중 하나가 rejected 되면 전체의 요청은 즉시 거부되고 결과를 저장하지 않는다는 이슈였다.</p>
<p>이 이슈를 해결하기 위해 검색하던 중  es2020에서 지원하는 Promise.AllSettled 함수를 알게 되었다. 이 함수는 요청 중 하나가 실패해도 다른 요청 성공값들은 보존할 수 있게 하는 함수였다. 물론 실패한 요청도 (상태, 실패한 이유)를 함께 배열에 저장한다.</p>
<p>하지만 이 함수를 사용하기 위해 프로젝트의 JS 참조 라이브러리를 갑자기 es2017에서 es2020으로 바로 올릴수는 조심스러웠기에, 공식문서를 참고하여 해당 함수의 폴리필을 직접 구현하였다. (es2020을 사용할 수 있으면 바로 해당함수를 사용하면 된다.)</p>
<h3 id="promiseallsetteld-구현">Promise.AllSetteld 구현</h3>
<pre><code class="language-ts">/**
 * PromiseAllSettled polyfill 함수로 구현
 */

export function PromiseAllSettled(promises: any) {
  return Promise.all(
    promises.map(p =&gt;
      Promise.resolve(p).then(
        value =&gt; ({
          status: &#39;fulfilled&#39;,
          value,
        }),
        reason =&gt; ({
          status: &#39;rejected&#39;,
          reason,
        }),
      ),
    ),
  );
}</code></pre>
<h3 id="promiseallsetteld-사용">Promise.AllSetteld 사용</h3>
<pre><code class="language-ts">export const getServerSideProps: GetServerSideProps = async ctx =&gt; {
  /**
   * Promise All : 병렬로 요청을 진행하며 한 요청이 실패하면 다른 요청들도 같이 reject됨
   * Promise AllSettled : 병렬로 요청을 진행하며 한 요청이 실패해도 다른 요청들은 보존함
   */
  const datas = {
    bannerDatas: API.BANNER(&#39;HOM&#39;, &#39;MAN&#39;),
    recommendDatas: API.HOME_PRODUCT(&#39;MAN&#39;, &#39;REC&#39;),
    seasonDatas: API.HOME_PRODUCT(&#39;MAN&#39;, &#39;SEA&#39;),
    instagramDatas: API.INSTAGRAM,
  };
  const keys = Object.keys(datas);
  const values = Object.values(datas);

  try {
    const props = {};
    const responses = await PromiseAllSettled(values.map(url =&gt; defaultFetcher(url)));
    responses.forEach((item, idx) =&gt; {
      // 성공
      if (item.status === &#39;fulfilled&#39;) {
        const key = keys[idx];
        props[key] = item.value;

        //실패
      } else if (item.status === &#39;rejected&#39;) {
        console.log(item.reason);
      } 
    });

    return {
      props: props,
    };
  } catch (error) {
    return {
      props: {},
    };
  }
};</code></pre>
<p>[최종 결과] : 여러개의 병렬 API 요청이 서버로 정상적으로 들어갔고, 그 중 한개의 요청이 실패하여도 정상적으로 responses 배열에 담겨서 props를 정상적으로 내려보냈다.😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nextjs - ServeSideProps 에서 cookie 사용]]></title>
            <link>https://velog.io/@denmark-banana/Nextjs-SSR-cookie</link>
            <guid>https://velog.io/@denmark-banana/Nextjs-SSR-cookie</guid>
            <pubDate>Mon, 22 Feb 2021 09:41:36 GMT</pubDate>
            <description><![CDATA[<p>Nextjs에서 SSR을 위해 사용하는 ServerSideProps 함수는 서버단에서 동작하는 코드이기 때문에 브라우저의 cookie를 사용하여 API를 요청하는 것이 까다롭다. </p>
<p>다행히 ServerSideProps 함수는 context 파라미터를 주입받기 때문에 context 객체가 가지고 있는 req 필드를 통해 cookie 정보를 알 수 있다.</p>
<pre><code class="language-ts">export const getServerSideProps: GetServerSideProps = async ctx =&gt; {

    // get the cookies
    const cookieString = ctx.req ? ctx.req.headers.cookie : &#39;&#39;;

    // set the cookies
    ctx.res.setHeader(&#39;set-Cookie&#39;, &#39;foo=bar; HttpOnly&#39;);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[OurCat Side Project - #Sprint1]]></title>
            <link>https://velog.io/@denmark-banana/OurCat-Side-Project-Sprint1</link>
            <guid>https://velog.io/@denmark-banana/OurCat-Side-Project-Sprint1</guid>
            <pubDate>Sun, 14 Feb 2021 09:00:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/denmark-banana/post/c0ac4f6f-f342-43c7-a34d-3c7c8e5e4a4c/image.png" alt=""></p>
<p>대망의 첫번째 스프린트 시작이다. 같은 팀 프론트엔드 개발자인 장봄님과 주로 협업을 진행하였다. 또한 이전 스프린트에서 정한 협업 플로우를 같이 진행하면서 협업의 재미(?)를 느낄 수 있었다.</p>
<p>스프린트#1은 2월 11일 ~ 2월 21일까지 2주간 진행될 예정이며 그동안 진행한 이슈들에 대해서 이 곳에 정리할 예정이다.</p>
<h2 id="🎫-2월-11일--2월-14일">🎫 2월 11일 ~ 2월 14일</h2>
<h3 id="1-폴더-구조--적용-🏃">1. 폴더 구조  적용 🏃</h3>
<p>컴포넌트들을 재사용성을 최대한으로 끌어올리기 위해 Atomic Design Pattern을 사용하였다. <a href="https://brunch.co.kr/@ultra0034/63">Atomic Design Pattern이란?</a></p>
<p><img src="https://images.velog.io/images/denmark-banana/post/95342411-522d-4b56-9d7f-6e3aa2fcf407/image.png" alt=""></p>
<p>components 하위 디렉토리를 보면 atoms, molecules, organisms가 있는 것을 확인 할 수 있다.</p>
<blockquote>
<p>atoms는 더이상 쪼갤 수 없는 컴포넌트를 뜻한다. (text, image, ...)
molecules는 atom 컴포넌트들의 조합이다. (card, ...)
organisms는 molecules의 조합이다. (cardBox, ...)</p>
</blockquote>
<h3 id="2-atomic-컴포넌트-구현-🤾">2. Atomic 컴포넌트 구현 🤾</h3>
<p>아래와 같이 7개의 Atomic 컴포넌트들을 구현하였다.</p>
<blockquote>
<p>Label, Input, Button, Image, Checkbox, TextAra, Range</p>
</blockquote>
<ol>
<li><p>Label component 예시</p>
<pre><code class="language-ts">/* index.tsx */
import React from &#39;react&#39;;
import * as S from &#39;./style&#39;;
import { IComponent } from &#39;common&#39;;
export interface ILabelProps extends IComponent {
onClick?: React.MouseEventHandler&lt;HTMLElement&gt;;

backgroundColor?: string;
lineThrough?: boolean;
letterSpacing?: string;
pointer?: boolean;
}
</code></pre>
</li>
</ol>
<p>export const Label: React.FC<ILabelProps> = props =&gt; {
  return &lt;S.WrapLabel {...props}&gt;{props.children}&lt;/S.WrapLabel&gt;;
};</p>
<p>/* style.ts */
import { ComponentMixin } from &#39;common&#39;;
import styled from &#39;styled-components&#39;;
import { ILabelProps } from &#39;./&#39;;</p>
<p>export const WrapLabel = styled.div<ILabelProps>`
  ${ComponentMixin}</p>
<p>  background-color: ${props =&gt; props.backgroundColor &amp;&amp; props.backgroundColor};
  letter-spacing: ${props =&gt; props.letterSpacing &amp;&amp; props.letterSpacing};
  text-decoration: ${props =&gt; (props.lineThrough ? &#39;line-through&#39; : &#39;none&#39;)};
  cursor: ${props =&gt; (props.pointer ? &#39;pointer&#39; : &#39;default&#39;)};
`;</p>
<pre><code>
모든 Atomic Component들이 공통적으로 가지고 있는 props들은 common의 IComponent 인터페이스에서 관리하며, 개별적으로 가지고 있어야할 props들만 위에서 추가시켜준다.

style 또한 공통적으로 가지고 있어야할 css 속성들은 common의 Component Mixin 파일에서 가지고 있으며 개별적으로 가지고 있어야할 css만 추가시켜준다.

### 3. 이슈 🤽 

1. Styled-components with SSR

&gt; 새로고침 시에 적용한 style들이 다 없어지는 현상이 발생하였다. 😭
알고보니 babel-plugin-styled-components&#39; 라이브러리를 설치하지 않아서 발생했던 이슈였고, 라이브러리를 설치한 후 .babelrc 파일과 _document.ts 파일에 ssr 설정을 세팅해주었다.

```ts
//.babelrc
{
  &quot;presets&quot;: [&quot;next/babel&quot;],
  &quot;plugins&quot;: [
    [&quot;babel-plugin-styled-components&quot;, { &quot;ssr&quot;: true, &quot;displayName&quot;: true, &quot;preprocess&quot;: false }]
  ]
}
//_document.ts
import Document, { DocumentContext, Head, Html, Main, NextScript } from &#39;next/document&#39;;
import { ServerStyleSheet } from &#39;styled-components&#39;;

interface StyledProps {
  styleTags: Array&lt;React.ReactElement&lt;{}&gt;&gt;;
}

class MyDocument extends Document&lt;StyledProps&gt; {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;
    const initialProps = await Document.getInitialProps(ctx);
    try {
      ctx.renderPage = () =&gt;
        originalRenderPage({
          enhanceApp: App =&gt; props =&gt; sheet.collectStyles(&lt;App {...props} /&gt;),
        });

      return {
        ...initialProps,
        styles: (
          &lt;&gt;
            {initialProps.styles}
            {sheet.getStyleElement()}
          &lt;/&gt;
        ),
      };
    } catch (error) {
      console.error(error);
    } finally {
      sheet.seal();
    }
    console.error(&#39;return Origin initialProps&#39;);
    return initialProps;
  }
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[OurCat Side Project - 시작하며]]></title>
            <link>https://velog.io/@denmark-banana/OurCat-Side-Project-%EC%8B%9C%EC%9E%911</link>
            <guid>https://velog.io/@denmark-banana/OurCat-Side-Project-%EC%8B%9C%EC%9E%911</guid>
            <pubDate>Sun, 14 Feb 2021 07:22:21 GMT</pubDate>
            <description><![CDATA[<p>항상 미뤄뒀던 사이드 프로젝트를 시작하며<br>오랜만에 개발 블로그 포스팅을 하게 되었네요.
이 포스팅은 제가 진행하고 있는 사이드 프로젝트에 대한 정보를 담고 있습니다.😀</p>
<hr>
<h2 id="🙋♀-프로젝트-정보">🙋‍♀ 프로젝트 정보</h2>
<blockquote>
<p><a href="https://ourcat.netlify.app/">OurCat 배포 사이트</a>
<a href="https://github.com/ourCat/ourCat_frontend">OurCat Github</a>
<a href="https://github.com/ourCat/ourCat_frontend/wiki">OurCat Wiki</a>
<a href="https://github.com/ourCat/ourCat_frontend/projects/1">OurCat Project Sprint#1</a></p>
</blockquote>
<hr>
<h2 id="👪-구성원">👪 구성원</h2>
<ul>
<li>FrontEnd 2명 : 나, 봄님</li>
<li>BackEnd 1명 : 김민재님
<img src="https://images.velog.io/images/denmark-banana/post/9b96441f-9fc2-4500-883b-b3f7d63c9a47/image.png" alt=""></li>
</ul>
<hr>
<h2 id="🌈-기획--디자인">🌈 기획 &amp; 디자인</h2>
<blockquote>
<p>기획과 디자인은 12월부터 2개월간 회의를 통해 진행했습니다.
(서비스 기획을 해보는것은 처음이라.. 무척 까다로웠네요.)
(디자인 시안은 디자이너 분한테 도움을 받았습니다. 감사합니다!)</p>
</blockquote>
<h3 id="서비스-기획">서비스 기획</h3>
<p>우리 주변에는 많은 길고양이들이 있습니다.
짧은 순간, 스쳐지나간 이름 없는 고양이들에게도
누군가에게 잊혀지지 않는 &#39;어떤&#39; 고양이가 될 수 있는 공간이 되었으면 좋겠습니다.
우리 동네 고양이들의 소식통!! &#39;ourCat&#39;으로 고양이의 이름과 특징을 공유하고 사진을 업로드할 수 있는 어플입니다.
나만의 고양이가 아닌 우리의 고양이를 공유하고 커뮤니티를 형성 할 수 있습니다.</p>
<h3 id="기능-플로우-figma-사용">기능 플로우 (Figma 사용)</h3>
<p><img src="https://images.velog.io/images/denmark-banana/post/eb9a4c90-3dc0-441b-91f8-e1d05c3a1970/KakaoTalk_20210214_152945735.png" alt=""></p>
<hr>
<h2 id="🚝-stack">🚝 Stack</h2>
<blockquote>
<p>프론트엔드는 React &amp; TypeScript를 사용하고, SSR을 위해 NextJS 9.0으로 기술 스택을 정했습니다. 상태관리는 Redux와 Redux toolkit을 사용합니다. </p>
</blockquote>
<p><img src="https://images.velog.io/images/denmark-banana/post/a985e71f-540d-496f-91db-b54aa2fe2ae8/KakaoTalk_20210214_155217371.jpg" alt=""></p>
<hr>
<h2 id="🏊-배포-관리">🏊 배포 관리</h2>
<blockquote>
<p>배포 툴은 netlify를 사용합니다. netlify의 continous 배포 기능을 이용하면 develop branch에 push되거나 PR 요청을 진행할 때 자동으로 배포가 진행됩니다. 😍</p>
</blockquote>
<p><img src="https://images.velog.io/images/denmark-banana/post/5dacff3c-c746-4e6b-83b5-527ac7d1161e/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/denmark-banana/post/e8b65b2b-adb2-428a-a3c0-528c2456ad17/image.png" alt=""></p>
<hr>
<h2 id="💬-wiki">💬 Wiki</h2>
<blockquote>
<p>Wiki 또한 github 프로젝트의 Wiki 기능를 사용하였다. Wiki는 개발을 진행하며 참고한 레퍼런스들을 기록해두는 것이 목적이고, 다른 팀원들에게 공유가 필요한 내용들을 정리해둘 수도 있다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/denmark-banana/post/0de09918-b547-403c-9a0c-a6f54b09fc2c/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/denmark-banana/post/3b273967-564d-45f9-87f5-41e0643a5cd8/image.png" alt=""></p>
<hr>
<h2 id="🎫-프로젝트-관리">🎫 프로젝트 관리</h2>
<h3 id="1-sprint">1. Sprint</h3>
<ul>
<li>Sprint (1 Sprint = 2주) 단위로 진행합니다.
<img src="https://images.velog.io/images/denmark-banana/post/32e82a18-1e4e-46c1-a97f-494e3e1306b2/image.png" alt=""></li>
<li>매 Sprint가 끝날 시에 회고 및 피드백 사항을 공유합니다.</li>
</ul>
<h3 id="2-branch">2. Branch</h3>
<ul>
<li><a href="https://uxgjs.tistory.com/183">Git flow</a> 를 참고하여 Branch들을 관리합니다.</li>
<li>Main, Develop, Feature Branch</li>
</ul>
<h3 id="3-협업-flow">3. 협업 flow</h3>
<ol>
<li>Github에서 이슈를 생성하고 담당자와 리뷰어를 선택합니다.
<img src="https://images.velog.io/images/denmark-banana/post/32fc4e5b-f814-47e2-ac59-6a246b0b4ca6/image.png" alt=""></li>
<li>Feature Branch를 생성합니다.<pre><code class="language-bash">git checkout -b feat/add-input-component
git push origin feat/add-input-component</code></pre>
</li>
<li>Commit 네이밍을 Karma 문법을 통해 작성합니다.</li>
</ol>
<ul>
<li><a href="http://karma-runner.github.io/6.1/dev/git-commit-msg.html">Karma 네이밍</a>
<img src="https://images.velog.io/images/denmark-banana/post/29a07ae5-c041-438d-8f75-4b1aa6c808a7/image.png" alt=""></li>
</ul>
<ol start="4">
<li><p>Feature 개발이 끝나거나 리뷰가 필요할때 PR을 리뷰어에게 보냅니다.
<img src="https://images.velog.io/images/denmark-banana/post/8a5627af-b762-46ba-afdc-b6eb0973ffb6/image.png" alt=""></p>
</li>
<li><p>리뷰어는 받은 PR을 토대로 코드리뷰와 수정할 부분을 댓글로 남깁니다.
<img src="https://images.velog.io/images/denmark-banana/post/efbdc989-3dc6-4da3-aa13-969097c90b00/image.png" alt=""></p>
</li>
<li><p>이후 수정할 부분이 다 수정되면 리뷰어는 해당 PR을 merge합니다.
1) create a merge commit : git merge 명령이랑 같으며 병합될 때 PR의 commit log들이 지저분하게 들어가는 단점이 있다.
2) rebase and merge : PR의 commit log들이 master에 재정렬되서 병합된다.
3) <strong>squash and merge</strong> : <strong>PR의 commit log들을 한개로 추려서 병합된다. (PR = Commit)</strong></p>
<blockquote>
<p>3번을 선택해서 진행하고 있습니다. 밑의 그림처럼 한개의 merge commit이 하위 commit을 포함해서 기록되는것을 볼 수 있습니다. 😍</p>
</blockquote>
<p><img src="https://images.velog.io/images/denmark-banana/post/32e623de-842f-4577-8994-420a0216b11e/image.png" alt=""></p>
</li>
</ol>
<hr>
<h2 id="🎁-마치며">🎁 마치며</h2>
<blockquote>
<p>다음 포스팅은 설날 4일간 진행한 이슈들에 대해서 다루도록 하겠습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 모듈 , 네임스페이스]]></title>
            <link>https://velog.io/@denmark-banana/TypeScript-%EB%AA%A8%EB%93%88-%EB%84%A4%EC%9E%84%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@denmark-banana/TypeScript-%EB%AA%A8%EB%93%88-%EB%84%A4%EC%9E%84%EC%8A%A4%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Tue, 05 May 2020 15:39:41 GMT</pubDate>
            <description><![CDATA[<h2 id="typescript-모듈">TypeScript 모듈</h2>
<blockquote>
<p>모듈은 독립 가능한 기능의 단위이다. 프로그램은 여러 모듈로 구성돼 있고 모듈을 결합해 하나의 프로그램을 만든다. 모듈을 사용하면 다음과 같은 장점이 있다.</p>
</blockquote>
<ul>
<li>유지보수의 용이성</li>
<li>전역 스코프 오염을 방지</li>
<li>재사용성 향상</li>
</ul>
<h3 id="모듈러-프로그래밍을-위한-접근">모듈러 프로그래밍을 위한 접근</h3>
<blockquote>
<p>모듈러 프로그래밍은 프로그램의 설계 기술로 모듈의 분리와 모듈의 손쉬운 교체에 관심이 있다.</p>
</blockquote>
<ul>
<li>모듈을 식별함</li>
<li>모듈을 분리해 선언함</li>
<li>모듈을 외부로 공개함</li>
</ul>
<ol>
<li><p>모듈러 프로그래밍의 첫 번째 과정은 모듈을 식별하는 것이다. 모듈의 식별은 프로젝트 설계와 분석만으로는 어렵다. 공통 기능이 무엇인지는 실제로 구현하는 과정에서 식별될 가능성이 크다. </p>
</li>
<li><p>두번째 과정은 모듈을 분리하는 것이다. 함수 내부에서 발견되는 공통기능은 모듈을 분리할 수 있다. 모듈로 공통 기능을 분리하면 중복 코드가 줄어들고 각 함수의 역할이 더욱 분명해진다. 또한 모듈 단위로 테스트가 쉬워지므로 에러가 발생할 확률도 줄어든다.</p>
</li>
<li><p>세번째 과정은 모듈을 외부로 공개하는 것이다. 모듈을 외부로 공개함으로써 프로젝트 내에 존재하는 특정 파일에서 호출해 사용할 수 있게 된다. 모듈을 호출하려면 모듈이 노출(export)되도록 선언해야 한다.</p>
</li>
</ol>
<h3 id="내부-모듈과-외부-모듈">내부 모듈과 외부 모듈</h3>
<ol>
<li>내부모듈 : 네임스페이스를 의미</li>
<li>외부모듈 : export라고 선언해 외부로 공개된 모듈을 말한다.</li>
</ol>
<h3 id="내부-모듈">내부 모듈</h3>
<blockquote>
<p>내부 모듈인 네임스페이스는 전역 이름 공간과 분리된 네임스페이스 단위의 이름 공간이다. 따라서 같은 네임스페이스의 이름 공간이라면 파일 B가 파일 A에 선언된 모듈을 참조(reference)할 수 있는데 참조할 때는 별도의 참조문을 선언하지 않아도 된다. </p>
</blockquote>
<blockquote>
<p>기억할 점은 파일이 다르더라도 프로젝트 내에서 같은 네임스페이스 내에서는 이름을 중복해 클래스, 함수, 변수 등을 선언하면 안된다. 반대로 네임스페이스가 다르면 이름이 같아도 이름 충돌이 없다.</p>
</blockquote>
<h3 id="외부-모듈">외부 모듈</h3>
<blockquote>
<p>흔히 말하는 모듈은 외부 모듈을 가리킨다. export 키워드를 이용해 외부 모듈로 선언할 수 있는 대상은 변수, 함수, 클래스 심지어 네임스페이스도 가능하다. 외부 모듈의 이름 공간은 파일 내부로 제한되는 특징이 있다.</p>
</blockquote>
<blockquote>
<p>타입스크립트는 module 옵션을 통해 다른 모듈 형식으로 변환할 수 있도록 지원한다.</p>
</blockquote>
<pre><code class="language-typescript">export class MyCar { ... }
import { MyCar } from &#39;./my-car&#39;;</code></pre>
<blockquote>
<p>모듈 변환을 위한 명령어는 다음 형태와 같다.
[형식]
tsc --module &lt;모듈 형식&gt; &lt;변환할 파일명&gt;</p>
</blockquote>
<pre><code class="language-bash">$ tsc --module commonjs main.ts</code></pre>
<blockquote>
<p>위 명령어를 입력하면 main.ts 파일을 commonjs 모듈 형식으로 컴파일하고 파일(main.js)을 생성한다. module 옵션에서 사용할 수 있는 모듈 형식에는 다음과 같은 것들이 있다.</p>
</blockquote>
<ul>
<li>commonjs</li>
<li>amd</li>
<li>system</li>
<li>umd</li>
<li>es2015 or es6</li>
</ul>
<h2 id="네임스페이스">네임스페이스</h2>
<blockquote>
<p>네임스페이스는 하나의 독립된 이름 공간을 만들고 여러 파일에 걸쳐 하나의 이름 공간을 공유할 수 있다. 네임스페이스는 namespace 키워드를 이용해 다음처럼 선언한다. </p>
</blockquote>
<pre><code class="language-typescript">namespace Hello { ... }</code></pre>
<blockquote>
<p>네임스페이스와 똑같은 역할을 하는 키워드로는 module이 있다. namespace와 module은 키워드는 다르지만, 역할과 기능상 차이가 없다. 네임스페이스는 보통 여러 파일에 걸쳐 하나의 이름 공간을 공유한다.</p>
</blockquote>
<blockquote>
<p>프로젝트 규모가 커지면 파일 단위로 모듈을 분할해야 한다. 이때 네임스페이스를 이용하면 여러 파일에 걸쳐 하나의 네임스페이스의 이름 공간을 공유할 수 있다. 
타입스크립트는 네임스페이스를 이용해 논리적 그룹화를 제공한다. 논리적 그룹화는 네임스페이스의 이름만 같다면 컴파일 시에 하나의 논리적 영역으로 묶어 컴파일 할 수 있게 한다. </p>
</blockquote>
<blockquote>
<p>tsc 명령어는 프로젝트에 속한 모든 *.ts파일을 대상으로 프로젝트 단위 컴파일을 수행하므로 네임스페이스를 명시적으로 참조하지 않아도 된다.</p>
</blockquote>
<h3 id="네임스페이스-모듈">네임스페이스 모듈</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 클래스와 인터페이스]]></title>
            <link>https://velog.io/@denmark-banana/TypeScript-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@denmark-banana/TypeScript-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Sun, 19 Apr 2020 07:06:32 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript-클래스와-인터페이스">TypeScript 클래스와 인터페이스</h1>
<h2 id="1-객체지향-프로그래밍과-클래스-기초">1. 객체지향 프로그래밍과 클래스 기초</h2>
<h3 id="타입스크립트의-객체지향-프로그래밍-지원">타입스크립트의 객체지향 프로그래밍 지원</h3>
<blockquote>
<p><strong>객체지향 프로그래밍(OOP, Object-Oriented Programming)</strong>은 애플리케이션을 개발할 때 <strong>코드 중복을 획기적으로 줄일 수 있는 방법</strong>이다. 객체지향 프로그래밍은 커다란 문제를 <strong>클래스</strong>라는 단위로 나누고 클래스 간의 관계를 추가하면서 코드 중복을 최소화하는 개발 방식이다. 클래스 간의 관계는 <strong>상속이나 포함 관계</strong>를 고려해 추가한다.</p>
</blockquote>
<h3 id="클래스-선언과-객체-생성">클래스 선언과 객체 생성</h3>
<pre><code class="language-ts">class Rectangle {
  x: number,
  y: number,

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
  getArea(): number { return this.x * this.y; }
}</code></pre>
<blockquote>
<p>이렇게 선언한 Rectangle 클래스는 클래스 타입(class type)이 된다. 클래스 타입은 다음의 인터페이스 타입과 정확히 일치한다.</p>
</blockquote>
<pre><code class="language-ts">interface Rectangle {
  x: number;
  y: number;
  getArea(): number;
}</code></pre>
<blockquote>
<p>클래스 내부에는 <strong>생성자인 constructor를 정의</strong>한다. 생성자는 객체를 생성할 때 클래스에 필요한 설정을 <strong>매개변수로 전달받아 멤버 변수를 초기화</strong>한다. 클래스를 선언할 때 생성자를 생략하면 기본 생성자(default constructor)를 호출한다. 만약 클래스에 초기화할 내용이 없다면 다음처럼 클래스 선언 때 생성자를 생략 가능하다.</p>
</blockquote>
<pre><code class="language-ts">class Rectangle { }</code></pre>
<blockquote>
<p>클래스는 멤버 변수와 멤버 메서드 등으로 구성된 <strong>틀</strong>이며 클래스를 실제로 사용하려면 <strong>객체로 생성</strong>해야 한다. 예를 들어 Rectangle 클래스를 객체로 생성하려면 다음처럼 선언해줘야 한다.</p>
</blockquote>
<pre><code class="language-ts">let rectangle = new Rectangle(1, 5);</code></pre>
<blockquote>
<p>위 코드에서 보면 new 키워드를 이용해 Rectangle 객체를 생성해 객체 참조변수(object reference variable)에 할당했다. 생성된 객체는 실제 메모리에 위치하고 객체의 참조가 객체 참조변수에 할당되는 과정을 <strong>인스턴스화</strong>라고 한다. </p>
</blockquote>
<h3 id="상속-관계와-포함-관계">상속 관계와 포함 관계</h3>
<blockquote>
<p>객체지향 프로그래밍에서는 클래스 간의 관계를 크게 두가지로 나눠볼 수 있다.</p>
</blockquote>
<ul>
<li>상속 관계</li>
<li>포함 관계</li>
</ul>
<blockquote>
<p>상속(inheritance)은 코드의 재사용성을 높인다. 예를 들어 자식 클래스가 부모 클래스를 상속하면 자식 클래스는 부모 클래스에 선언된 멤버 변수나 멤버 메서드를 상속받아 사용할 수 있다. 상속 관계를 다른 말로 IS-A 관계라고도 한다. 포함은 한 클래스에 다른 클래스를 멤버 변수로 선언하는 것으로 HAS-A 관계로 표현된다.</p>
</blockquote>
<pre><code class="language-ts">class dinosour extends animal {
  constructor() {
    super();
  }
}</code></pre>
<blockquote>
<p>포함 관계는 클래스가 다른 클래스를 포함하는 HAS-A 관계이다. 클래스 내부에 다른 클래스를 포함하는 관계는 대표적으로 두가지로 나뉜다.</p>
</blockquote>
<ul>
<li>합성 관계</li>
<li>집합 관계</li>
</ul>
<blockquote>
<p>합성 관계는 전체가 부분을 포함하며 <strong>강한 관계</strong>이다.</p>
</blockquote>
<pre><code class="language-ts">class Engine { }
class Car {  
  private engine;
  constructor() {
    this.engine = new Engine();
  }
}
let myCar = new Car();
myCar = null;</code></pre>
<blockquote>
<p>Car 클래스에 선언된 engine 객체는 Car 객체가 new로 생성될 때 함께 생성되고 객체(myCar)가 null이 되면 함께 제거된다. 수명주기를 함께 하므로 <strong>강한 관계</strong>가 된다.</p>
</blockquote>
<pre><code class="language-ts">class Engine { }
class Car {  
  private engine;
  constructor(engine: Engine) {
    this.engine = new Engine();
  }
}
let engine = new Engine();
let myCar = new Car(engine);</code></pre>
<blockquote>
<p>car 객체에 null이 할당돼 제거되더라도 engine 객체는 Car 클래스 외부에 선언돼있으므로 제거되지 않는다. 수명주기를 함께 하지 않으므로 <strong>약한 관계</strong>가 된다.</p>
</blockquote>
<h3 id="접근제한자의-사용법">접근제한자의 사용법</h3>
<ul>
<li>public : public으로 설정된 멤버(멤버 변수, 멤버 메서드 등)는 자식 클래스에서 접근할 수 있음 (상속O, 외부객체를 통한 접근 O)</li>
<li>protected : 자식 클래스에서 접근 가능 (상속O, 외부객체를 통한 접근 X)</li>
<li>private : 현재 클레스에서만 접근할 수 있고, 자식 클래스에서 접근할 수 없음 (상속X, 외부객체를 통한 접근 X)</li>
</ul>
<h3 id="생성자-매개변수에-접근-제한자-추가">생성자 매개변수에 접근 제한자 추가</h3>
<blockquote>
<p>생성자의 매개변수에 접근 제한자를 추가하면 매개변수 속성(parameter properties)이 돼 멤버 변수가 되는 효과가 있다.</p>
</blockquote>
<pre><code class="language-ts">class Cube {
  constructor(public width: number, private length: number, protected height: number) { }

  getVolume() { 
    return this.width * this.length * this.height;
  }
}
let [cWidth, cLength, cHeight] = [1,2,3];
let cube = new Cube(cWidth, cLength, cHeight);
console.log(&quot;1번 세로 : &quot;, cube.width, &quot;cm&quot;);
console.log(&quot;2번 부피 : &quot;, cube.getVolume(), &quot;ml&quot;);    
}</code></pre>
<h3 id="기본접근-제한자">기본접근 제한자</h3>
<blockquote>
<p>기본 접근 제한자(default access modifier)는 접근 제한자 선언을 생략할 때 적용된다. 기본 접근 제한자가 적용될 수 있는 대상은 클래스 멤버 변수, 멤버 메서드, 클래스 Get/Set 프로퍼티, 생성자의 매개변수이다. 다음은 Account 클래스에 선언된 멤버들이 접근 제한자를 생략했을 때 기본 접근 제한자가 무엇인지를 나타낸다.</p>
</blockquote>
<pre><code class="language-ts">class Account {
  public balance: number;
  public getBalance() { ... }
  public setBalance(amount: number) { ... }
  constructor( defaultBalance: number = 1000, protected bankName: string = &quot;happy bank&quot;) { ... }
  // 접근 제한자가 생략되면 기본 접근 제한자가 없어 생성자 내부에서만 사용 가능함
  getBankName() { return this.bankName; }
  getDefaultBalance() { return this.defaultBalance; } //접근 불가
                                                                              }</code></pre>
<h3 id="추상-클래스를-이용한-공통-기능-정의">추상 클래스를 이용한 공통 기능 정의</h3>
<blockquote>
<p>추상 클래스(abstract class)는 구현 메서드와 추상 메서드(abstract method)가 동시에 존재할 수 있다. 구현 메서드는 실제 구현 내용을 포함한 메서드이고 추상 메서드는 선언만 된 메서드이다. 추상 클래스는 단독으로 객체를 생성할 수 없고 추상 클래스를 상속하고 구현 내용을 추가하는 자식 클래스를 통해 객체를 생성해야 한다.</p>
</blockquote>
<blockquote>
<p>추상 클래스는 abstract 키워드를 클래스 선언 앞에 붙여서 선언하고 추상 메서드를 선언할때도 사용할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">abstract class 추상클래스 {
  abstract 추상메서드();
  abstract 추상멤버변수: string;
  public 구현메서드(): void {
    공통적으로 사용할 로직을 추가함
    로직에서 필요 시 추상 메서드를 호출해 구현 클래스의 메서드가 호출되게 함
    this.추상메서드();
  }
}</code></pre>
<blockquote>
<p>추상 클래스에 선언한 추상 메서드는 오버라이딩(overriding)해서 자식 클래스에서 반드시 구현해서 사용해야 한다.</p>
</blockquote>
<h2 id="2-인터페이스에-대한-이해">2. 인터페이스에 대한 이해</h2>
<h3 id="인터페이스-소개">인터페이스 소개</h3>
<blockquote>
<p>인터페이스는 ES6가 지원하지 않는 타입스크립트만의 특징이다. 인터페이스는 타입이며 컴파일 후에 사라진다. 추상 클래스는 선언과 구현이 모두 존재하지만 인터페이스는 선언만 존재하며, 멤버 변수와 멤버 메서드를 선언할 수 있지만 접근 제한자는 설정할 수 없다.</p>
</blockquote>
<pre><code class="language-ts">interface Car {
  speed: number;
}</code></pre>
<blockquote>
<p>알아둘 점은 자식 인터페이스는 여러 부모 인터페이스를 다중 상속할 수 있다. </p>
</blockquote>
<h3 id="인터페이스를-배열-타입으로-지정함">인터페이스를 배열 타입으로 지정함</h3>
<blockquote>
<p>인터페이스는 객체 리터럴을 정의하는 타입으로 사용될 수 있다. 먼저 객체 리터럴의 구조를 인터페이스로 다음과 같이 정의할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">interface Person {
  name: string;
  city: string;
}
let person4: Person[] = [
  { name: &quot;a&quot;, city: &quot;seoul&quot; },
  { name: &quot;b&quot;, city: &quot;daejeon&quot; },
  { name: &quot;c&quot;, city: &quot;daegu&quot; }
];
console.log(JSON.stringify(person4));</code></pre>
<h3 id="인터페이스에-함수-타입을-정의하기">인터페이스에 함수 타입을 정의하기</h3>
<blockquote>
<p>인터페이스는 익명 함수에 대한 함수 타입을 정의할 수 있는 기능으로도 사용된다.</p>
</blockquote>
<pre><code class="language-ts">interface IFormat {
  (data: string, toUpper?: boolean): string;
}

let format: IFormat = function (str: string, isUpper: boolean) {
  ...
}</code></pre>
<h2 id="3-클래스와-인터페이스의-활용">3. 클래스와 인터페이스의 활용</h2>
<h3 id="오버라이딩으로-메서드를-재정의-하기">오버라이딩으로 메서드를 재정의 하기</h3>
<blockquote>
<p>오버라이딩(overriding)은 부모 클래스에 정의된 메서드를 자식 클래스에서 새로 구현하는 것을 일컫는 개념이다. 여기서 오버라이딩할 대상이 있는 부모 클래스를 오버라이든 클래스(overridden class)라 한다. 오버라이든 클래스에는 오버라이든 메서드(overridden method)가 존재한다. 오버라이든 메서드는 파생 클래스에 정의된 메서드에 오버라이딩돼 오버라이딩 메서드로 새롭게 재정의된다.</p>
</blockquote>
<blockquote>
<p>오버라이딩으로 메서드가 재정의되려면 기본적으로 오버라이든 메서드와 오버라이딩 메서드는 서로 이름이 같아야 한다. 그리고 오버라이딩을 위해 다음 두 조건을 만족해야 한다.</p>
</blockquote>
<ul>
<li><p>조건1: 오버라이든 메서드의 매개변수 타입은 오버라이딩 메서드의 매개변수 타입과 같거나 상위 타입이어야 한다.</p>
</li>
<li><p>조건2: 오버라이든 메서드의 매개변수 개수가 오버라이딩 매서드의 매개변수 개수와 같거나 많아야 한다. (단, 조건1이 성립된다는 전제가 있어야 함)</p>
</li>
</ul>
<h3 id="오버로딩을-구현하는-여러-방법">오버로딩을 구현하는 여러 방법</h3>
<blockquote>
<p>메서드 오버로딩(method overloading)은 메서드의 이름이 같지만 매개변수의 타입과 개수를 다르게 정의하는 방법을 일컫는다.</p>
</blockquote>
<ul>
<li>오버라이딩 메서드를 오버로딩</li>
<li>인터페이스를 클래스에서 구현하여 오버로딩</li>
</ul>
<h3 id="클래스와-인터페이스-기반의-다형성-구현하기">클래스와 인터페이스 기반의 다형성 구현하기</h3>
<blockquote>
<p>다형성(polymorphism)은 &#39;여러 모양&#39;을 의미하는 그리스 단어이고 다형성에서 형은 타입(type)을 의미한다. 프로그래밍 언어에서 다형성이란, 여러 타입을 받아들임으로써 여러 형태를 가지는 것을 의미한다.</p>
</blockquote>
<ol>
<li>클래스의 다형성<blockquote>
<p>자식 클래스가 부모 클래스를 상속하고 있을 때 부모 클래스를 타입으로 가지는 객체 참조변수에 자식 클래스의 객체가 할당(구조 타이핑)됨으로써 다형성을 지니게 된다.</p>
</blockquote>
</li>
</ol>
<pre><code class="language-ts">class Planet {
  public diameter: number; //지름
  protected isTransduction: boolean = true; //공전

  getIsTransduction(): boolean {
    return this.isTransduction;
  }

  stopTransduction(): void {
    console.log(&quot;stop1&quot;);
    this.isTransduction = false;
  }
}

class Earth extends Planet {
  public features: string[] = [&quot;soil&quot;, &quot;water&quot;, &quot;oxyzen&quot;];
  stopTransduction(): void {
    console.log(&quot;stop2&quot;);
    this.isTransduction = false;
  }
}

let earth: Planet = new Earth();
earth.diameter = 12656.2;
console.log(&quot;1번 : &quot; + earth.diameter); // 12656.2
console.log(&quot;2번 : &quot; + earth.getIsTransduction()); //true
earth.stopTransduction(); //stop2
console.log(&quot;3번 : &quot; + earth.getIsTransduction()); // false
console.log(earth.features); // 접근불가</code></pre>
<blockquote>
<p>이러한 상속 관계에서 부모 클래스(Planet)의 타입으로 지정된 객체 참조변수(earth)는 자식 클래스의 객체(new Earth())를 할당받더라도 실제 동작은 부모 클래스를 기준으로 실행된다. 따라서 earth는 부모 클래스에 선언된 getIsTransduction())에 접근할 수 있지만 자식 클래스에 선언된 멤버 변수(features)에는 접근할 수 없다.</p>
</blockquote>
<blockquote>
<p>여기서 유의해서 볼 점은 stopTransduction() 메서드는 오버라이든 메서드보다 오버라이딩 메서드가 우선으로 호출된다. 이처럼 런타임 시에 호출될 메서드가 결정되는 특성을 런타임 다형성(runtime polymorphism)이라 한다. </p>
</blockquote>
<ol start="2">
<li><p>인터페이스의 다형성</p>
<blockquote>
<p>인터페이스 또한 부모 클래스의 타입으로 할당되었을때 구현 클래스에 새롭게 추가된 메서드에 접근할 수 없다.</p>
</blockquote>
</li>
<li><p>매개변수의 다형성(유니언 타입 이용)</p>
<blockquote>
<p>매서드의 매개변수 타입을 유니언 타입을 이용함으로써 객체가 다형성의 성질을 띠도록 만들수 있다. 예를 들어 string 타입이나 number 타입을 받아들이도록 다형성 메서드를 구현하려면 매개변수의 타입을 유니언 타입으로 선언해 주면 된다. </p>
</blockquote>
</li>
<li><p>매개변수의 다형성(인터페이스 이용</p>
</li>
</ol>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Netflix Clone Project 구조 정리]]></title>
            <link>https://velog.io/@denmark-banana/Netflix-Clone-Project</link>
            <guid>https://velog.io/@denmark-banana/Netflix-Clone-Project</guid>
            <pubDate>Sun, 12 Apr 2020 12:11:35 GMT</pubDate>
            <description><![CDATA[<h1 id="netflix-clone-project-구조">Netflix Clone Project 구조</h1>
<blockquote>
<p>React를 학습하며 진행했었던 Netflix Clone Project에 대한 전체 구조를 기록해두었다.
중간에 개념들도 섞어넣어 정리하여 잊지 않도록 하자.</p>
</blockquote>
<ul>
<li><p>React16.13, styled-component</p>
</li>
<li><p>[Venus Project] (<a href="https://denmark-banana.github.io/Venus">https://denmark-banana.github.io/Venus</a>)</p>
</li>
</ul>
<h2 id="page-설계">Page 설계</h2>
<ul>
<li>Home : &#39;/&#39;</li>
<li>TV : &#39;/tv&#39;</li>
<li>Search: &#39;/search&#39;</li>
<li>Detail: &#39;/movie/{id}&#39;, &#39;/show/{id}&#39;</li>
</ul>
<h3 id="container-presenter-pattern">Container Presenter Pattern</h3>
<blockquote>
<p>중규모의 React기반의 디자인 패턴이다. 기본적으로 Container는 Data, State를 가지고 api를 불러온다. Container(Class Component)는 Data를 Fetch하는 등 State를 이용한 모든 로직을 처리하며, Presenter(Function Component)는 State를 Props로 받아 해당 데이터들을 보여주는 역할을 한다. </p>
</blockquote>
<blockquote>
<p>Container Component들 같은 경우에는 주석을 통해 state의 type들을 확인할 수 있고, Function Component들 같은 경우에는 propTypes를 통해 props의 type들을 확인할 수 있다.</p>
</blockquote>
<blockquote>
<p>React에서 한 Component가 다른 Component와 통신하기 위해서는 props를 통해 전달해야 한다. React에서는 데이터가 한쪽으로만 전달된다. 단방향 통신 흐름은 데이터의 전달 과정을 이해하고 예측하기 수월해진다.</p>
</blockquote>
<h3 id="styled-component">Styled Component</h3>
<blockquote>
<p>기존에 웹사이트를 개발할 때는 HTML과 CSS, JavaScript는 각자 별도의 파일에 두는 것이 best practice로 여겨졌다. 최근에는 웹 애플리케이션을 여러 개의 재활용이 가능한 컴포넌트 기반 개발 방법이 주류가 되고 있다. 따라서 웹페이지를 여러개의 컴포넌트로 분리하여 각 컴포넌트에 HTML, CSS, JavaScript를 한번에 넣는 형태를 취하고 있는데, 여기에 
CSS-in-JS 라이브러리만 사용하면 손쉽게 JavaScript에 삽입할 수 있다.</p>
</blockquote>
<ul>
<li>class명 중복을 피할 수 있음</li>
<li>props를 받을 수 있음</li>
</ul>
<h3 id="react-router-dom">React-router-dom</h3>
<p><a href="https://medium.com/@krpeppermint100/js-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A1%9C-%ED%95%B4%EB%A6%AC%ED%8F%AC%ED%84%B0-spell-book-%EB%A7%8C%EB%93%A4%EA%B8%B0-react-router-dom-fetch-api-9551fb65bca9">React-router-dom 참고</a></p>
<h2 id="components">Components</h2>
<h3 id="router-component">Router Component</h3>
<ol>
<li>Router에서는 BrowserRouter(vs HashRouter)를 사용하였고 위에서부터 Header, Route 구조로 이루어진다. </li>
</ol>
<blockquote>
<p>React Router 종류</p>
</blockquote>
<ol>
<li>BrowserRouter</li>
</ol>
<ul>
<li>Link to 속성에 이동할 경로 기술한다.</li>
<li>새로고침하면 경로 몾찾아서 에러난다.</li>
</ul>
<ol start="2">
<li>HashRouter</li>
</ol>
<ul>
<li>검색 엔진에 사용될 수 없다.</li>
<li>정적 페이지에 적합하다.</li>
</ul>
<h3 id="header-component">Header Component</h3>
<ol>
<li><p>Header에서는 withRouter(주로 history에 접근하여 컴포넌트에서 라우터를 조작하는 데 사용한다.)를 사용하여 history의 location의 pathname에 접근할 수 있다. pathname을 이용하여 해당 메뉴에 여러 컴포넌트에 Link를 통해 접근할 수 있는 네비게이션 역할을 맡고 있다.</p>
</li>
<li><p>style을 잠깐 들여다보면 position: fixed를 통해 스크롤시에도 해당 위치를 고정시켰고 Header의 child인 List(ul)는 flex를 주었고 각각의 Item(li)들은 pathname을 이용한 boolean값을 props로 받아 선택시에 아래선에 포인트를 주었다. 또한 react-router-dom의 Link 컴포넌트를 바로 사용하는 것이 아니라 style-component를 이용하여 추가로 디자인을 입혔다.</p>
</li>
</ol>
<blockquote>
<p><strong>position</strong></p>
</blockquote>
<ol>
<li>static (기본위치) : position 프로퍼티의 기본 값으로 position 프로퍼티를 지정하지 않았을 떄와 같다. 기본적인 요소의 배치 순서에 따라 위에서 아래로, 왼쪽에서 오른쪽으로 순서에 따라 배치되며 부모 요소 내에 자식 요소로서 존재할 때는 <strong>부모 요소의 위치를 기준으로 배치</strong>된다.</li>
<li>relative (상대위치) : 기본 위치(static으로 지정되었을 때의 위치)를 기준으로 좌표 프로퍼티(top, bottom, left, right)를 사용하여 위치를 이동시킨다.</li>
<li>absolute (절대위치) : 부모 요소 또는 가장 가까이 있는 조상 요소(static 제외)를 기준으로 좌표 프로퍼티(top, bottom, left, right)만큼 이동한다. 만일 부모 또는 조상 요소가 static인 경우, document body를 기준으로 하여 좌표 프로퍼티 대로 위치하게 된다. 이때 다른 요소가 먼저 위치를 점유하고 있어도 뒤로 밀리지 않고 덮어쓰게 된다. absolute 프로퍼티 선언 시, block 요소의 width는 inline 요소와 같이 content에 맞게 변화되므로 적절한 width를 지정하여야 한다.</li>
<li>fixed (고정위치) : 부모 요소와 관계없이 브라우저의 viewport를 기준으로 좌표프로퍼티(top, bottom, left, right)을 사용하여 위치를 이동시킨다. fixed 프로퍼티 선언 시, block 요소의 width는 inline 요소와 같이 content에 맞게 변화되므로 적절한 width를 지정하여야 한다.</li>
</ol>
<h3 id="home-component">Home Component</h3>
<ol>
<li>Router에서 &#39;Routes/Home&#39;의 Home을 import시에 Home 디렉토리의 index.js를 참조하게 되며 index.js는 HomeContainer를 import한 후 export 하는 구조이다.</li>
</ol>
<h3 id="homecontainer-component">HomeContainer Component</h3>
<blockquote>
<p><strong>Componet LifeCycle</strong></p>
</blockquote>
<ol>
<li>Mounting : DOM에 Element를 넣는 단계 </li>
</ol>
<ul>
<li>constructor() : 컴포넌트가 초기화 되었을때 state를 초기화한다. props와 같은 인자를 받고 부모 class의 super method를 호출한다.</li>
<li>render() : DOM을 위해 JSX을 이용하여 실제 HTML을 반환하는 함수</li>
<li>componentDidMount() : 컴포넌트가 렌더된 후 호출되는 함수 (주로 데이터를 fetch할때 사용)</li>
</ul>
<ol start="2">
<li>Updating : 컴포넌트가 업데이트 됬을때</li>
</ol>
<ul>
<li>render() : 컴포넌트가 업데이트 되었을때 다시 호출</li>
<li>componentDidUpdate() : 컴포넌트가 다시 렌더링 되었을때 호출되는 함수</li>
</ul>
<ol start="3">
<li>Unmounting : 컴포넌트가 DOM에서 제거되었을때</li>
</ol>
<ul>
<li>componentWillUnmout() : 컴포넌트가 제거되기 직전에 호출되는 함수</li>
</ul>
<ol>
<li><p>HomeContainer는 Class Component이며 Class LifeCycle 구조를 갖는다. </p>
</li>
<li><p>constructor에서는 해당 state를 초기화해주고 초기 render()에서는 state를 통해 presenter component를 렌더링한다. </p>
</li>
<li><p>componentDidMount()에서 api의 movesApi를 호출하여 각각의 정보를 fetch 해오고 setState를 통해 state를 업데이트 한다. 도중 error 발생시에는 error state를 업데이트 시켜주고 최종적으로 finally에서는 loading변수를 false로 할당한다. state가 업데이트 되었으니 cycle대로 render()를 재호출한다.</p>
</li>
</ol>
<blockquote>
<p>axios의 장점</p>
</blockquote>
<ol>
<li>구형브라우저를 지원한다.(fetch의 경우는 폴리필 필요)</li>
<li>request aborting에 대한 방법을 제공한다.</li>
<li>응답 시간 초과를 설정하는 방법이 있다.
fetch의 장점</li>
<li>라이브러리를 import 하지 않아도 사용할 수 있다.</li>
</ol>
<h3 id="homepresenter-component">HomePresenter Component</h3>
<blockquote>
<p>propTypes는 받은 데이터가 유효한 지 확인하는 데 사용할 수 있는 유효성 검사기의 범위를 내보낸다. 일부 어플리케이션에서 Flow나 TypeSCript와 같이 타입체크를 할 수 있는 자바스크립트 확장을 사용할 수도 있다. 이런 것들을 사용하지 않는다면 React에서 빌트인 타입 체킹이 가능하다.</p>
</blockquote>
<ol>
<li><p>loading이라는 props를 통해 true일시에는 loading component를 렌더링하고(아직 data를 가져오기 전임을 뜻함) false일시에 data를 통해 렌더링한다. </p>
</li>
<li><p>nowPlaying이 존재하고 있고 길이가 0보다 크다면 Section Component를 props(title, children)와 함께 호출한다. 각각의 movie들은 map function을 이용하여 Poster Component들의 props에 property들을 넣어서 호출한다.</p>
</li>
<li><p>error props가 null이 아닌 경우 Message Component를 props(text, color)와 함께 호출한다.</p>
</li>
</ol>
<h3 id="section-component">Section Component</h3>
<blockquote>
<p>CSS flexbox : 인터페이스 내의 아이템 간 공간 배분과 강력한 정렬 기능을 제공하기 위한 1차원 레이아웃 모델로 설계</p>
</blockquote>
<ol>
<li>주축
flex-direction: row는 main axis가 가로축, cross axis가 세로축
column은 main axis가 세로축, cross axis가 가로축</li>
<li>정렬
justify-content: main axis에 대한 정렬, align-content: cross axis에 대한 정렬 </li>
<li>지정 속성
flex-grow: 각 항목은 주축을 따라 분배받은 만큼 사이즈를 늘림
flex-shrink: 각 항목의 사이즈를 수축하는 방법을 정의</li>
</ol>
<blockquote>
<p>CSS Grid는 2차원(행과 열)의 레이아웃 시스템을 제공한다. Flexbox도 훌륭하지만 비교적 단순한 1차원 레이아웃을 위하며, 좀 더 복잡한 레이아웃을 위해 사용한다.</p>
</blockquote>
<ol>
<li><p>한개의 Section은 nowPlaying, upcoming, popular을 구분하는 용도이다.</p>
</li>
<li><p>Grid layOut을 사용하여 Poster들을 정렬한다. (1개의 poster는 125px이며 25px의 gap을 갖는다.)</p>
</li>
<li><p>auto-fill은 행/열의 개수를 그리드 컨테이너 및 행/열 크기에 맞게 자동으로 조정한다.</p>
</li>
</ol>
<h3 id="poster-component">Poster Component</h3>
<ol>
<li><p>한개의 Poster는 id를 통해 Detail로 연결할 수 있는 Link를 상위 컴포넌트로 사용하고 있다.</p>
</li>
<li><p>Container는 Image, Rating, Title, Year 정보를 표시하고 있으며 Image는 ImageUrl에 리소스가 없을 때 미리 준비한 no_poster 리소스를 사용한다. Title은 substring을 통해 길이를 조절한다.</p>
</li>
<li><p>Image와 Rating은 hover시에 transition을 통해 투명도를 조정하였다.</p>
</li>
</ol>
<h3 id="searchcontainer-component">SearchContainer Component</h3>
<ol>
<li>Container는 Presenter가 사용할 이벤트에 대한 함수를 메서드로 정의해두고 props를 통해 함수를 전달한다. </li>
</ol>
<ul>
<li>handleSubmit: form의 기본 event(page를 리로드하는 로직)을 막고 searchTerm state를 통해 searchByTerm을 호출한다.</li>
<li>updateTerm : input value가 바뀔시 발생하는 event를 params로 받아 searchTerm state를 업데이트한다.</li>
</ul>
<h3 id="detailcontainer-component">DetailContainer Component</h3>
<ol>
<li><p>Route에서 호출된 Detail Container는 route에 관련된 props를 갖고 초기화된다. 해당 props에서 pathname을 사용하여 isMovie state를 초기화한다. </p>
</li>
<li><p>props의 match property의 params 정보를 이용하여 Detail Information을 fetch한다. ES6의 디스트럭처링을 사용하여 object안에 있는 data property 에 접근이 가능하다. fetch하다가 에러가 발생했을 시 error state를 갱신하고 finally시에 loading과 result를 갱신한다.</p>
</li>
</ol>
<h3 id="detailcontainer-presenter">DetailContainer Presenter</h3>
<ol>
<li><p>최상위의 Container에 height을 정해주고 BackDrop div와 Content div를 children으로 포함한다. BackDrop div는 filter blur효과, 투명도0.5, z-index: 0를 주어서 배경 이미지 역할을 한다.</p>
</li>
<li><p>Content는 z-index를 주어서 상단에 노출시키고 Cover, Data, Overview로 구성되어 있다.</p>
</li>
<li><p>Data는 Title, ItemContainer 등으로 구성되어 있다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 함수]]></title>
            <link>https://velog.io/@denmark-banana/TypeScript-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@denmark-banana/TypeScript-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sat, 11 Apr 2020 11:27:22 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript-함수">TypeScript 함수</h1>
<h2 id="1-자바스크립트-함수">1. 자바스크립트 함수</h2>
<h3 id="기명-함수와-익명-함수의-선언">기명 함수와 익명 함수의 선언</h3>
<blockquote>
<p>자바스크립트의 함수는 함수의 이름을 명시해 선언하는 <strong>기명 함수(named function)</strong>와 함수의 이름을 명시하지 않고 사용하는 <strong>익명 함수(anonymous function)</strong>로 나뉩니다. </p>
</blockquote>
<pre><code class="language-ts">myFunction(1, 2); // 함수 선언전 호출 가능
function myFunction(a, b) // 함수 선언
{
  ...
}</code></pre>
<blockquote>
<p><strong>기명 함수</strong>는 호출될 때 호이스팅이 발생한다. 따라서 함수를 선언하기 전에도, 함수를 선언한 후에도 호출할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">result(1, 2); //익명 함수를 선언하기 전에 호출 불가
let result = function(a, b) { return a * b };
result(1, 2); //호출 가능</code></pre>
<blockquote>
<p>이와 반대로 <strong>익명 함수</strong>를 할당해 함수를 호출하면 익명 함수를 할당한 뒤에만 함수를 호출할 수 있도록 호출 시점을 제한할 수 있다.</p>
</blockquote>
<h3 id="자바스크립트-함수의-불안전성">자바스크립트 함수의 불안전성</h3>
<blockquote>
<p>자바스크립트는 매개변수의 타입이나 반환 타입은 없지만, 프로그램이 실행될 때 동적으로 타입을 할당해 <strong>추론된 타입</strong>이 지정된다. (빠른 속도 보장) 그러나 타입이 없기 때문에 런타임때 의도하지 않은 타입 변환이 일어날 수 있다. </p>
</blockquote>
<pre><code class="language-ts">function plus(str) {
  return str + 1000;
}
let result = plus(&quot;1000&quot;);
console.log(typeof result, result); //string 10001000</code></pre>
<blockquote>
<p>이러한 이유때문에 타입을 신뢰할 수 없어서 타입을 검사하는 코드와 타입 캐스팅을 수행하는 코드는 필연적이다.</p>
</blockquote>
<pre><code class="language-ts">function plus(num) {
  if(typeof num !== &quot;number&quot;) {
    num = Number(num);
  }
}</code></pre>
<h3 id="타입-안정성을-갖춘-typescript-function">타입 안정성을 갖춘 TypeScript Function</h3>
<pre><code class="language-ts">function max(x: number, y: number):number { ... }</code></pre>
<blockquote>
<p>타입스크립트는 함수의 매개변수나 반환 타입을 추가해 타입 안정성을 강화한다. </p>
</blockquote>
<h2 id="2-매개변수의-활용">2. 매개변수의 활용</h2>
<h3 id="기본-초기화-매개변수">기본 초기화 매개변수</h3>
<blockquote>
<p>ES6에서 추가된 기본 초기화 매개변수는 함수의 특정 매개변수에 인수가 전달되지 않으면 매개변수에 설정된 초깃값으로 값을 초기화하는 기능이다. </p>
</blockquote>
<pre><code class="language-ts">function pow( x: number, y: number = 2): number { ... }</code></pre>
<h3 id="나머지-매개변수-rest-parameter">나머지 매개변수 (Rest Parameter)</h3>
<blockquote>
<p>ES6에서 추가된 특징으로 개수가 정해지지 않은 인수(arguments)를 배열(array)로 받을 수 있는 기능이다. 개수가 정해지지 않은 만큼 순서가 크게 중요하지 않은 여러 요소를 전달하는 데 유용하다.</p>
</blockquote>
<pre><code class="language-ts">function colors(a: string, ...rest: string[]) 
{ 
    return a + &quot; &quot; + rest.join(&quot; &quot;); 
}

//colors();
let color1 = colors(&quot;red&quot;); //red
let color2 = colors(&quot;red&quot;, &quot;orange&quot;); //red orange
let color3 = colors(&quot;red&quot;, &quot;orange&quot;, &quot;yellow&quot;); //red orange yellow</code></pre>
<h3 id="선택-매개변수-optional-parameter">선택 매개변수 (Optional Parameter)</h3>
<blockquote>
<p><strong>선택 매개변수</strong>는 변수명 뒤에 물음표를 붙이는 식으로 선언한다. 선택 매개변수를 이용하면 선택 매개변수로 지정한 매개변수는 생략할 수 있다. </p>
</blockquote>
<pre><code class="language-ts">function sum(a: number, b?: number): number {
  return a + b;
}
console.log(sum(1));  // NAN</code></pre>
<h3 id="함수-오버로드">함수 오버로드</h3>
<blockquote>
<p><strong>함수 오버로드(function overloads)</strong>는 함수명은 같지만, 매개변수와 반환 타입이 다른 함수를 여러 개 선언할 수 있는 특징을 말한다. 컴파일 시간에 가장 적합한 오버로드를 선택해 컴파일하므로 실행 시에는 런타임 비용이 발생하지 않는 특징이 있다.</p>
</blockquote>
<pre><code class="language-ts">function add(a: string, b:string): string;
function add(a: number, b:number): number;
function add(a: any, b: any): any {
  return a + b;
}</code></pre>
<blockquote>
<p>가장 일반적인 (general) 함수 (매개변수를 any 타입으로 선언)의 <strong>시그니처</strong>를 가장 아래에 선언하고 그 위로 구체적인 (speific) 타입을 명시한 함수의 시그니처를 쌓는 방식으로 선언해야 한다.</p>
</blockquote>
<h2 id="3-익명-함수의-이해와-활용">3. 익명 함수의 이해와 활용</h2>
<h3 id="익명-함수와-화살표-함수">익명 함수와 화살표 함수</h3>
<blockquote>
<p><strong>화살표 함수(arrow function)</strong>는 ES6 표준에 포함된 익명 함수를 좀 더 간략하게 표현할수 있는 방법이다.</p>
</blockquote>
<pre><code class="language-ts">() =&gt; { };      //매개변수 목록 -&gt; 함수 블록</code></pre>
<blockquote>
<p>화살표 함수는 익명 함수로서 <strong>매개변수 목록, 화살표, 함수 블록</strong>으로 구성된다.</p>
</blockquote>
<pre><code class="language-ts">let z1 = ((x,y) =&gt; x + y); // return 값이 있음
let z2 = (x,y) =&gt; { return x + y; }; //중괄호가 있을때는 return을 써줘야 함</code></pre>
<blockquote>
<p>화살표 함수는 익명 함수라서 변수에 할당하고 호출을 해야하지만, 변수에 할당하지 않고 <strong>즉시 호출함수(IIF:Immediately Invoked Function)</strong>을 이용할 수 있다. 즉시 호출 함수는 코드를 실행하면 별도의 외부 호출 없이 자체적으로 호출되는 함수</p>
</blockquote>
<pre><code class="language-ts">let iif = (x =&gt; { return x; })(3);</code></pre>
<h3 id="화살표-함수를-filter-find-메서드에-적용">화살표 함수를 filter, find 메서드에 적용</h3>
<blockquote>
<p><strong>filter 메서드</strong>는 배열에서 조건에 맞는 요소를 추출하는 데 사용한다. filter 메서드를 사용한 방법은 for 문을 순회해 조건에 맞는 요소를 추출하는 방법보다 편리하고 유지보수에 좋다. find도 마찬가지 </p>
</blockquote>
<pre><code class="language-ts">let numberList = [1, 2, 3, 4, 5];
numberList = numberList.filter(n =&gt; {
  return n % 2 === 0;
});
console.log(numberList); // [2, 4]

const number = numberList.find(n =&gt; n === 2);
console.log(number); // 2</code></pre>
<h3 id="객체-리터럴의-선언과-객체-리터럴-타입의-선언">객체 리터럴의 선언과 객체 리터럴 타입의 선언</h3>
<blockquote>
<p>객체 리터럴(object literal)은 여러 속성과 값을 한 단위로 묶어서 표현할 수 있는 객체이다. 객체 리터럴의 속성은 키(key)가 되고, 값(value)은 숫자나 문자열 뿐만 아니라 사용자가 정의한 객체도 할당할 수 있다. 값을 선언하면서 객체 프로퍼티를 참조하려면 this 키워드를 이용하면 된다.</p>
</blockquote>
<pre><code class="language-ts">let person = {
  name: &#39;Happy&#39;,
  hello: function (name2: string) {
    return `Hello, ${this.name} + ${name2}`;
  }
};
console.log(person.hello(&quot;world&quot;));  //Hello, HappyWorld</code></pre>
<blockquote>
<p>객체 리터럴의 hello 속성에 선언된 함수는 <strong>함수 내부의 스코프에서 다른 객체 속성에 접근</strong>하려 할 때 <strong>코드 어시스트</strong>가 동작하지 않는다. 만약 정의한 객체 리터럴 내부에서 다른 프로퍼티를 참조할 일이 많다면 객체 리터럴의 타입을 선언해 내부 참조를 함으로써 코드 어시스트가 동작하게 할 수 있다. <strong>객체 리터럴의 타입은 인터페이스를 이용해 정의</strong>한다.</p>
</blockquote>
<pre><code class="language-ts">interface PersonType {
  name: string;
  hello(this: PersonType, name2: string): string;
}
let typedPerson: PersonType = {
  name: &quot;Happy&quot;,
  hello: function (this: PersonType, name2: string): string {
    let message = `Hello, ${this.name + name2}`;
    return message;
  }
}
console.log(typedPerson.hello(&quot;World&quot;));</code></pre>
<blockquote>
<p>this 키워드를 활용했기 때문에 <strong>객체 리터럴의 프로퍼티를 참조하는 내부 참조</strong> 시에 <strong>코드 어시스트</strong>가 작동하고, 외부에서 hello 함수에 접근할 때도 코드 어시스트가 작동한다. </p>
</blockquote>
<h3 id="익명-함수의-함수-타입">익명 함수의 함수 타입</h3>
<blockquote>
<p>익명 함수는 변수에 할당할 수 있다. 익명 함수가 할당된 변수는 타입을 추가할 수 있기 때문에 함수 자체에도 타입이 존재한다는 것을 짐작할 수 있다. 할당한 익명 함수에 매개변수 타입과 반환 타입을 추가할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">let myConcat = function (str1: string, str2: string): string { return str1 + str2; };</code></pre>
<blockquote>
<p>익명 함수의 매개변수나 반환값에 타입을 지정할 수 있지만, 익명 함수가 구현체이므로 타입을 선언하면 형태가 다소 복잡해진다. 이러한 점을 개선하기 위해 익명 함수에 선언된 타입을 별도로 분리해 함수 타입으로 선언하면, 타입 안정성을 보장하면서도 익명 함수의 타입이 무엇인지 쉽게 파악이 가능하다.</p>
</blockquote>
<pre><code class="language-ts">let myConcat: (str1: string, str2: string) =&gt; string = (str1, str2) =&gt; { return str1 + str2; };</code></pre>
<ul>
<li>익명 함수의 매개변수나 반환값에 타입을 별도로 분리할 수 있다.</li>
<li>익명 함수에 타입을 추가하지 않아도 함수 타입만으로 익명 함수의 타입 안전성이 보장된다.</li>
<li>익명 함수의 타입이 무엇인지는 함수 타입을 통해 곧바로 확인할 수 있으므로 가독성이 좋아진다.</li>
</ul>
<blockquote>
<p>익명 함수의 타입을 함수 타입으로 분리하면 새로 정의한 타입은 반복적으로 재활용해 사용할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">type calcType = (a: number, b: number) =&gt; number;</code></pre>
<h3 id="콜백-함수의-타입-선언과-활용">콜백 함수의 타입 선언과 활용</h3>
<blockquote>
<p><strong>콜백 함수(callback function)</strong>는 <strong>또 다른 함수의 매개변수로 전달될 수 있는 함수</strong>이다. 여기서 콜백 함수를 전달받는 함수는 콜백 함수보다 상위 처리를 담당하며 <strong>고차 함수(higher-order function)</strong>라고 불린다. 고차 함수에서 콜백 함수를 인수로 받아서 사용하면 <strong>고차 함수 실행(이벤트)이 끝난 다음의 후속 처리</strong>를 콜백 함수에서 실행할 수 있다.  </p>
</blockquote>
<pre><code class="language-ts">function echoFunction(message: string, callback) {
  return callback(message);
}

let responseMessage = echoFunction(&quot;hello world!&quot;, message =&gt; message);
console.log(responseMessage);     //hello world!</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 제어문 & 연산자]]></title>
            <link>https://velog.io/@denmark-banana/TypeScript-%EC%A0%9C%EC%96%B4%EB%AC%B8-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@denmark-banana/TypeScript-%EC%A0%9C%EC%96%B4%EB%AC%B8-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Tue, 24 Mar 2020 12:10:52 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript-제어문--연산자">TypeScript 제어문 &amp; 연산자</h1>
<h2 id="1-반복문">1. 반복문</h2>
<h3 id="es6의-for-of-문">ES6의 for of 문</h3>
<blockquote>
<p>인덱스를 이용해 값을 가져올 수 있는 <code>for in</code> 문과 달리 <code>for of</code> 문은 곧바로 값을 가져올 수 있다. 이터러블(iterable)은 반복 가능한 객체인 배열, 문자열, DOM 컬렉션, 맵(Map)과 셋(Set) 등을 말한다.</p>
</blockquote>
<pre><code class="language-ts">//for in
let fruits = {&quot;a&quot; : &quot;apple&quot;, &quot;b&quot; : &quot;banana&quot;, &quot;c&quot;: &quot;cherry&quot;};

for (let property in fruits) {
  console.log(property, fruits[property]); // a apple b banana c cherry
}
//for of
for (const value of [1,2,3]) {
  console.log(value); // 1, 2, 3
}</code></pre>
<blockquote>
<p>일반 for 문에서는 <code>let</code> 선언자가 아닌 <code>const</code>를 사용할 수 없다. <code>for of</code> 문은 Symbol.iterator의 구현을 통해 각 이터레이션 값의 요소를 가져오기 때문에 const를 사용할 수 있다는 사실!</p>
</blockquote>
<h3 id="맵과-셋을-for-of-문에-적용">맵과 셋을 for of 문에 적용</h3>
<blockquote>
<p>ES6에 추가된 이터러블 객체로 <code>맵(Map)</code>과 <code>셋(Set)</code>이 있다. 맵 객체는 키 중복을 허용하지 않는 자료구조이다.</p>
</blockquote>
<pre><code class="language-ts">//Map은 key의 중복을 허용하지 않는다.
let itMap = new Map([[&quot;one&quot;, 1], [&quot;one&quot;, 2]]);
itMap.set(&quot;one&quot;, 3);

for (let entry of itMap) 
  console.log(entry); // [&#39;one&#39;, 3]

//Set은 어떤 타입의 값이든 유일한 값을 저장할 수 있다.
let isSet = new Set([&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;a&quot;, &quot;b&quot;, &quot;c&quot;]);

for (let vlaue of itSet) 
  console.log(value); //a b c d</code></pre>
<h3 id="symboliterator-메서드를-이용한-이터러블-객체-사용"><code>[Symbol.iterator]()</code> 메서드를 이용한 이터러블 객체 사용</h3>
<blockquote>
<p><code>배열, 맵, 셋</code>과 같은 이터러블 객체를 <code>순회</code>하는 데 사용한다.</p>
</blockquote>
<pre><code class="language-ts">let arr = [1, 2];
let itObj = arr[Symbol.iterator]();

console.log(&quot;1:&quot;, typeof itobj); //object
console.log(&quot;2:&quot;, itObj.next()); //value:1, done: false
console.log(&quot;3:&quot;, itObj.next()); //value:2, done: false
console.log(&quot;4:&quot;, itObj.next()); //value: undefined, done: true</code></pre>
<h2 id="2-연산자">2. 연산자</h2>
<h3 id="기본-연산자">기본 연산자</h3>
<ul>
<li>비교 연산자 ===, &gt;=, &lt;, ...<blockquote>
<p>타입 스크립트에서 <code>&quot;==&quot;</code> 연산자 대신 <code>&quot;===&quot;</code>을, <code>&quot;!=&quot;</code> 연산자 대신 <code>&quot;!==&quot;</code>을 사용하기를 권장하는 이유는 자바스크립트로 컴파일하고 나서도 타입 안정성을 보장할 수 있기 때문이다.</p>
</blockquote>
</li>
<li>논리 연산자 &amp;&amp;,||,!<blockquote>
<p>truthy, falsy에 대해... 우리는 코딩을 하면서 자주 이런 에러를 만나게 된다. <code>Cannot read property &#39;name&#39; of undefined.</code> 항상 <strong>객체의 property에 접근할때는 해당 객체가 undefined인지 check logic</strong>을 넣어야한다. 아래의 예제를 보면 name property를 사용하기 위해 animal을 체크 한다. 마지막으로 name도 비어 있는 값인지 체크한다.</p>
</blockquote>
<pre><code class="language-ts">function getName(animal: { name: string }):string  {
let name:string = &#39;&#39;;
if (animal) {
  name = animal.name;
}
if (!name)
  return &#39;이름이 없는 동물&#39;;
else
  return name;
}
</code></pre>
</li>
</ul>
<p>//위의 예제처럼 쓸 수 있지만 논리 연산자를 사용하면 이렇게 줄일 수 있다.
function getName(animal: { name: string }):string  {
  return (animal &amp;&amp; animal.name) || &#39;이름이 없는 동물&#39;;<br>}</p>
<pre><code>https://dev-momo.tistory.com/entry/Javascript-Optional-Chaining

- 조건 연산자 ?:

&gt; 타입스크립트는 ES7의 지수 연산자인 `**`를 지원하므로 Math.pow를 대체해서 사용할 수 있다.

```ts
console.log(10 ** 3); // 1000
console.log(1 + &quot;happy&quot;); // 1happy</code></pre><h3 id="디스트럭처링">디스트럭처링</h3>
<blockquote>
<p>타입스크립트는 ES6의 디스트럭처링(destructuring)을 지원한다. 디스트럭처링이라는 말의 뜻은 객체의 구조(structure)를 제거(de)한다는 의미가 있다. 디스트럭처링은 객체의 구조를 분해 후 할당이나 확장과 같은 연산을 수행한다.</p>
</blockquote>
<ul>
<li>객체 디스트럭처링<blockquote>
<p>객체 디스트럭처링은 객체 리터럴에서 변수명에 대응하는 속성 값을 추출해 변수로 할당하는데 유용하다.</p>
</blockquote>
</li>
</ul>
<pre><code class="language-ts">let { id, country = 88 } = { id: &quot;happy&quot; }; //default value 설정
console.log(country); //88
let { id: newName1, country: newName2 } = { id: &quot;happy&quot;, country: 88 };
console.log(newName1); //happy

const deepObject = {
  state: {
    information: {
      name: &#39;tom&#39;,
      language: [&#39;korean&#39;, &#39;english&#39;, &#39;japanese&#39;]
    }
  },
  value: 5
}

const {
  state: {
    information: {
      name, language
    }
  }
} = deepObject
console.log(name) // tom</code></pre>
<ul>
<li>디스트럭처링 매개변수 선언</li>
</ul>
<pre><code class="language-ts">/*
** 객체의 속성에 각각의 property가 있는지 체크 후에 값을 할당하고 있다. 
*/
function printProfile(obj) {
  let name = &quot;&quot;;
  let nation = &quot;&quot;;
  name = obj.name ? &quot;none&quot; : obj.name;
  nation = obj.nation? &quot;?&quot; : obj.nation;
  console.log(name); //happy
}

/*
** property를 매개변수에서 체크하면 좀 더 효율적인 코드가 될 수 있다.
*/
function printProfile({ name = &quot;none&quot;, nation = &quot;?&quot; }) {
  console.log(name); //happy
}

function printProfile2({ name, nation = &quot;?&quot; } = { name: &quot;none&quot; }) {
  console.log(name, nation); //happy
}
printProfile2(); //none ?</code></pre>
<pre><code class="language-ts">//type 키워드를 이용해 매개변수의 타입을 선언하는 예제
type C= { a: string, b?: number };
function fruit({ a, b }: C): void {
  console.log(a, b);
}

fruit({ a: &quot;apple&quot; }); //apple, undefined
//매개변수 b는 number 타입이고 선택 연산자인 ?로 선언했으므로 생략 가능
</code></pre>
<ul>
<li>배열 디스트럭처링<pre><code class="language-ts">let numbers = [&quot;one&quot;, &quot;two&quot;, &quot;three&quot;, &quot;four&quot;, &quot;five&quot;];
let [,,num3, num4] = numbers;
console.log(num3, num4); //three, four</code></pre>
</li>
</ul>
<h3 id="전개-연산자">전개 연산자</h3>
<blockquote>
<p>타입스크립트는 ES6의 전개 연산자(spread operator)를 지원한다. 전개 연산자는 &#39;...&#39;로 나타내는데 다음 세 가지 경우에 사용된다.</p>
</blockquote>
<ul>
<li>나머지 매개변수를 선언할 때</li>
<li>배열 요소를 확장할 때</li>
<li>객체 요소를 확장할 때</li>
</ul>
<pre><code class="language-ts">//배열 concat 예제
let arr: number[] = [1,2];
let arr2: number[] = [...arr, 3, 4];
console.log(arr2); //[1,2,3,4]

//rest를 사용한 전개 연산자 (배열)
let [first, ...rest]: number[] = [10, 20, 30];
console.log(first) //10
console.log(rest) //[20, 30]

//rest를 사용한 전개 연산자 (객체)
let numGroup = { n1: 1, n2: 2, n3: 3 };
let { n2, ...rest } = numGroup;
console.log(n2, n13);  //2 { n1: 1, n3: 3 } </code></pre>
<h3 id="함수-인자와-spread">함수 인자와 spread</h3>
<blockquote>
<p>배열의 원소들의 합을 출력하는 함수를 만든다고 해보자. 배열을 인자로 받은 후에 for문 돌려서 return을 하는 것이 그려지는가? 이런 방법도 있다는 것을 알아보자.</p>
</blockquote>
<pre><code class="language-ts">function sum(...rest:number[]):number {
  return rest.reduce((acc, current) =&gt; acc + current, 0);
}

const numbers = [1,2,3,4,5,6];
const result = sum(...numbers);
console.log(result); //21</code></pre>
<blockquote>
<p>내친김에 최대값도 해보자. rest와 reduce를 이용하면 이렇게 깔끔해질 수 있다.</p>
</blockquote>
<pre><code class="language-ts">function max(...rest:number[]):number {
  const sum = rest.reduce((acc, current) =&gt; (acc &lt; current ? current : acc), 0);
  return sum;
}
const result = max(1, 2, 3, 4, 5, 6);
console.log(result);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript 변수 선언과 기본 타입]]></title>
            <link>https://velog.io/@denmark-banana/TypeScript-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8%EA%B3%BC-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@denmark-banana/TypeScript-%EB%B3%80%EC%88%98-%EC%84%A0%EC%96%B8%EA%B3%BC-%EA%B8%B0%EB%B3%B8-%ED%83%80%EC%9E%85</guid>
            <pubDate>Sun, 15 Mar 2020 13:19:40 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript-변수-선언과-기본-타입">TypeScript 변수 선언과 기본 타입</h1>
<h2 id="1-변수-선언">1. 변수 선언</h2>
<h3 id="var">var</h3>
<blockquote>
<p>var 선언자는 기본적으로 <code>Hoisting</code> 의 원리를 따르고 있다. 변수가 선언된 위치와 관계없이 <code>scope</code>의 최상위로 끌어올림 되어 같은 스코프라면 어디서든 호출이 된다. 그러나 할당을 먼저하고 나중에 선언하는 코드는 가독성을 떨어뜨리므로 지양한다. 또한 <code>function 레벨 스코프</code>를 지원하므로 함수내에서 선언한 변수는 함수 내에서만 유효하다. 문제는 <code>block 레벨 스코프</code>를 지원하지 않는다.</p>
</blockquote>
<pre><code class="language-ts">//Function Level Scope
var mayName = &quot;cool&quot;;

if(true) {
  var myName = &quot;happy&quot;
}
console.log(myName); // &quot;happy&quot;</code></pre>
<blockquote>
<p><code>block 레벨 스코프</code>를 지원하는 대표적인 선언은 다음과 같다</p>
</blockquote>
<ul>
<li>let, cont</li>
<li>클래스, 인터페이스, 타입 에일리어스, enum 선언</li>
</ul>
<h3 id="let">let</h3>
<blockquote>
<p><code>block 레벨 스코프</code>를 지원하며 <code>Hoisting</code>을 방지한다. ES6의 대표적인 변수 선언에 사용된다.</p>
</blockquote>
<pre><code class="language-ts">//Block Level Scope
var mayName = &quot;cool&quot;;

if(true) {
  let myName = &quot;happy&quot;;
}
console.log(myName); // &quot;cool&quot;</code></pre>
<h3 id="const">const</h3>
<blockquote>
<p>let과 마찬가지로 <code>block 레벨 스코프</code>를 지원하며 <code>Hoisting</code>을 방지한다. ES6의 대표적인 상수 선언에 사용된다. 초기화는 되지만 재할당되지 않는 읽기 전용(readonly) 변수가 된다. 단 const로 선언한 변수라도 객체 리터럴의 속성으로는 변경할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">const profile ={
 name: &quot;nice&quot;,
 month: 9
}
const number = 5;

number = 4; // 할당 불가
profile.name = &quot;cool1&quot;; // 할당 가능
profile.month = 8; // 할당 가능</code></pre>
<blockquote>
<p>이는 타입스크립트가 속성값의 변경을 허용하는 특성이 있기 때문이다.</p>
</blockquote>
<h2 id="2-타입-검사와-타입-선언">2. 타입 검사와 타입 선언</h2>
<h3 id="점진적-타입-검사">점진적 타입 검사</h3>
<blockquote>
<p>언어에 따라 수행하는 타입 검사의 종류</p>
</blockquote>
<ul>
<li><strong>정적 타입 검사 (statically type checking)</strong> : 실행 전에 타입 검사를 수행하며 <strong>Java, C++</strong>가 대표적이다.</li>
<li><strong>동적 타입 검사 (dynamically type checking)</strong> : 실행 중에 타입 검사를 수행하며 <strong>Javascript</strong>가 대표적이다. (loosely typed) 체계</li>
<li><strong>점진적 타입 검사 (gradually type checking)</strong> : 타입 검사를 수행하면서 필요에 따라 타입 선언의 생략을 허용한다. 타입 선언을 생략하면 <strong>암시적(implicit)</strong> 형변환이 일어난다. 타입스크립트에서 점진적 타이핑을 설명할 때 적절한 타입으로 <strong>any</strong>가 있다. <strong>any 타입</strong>은 모든 타입의 최상위 타입이며, <strong>any 타입</strong>으로 선언된 변수는 어떤 타입의 변수도 받아들이면서 심지어 타입이 없는 변수도 받아들인다. <strong>TypeScript, Python</strong>이 대표적이다. (strong typed) 체계</li>
</ul>
<h3 id="자바스크립트의-동적-타이핑">자바스크립트의 동적 타이핑</h3>
<ul>
<li><strong>기본 타입 (primitive types)</strong>: Number, Boolean, String</li>
<li><strong>객체 타입 (object tpyes)</strong>: 객체 리터럴, 배열, 내장 객체<blockquote>
<p>자바스크립트에는 타입이 추론된다. 이처럼 값을 변수에 할당할 때 타입이 정해지는 것을 동적 타이핑(dynamic typing)이라 한다.</p>
</blockquote>
</li>
</ul>
<pre><code class="language-ts">var width = 10;
var myName = &quot;happy&quot;;

console.log(typeof myName); //string
console.log(typeof width); //number</code></pre>
<ul>
<li>자바스크립트에서는 해당 타입인것을 보장하기 위해 타입 검사 코드를 추가해야한다. (런타임에 비교 연산을 수행해야 하므로 성능에 지장을 줄 수 있다.)</li>
<li>자바스크립트에서는 안전을 위해 해당 함수 인자가 어떤 타입인지 명시해주는 주석이 따로 필요하다.</li>
</ul>
<h3 id="기본-타입-primitive-type">기본 타입 (Primitive type)</h3>
<p>기본타입은 보편적으로 많이 사용되는 내장 타입이다.</p>
<blockquote>
<p>string, number, boolean, symbol, enum, 문자열 리터럴</p>
</blockquote>
<p>** Symbol ** type은 Symbol() 함수를 이용해 생성한 고유하고 수정 불가능한 데이터 타입으로 객체 속성의 식별자로 사용된다. </p>
<p><strong>Symbol을 사용하는 이유</strong> : 객체의 key가 문자열이나 정수일 때의 문제는, 프로그래머의 실수등으로 존재하는 객체의 key 값이 변경될 수 있다. Symbol로 정의할 경우 해당 키는 unique 하기에 중복되지 않는다. </p>
<pre><code class="language-ts">let hello = Symbol(&quot;hello&quot;);
let hello2 = Symbol(&quot;hello&quot;);
console.log(hello === hello2); // false

const uniqueKey = Symbol();
let obj = {};

obj[uniqueKey] = 1234;
console.log(obj[uniqueKey]); //1234
console.log(obj); // { [Symbol()]: 1234 }</code></pre>
<p><strong>enum</strong>은 number에서 확장된 타입으로 첫 번째 Enum 요소에는 숫자 0 값이 할당된다. <code>(ts 2.4부터는 문자열도 가능)</code> 그 다음 값은 특별히 초기화되지 않는 이상 1씩 증가한다.</p>
<pre><code class="language-ts">enum WeekDay = { Mon, Tue, Wed, Thu }
let day: WeekDay = WeekDay.Mon;</code></pre>
<blockquote>
<p>enum을 사용하는 이유 : 코드가 단순해지며 가독성이 좋다. 키워드 enum을 사용하기 때문에 구현의 의도가 열거임을 분명하게 나타낸다.</p>
</blockquote>
<p><strong>문자열 리터럴</strong> 타입은 string 타입의 확장 타입으로 사용자 정의 타입에 정의한 문자열만 할당받을 수 있다.</p>
<pre><code class="language-ts">type EventType = &quot;keyup&quot; | &quot;mouseover&quot;;</code></pre>
<h3 id="객체-타입-object-type">객체 타입 (Object type)</h3>
<p>객체 타입은 속성을 포함하고 있으며, 호출 시그니처(call signature), 생성자 시그니처(const signature) 등으로 구성된 타입이다.</p>
<blockquote>
<p>Array, Tuple, Function, 생성자, Class, Interface</p>
</blockquote>
<ol>
<li><strong>array</strong>는 배열 요소에 대응하는 타입이다. <pre><code class="language-ts">let items: number[] = [1,2,3];</code></pre>
</li>
<li><strong>tuple</strong>은 배열 요소가 n개로 정해질 때 각 요소별로 타입을 지정한 타입이다.<pre><code class="language-ts">let tuple: [string, number];
tuple = [&#39;hello&#39;, 10]; // OK
tuple = [10, &#39;hello&#39;]; // Error
tuple = [&#39;hello&#39;, 10, &#39;world&#39;, 100]; // Error</code></pre>
</li>
<li>TypeScript는 <strong>function</strong>에도 Type을 선언할 수 있다. 타입 지정 대상은 함수로 전달되는 매개변수와 최종 리턴 값이 될 수 있다.<pre><code class="language-ts">function split(str: string): string[] {
return str.split(&#39;&#39;);
}
let myFn: (string) =&gt; string[] = split;
myFn = function() { }; // Type &#39;() =&gt; void&#39; is not assignable to type &#39;(string: any) =&gt; string[]&#39;. </code></pre>
</li>
<li><strong>생성자 타입</strong>은 하나의 객체(클래스로부터 생성)가 여러 생성자의 시그니처로 구성될 때 포함할 수 있는 타입으로, 생성자 타입 리터럴을 사용해 정의한다.</li>
</ol>
<blockquote>
<p>메서드 시그니처(method signature)는 메서드의 선언부에 명시되는 매개변수의 리스트를 가리킨다. 만약 두 메서드가 매개변수의 개수와 타입, 그 순서까지 모두 같다면, 이 두 메서드의 시그니처는 같다고 할 수 있다.</p>
</blockquote>
<p><a href="https://www.huskyhoochu.com/literal-and-constructor/">참고자료 : 자바스크립트: 리터럴과 생성자 </a></p>
<p><a href="https://velog.io/@zeros0623/TypeScript-%EA%B3%A0%EA%B8%89-%ED%83%80%EC%9E%85">참고자료 : TypeScript 고급 타입</a></p>
<blockquote>
<p>관련 조사를 찾던 중 알게 된 TypeScript 팁1!!</p>
</blockquote>
<p><strong>TypeScript class constructor Tip!</strong></p>
<pre><code class="language-ts">//이 예제에서는 constructor를 사용하여 기본 클래스에서 공용 속성 position 및 보호 된 속성 speed를 선언한다. 이러한 속성을 매개 변수 속성이라고 한다.
class Car {
    public position: number;        
    protected speed: number;

    constructor(position: number, speed: number) {
        this.position = position;
        this.speed = speed;
    }

    move() {
        this.position += this.speed;
    }        
}

//TypeScript는 관련 속성에 생성자 매개 변수를 자동으로 할당해준다.
class Car {
    constructor(public position: number, protected speed: number) {}

    move() {
        this.position += this.speed;
    }        
}</code></pre>
<h3 id="기타-타입">기타 타입</h3>
<ol>
<li><p>union : 2개 이상의 타입을 하나의 타입으로 정의한 타입</p>
<pre><code class="language-ts">var x: string | number;</code></pre>
</li>
<li><p>intersection : 두 타입을 합쳐 하나로 만들 수 있는 타입</p>
<pre><code class="language-ts">interface Cat { leg: number; }
interface Bird { wing: number; }
let birdCat: Cat &amp; Bird = { leg: 4, wing:2 };</code></pre>
</li>
<li><p>void : 빈 값을 나타내는 타입</p>
</li>
<li><p>null, undefined 타입은 다른 모든 타입의 하위 타입(subtype)이다. tsconfig.json에서 <code>strictNullChecks 옵션</code>을 통해 할당을 방지할 수 있다. </p>
</li>
</ol>
<ul>
<li>undefined : 어떠한 빈 값으로도 초기화 되지 않는 타입</li>
<li>null : 빈 객체로 초기화됨<pre><code class="language-ts">var person = { name: &quot;happy&quot; };
person = null;
console.log(typeof(person)); // object</code></pre>
</li>
</ul>
<ol start="5">
<li>non-nullable : null이나 undefined 허용하지 않는 타입</li>
<li>lookup type - keyof : keyof로 속성을 포함하는 대상을 찾아서 union type처럼 동작<pre><code class="language-ts">interface exLookup { ex1: number; ex2: number; ex3: number; } 
type useLookup = keyof exLookup;
let real:useLookup = &quot;ex2&quot; // 허용</code></pre>
</li>
</ol>
<h2 id="3-자바스크립트의-타입">3. 자바스크립트의 타입</h2>
<h3 id="자바스크립트의-내장-타입">자바스크립트의 내장 타입</h3>
<ul>
<li>boolean </li>
<li>number</li>
<li>string</li>
<li>enum</li>
<li>symbol<pre><code class="language-ts">let type1 = new Boolean(false); 
let type2= new Number(123);
let type3= new String(&quot;hello world&quot;);
type1.valueOf(); type2.valueOf(); type3.valueOf();</code></pre>
</li>
</ul>
<blockquote>
<p>책을 보던 중 알게된 JavaScript 팁2!!
==는 값의 비교, ===는 값과 타입 동시에 비교</p>
</blockquote>
<h3 id="타입스크립트의-내장-타입">타입스크립트의 내장 타입</h3>
<ul>
<li><p>any</p>
<blockquote>
<p>any 타입은 제약이 없는 타입으로 어떤 타입의 값도 받아들일 수 있다. any 의 경우 타입 안정성이 떨어져서 의도치 않는 결과가 나올 수 있고, 그렇다고 한가지 타입으로만 정의하면 지정된 타입 이외에는 다른 타입을 받을 수 없다는 단점이 있다.
noImpicitAny 옵션을 통해 사용을 강제할 수 있따.</p>
</blockquote>
</li>
<li><blockquote>
<p>나중에 등장하게 될 Generic 사용</p>
</blockquote>
</li>
<li><p>object</p>
<blockquote>
<p>object 타입은 any타입 처럼 타입 구분 없이 값을 할당할 수 있는 특성이 있어 any 타입과 비슷하다. 그런데 속성 유무를 검사하는 시점이 다르다. any 타입으로 선언한 변수는 속성의 유무를 런타임 시에 검사하지만, object 타입으로 선언한 변수는 컴파일 시간에 속성의 유무를 검사한다. 따라서 object 타입의 변수에 숫자를 할당하더라도 컴파일 시에 숫자 메서드를 인식하지 못하므로 컴파일 시간에 에러가 발생한다. object 타입은 컴파일 과정에서만 유효한 타입이다.</p>
</blockquote>
</li>
</ul>
<pre><code class="language-ts">let number = 50;
console.log(typeof number, number.toFixed(1)); // number, 50.0

let number2: Object = 50;
console.log(typeof number2, number2.toFixed(1)); //error 발생

let number3: any = 50;
console.log(typeof number3, number3.toFixed(1)); //number, 50.0</code></pre>
<ul>
<li><p>Array Type</p>
<blockquote>
<p>배열 타입은 요소 타입에 <code>[ ]</code>를 붙여 선언한다. </p>
</blockquote>
<pre><code class="language-ts">let myVar: string[] = [&quot;banana&quot;,&quot;apple&quot;];</code></pre>
</li>
<li><p>Generic Array Type</p>
<blockquote>
<p>제너릭 배열 타입은 <code>Array&lt;T&gt;</code> 형태로 선언한다</p>
</blockquote>
<pre><code class="language-ts">let num: Array&lt;number&gt; = [1,2,3];
let num2: typeof num = [4,5,6]; //Type queries</code></pre>
</li>
<li><p>Tuple Type</p>
<blockquote>
<p>튜플 타입은 n개의 요소로 이뤄진 배열에 대응하는 타입, </p>
</blockquote>
</li>
<li><p>void, null, undefined Type</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ReactJS 간단히 정리]]></title>
            <link>https://velog.io/@denmark-banana/ReactJS-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@denmark-banana/ReactJS-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 29 Feb 2020 03:50:39 GMT</pubDate>
            <description><![CDATA[<h1 id="reactjs-간단-정리">ReactJS 간단 정리</h1>
<h2 id="1-fundamental">1. Fundamental</h2>
<ol>
<li>Arrow Function =&gt;  <blockquote>
<p>return을 함축적으로 가지고 있음</p>
</blockquote>
</li>
<li>Template Literals <blockquote>
<p><code>${id}</code></p>
</blockquote>
</li>
<li>Object Destrucuturing  <blockquote>
<p>const { data } = req;</p>
</blockquote>
</li>
<li>Spread Operator  ...<blockquote>
<p>배열로부터 아이템을 가져와서 Unpack함</p>
</blockquote>
</li>
<li>classes</li>
<li>Array.map<blockquote>
<p>각각의 아이템에 대해 시행하고 아이템을 모아서 배열을 return하는것</p>
</blockquote>
</li>
<li>Array.filter<blockquote>
<p>각각의 아이템에 대해서 해당 조건이 맞는 아이템을 모아서 배열을 return하는것</p>
</blockquote>
</li>
<li>Array.forEach<blockquote>
<p>foreach function은 각각의 아이템에 대해서 어떠한 시행만 하는것</p>
</blockquote>
</li>
</ol>
<pre><code class="language-js">//연습 js
const days = [&quot;Mon&quot;, &quot;Tues&quot;, &quot;Wed&quot;];
const otherDays = [&quot;Thu&quot;, &quot;Fri&quot;, &quot;Sat&quot;];

const allDays = [...days, ...otherDays, &quot;Sun&quot;];
console.log(allDays);

const happyDays = allDays.map((day, idx) =&gt; `happy ${idx + 1}:${day}`);
console.log(happyDays);

const numbers = [2, 45, 22, 456, 23];

const biggerThan15 = numbers.filter((num, idx) =&gt; num &gt; 15);
console.log(biggerThan15);

allDays.forEach(day =&gt; console.log(day));</code></pre>
<h2 id="settings">Settings</h2>
<pre><code class="language-bash">npx create-react-app venus</code></pre>
<h2 id="css">CSS</h2>
<ol>
<li>&#39;.css&#39; file : component들과 css file이 분리되는 단점</li>
<li>index, css파일들을 폴더에 넣어서 해당 폴더가 component라고 생각함 (또한 css가 글로벌로 적용되기때문에 이름 중복 안되게 조심해야함)</li>
<li>CSS 모듈 : CSS가 글로벌이 아니라 로컬로 적용되게 가능함  file.module.css 만든 후에 styles.navList 이런식으로 적용하면 style값이 랜덤으로 뒤에 숫자가 붙음</li>
<li>Styled-components : style이 안에 있는 컴포넌트를 생성할 수 있게 함</li>
</ol>
<h2 id="container-presenter-pattern">Container Presenter Pattern</h2>
<blockquote>
<p>중규모의 React Project. 기본적으로 작동하는 방법은, Container는 data, state를 가지고 api를 불러온다. 그리고 모든 로직을 처리할꺼고, 그다음에 프리젠터는 그 데이터들을 보여주는 역할을 한다. 하지만 프리젠터는 state를 갖고 있지 않고, API가 뭔지 모르고, 클래스도 없고, 그냥 함수형 컴포넌트이다. 프리젠터는 스타일이고 컨테이너는 데이터다. </p>
</blockquote>
<h2 id="react-with-typescript">React with TypeScript</h2>
<blockquote>
<p>npx create-react-app project --typescript</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[React.js  스터디 일지 3차]]></title>
            <link>https://velog.io/@denmark-banana/react-Study3</link>
            <guid>https://velog.io/@denmark-banana/react-Study3</guid>
            <pubDate>Fri, 21 Feb 2020 00:24:08 GMT</pubDate>
            <description><![CDATA[<h1 id="reactjs--스터디-일지-3차">React.js  스터디 일지 3차</h1>
<h2 id="3차">3차</h2>
<h3 id="개발">개발</h3>
<h4 id="1-중복-렌더링-이슈">1. 중복 렌더링 이슈</h4>
<p><img src="https://images.velog.io/images/denmark-banana/post/4123dad0-a636-4dae-b115-c38a3ce3bb07/image.png" alt=""></p>
<ul>
<li>Home Component를 렌더링해야할 때 여러 axios에서 data를 가져와야 하는 경우, setState를 여러번 호출하였기 때문에 발생</li>
<li>componentDidMount()에서 await을 사용하여 동기적으로 data를 전부 받은 후 setState를 한번만 진행하는 식으로 해결하였다.</li>
</ul>
<h4 id="2-javascript---object-null-check">2. Javascript - Object Null Check</h4>
<ul>
<li>Null Check는 개발 과정에서 가장 많이 접하면서 간과하기 쉬운 예외 중 하나이다. 항상 null 값에 대비하여 프로그래밍을 해야 한다.</li>
<li>이를 해결하기 위한 방법은 여러가지가 있는데 Java8에서는 Optional class가 있고 Javascript에는 Optional chaning 연산자가 있다.</li>
</ul>
<blockquote>
<p>Optional chaining 연산자 ?.는 체인의 각 참조가 유효한지 명시적으로 검증하지 않고, 연결된 객체 체인내에 깊숙이 위치한 속성 값을 읽을 수 있다. 만약 참조가 nullish(null or undefined)라면, 에러가 발생하는 것 대신에 표현식의 리턴 값은 undefined로 단락된다. </p>
</blockquote>
<ul>
<li>객체의 프로퍼티를 체크하는데 주로 쓰이며 기존의 hasOwnProperty를 대체할 수 있다.</li>
<li>문법이 굉장히 직관적이며 &quot;?.&quot;을 사용하여 프로퍼티가 존재하는지 유무를 체크할 수 있다. 만약 체크하는게 함수 타입일 경우, null/undefined가 아니라면 함수를 실행시킨다.</li>
</ul>
<h3 id="이슈">이슈</h3>
<h3 id="todo">TODO</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[React.js  스터디 일지 1~2차]]></title>
            <link>https://velog.io/@denmark-banana/react-Study</link>
            <guid>https://velog.io/@denmark-banana/react-Study</guid>
            <pubDate>Thu, 20 Feb 2020 03:26:17 GMT</pubDate>
            <description><![CDATA[<h1 id="react-study-스터디-일지-12차">React Study 스터디 일지 1~2차</h1>
<h2 id="1차-create-react-app-없이-react-프로젝트-생성하기">1차 Create-react-app 없이 React 프로젝트 생성하기</h2>
<h3 id="react--babel--webpack--live-dev-server-설정">React &amp; Babel &amp; Webpack &amp; live Dev Server 설정</h3>
<blockquote>
<p>참고 사이트 : <a href="https://velog.io/@yesdoing/%EB%82%B4%EB%A7%98%EB%8C%80%EB%A1%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8-A-to-Z-1-9pjwz1o6ai">https://velog.io/@yesdoing/내맘대로-리액트-A-to-Z-1-9pjwz1o6ai</a></p>
</blockquote>
<h2 id="2차-open-api를-사용하여-component-만들기">2차 Open API를 사용하여 Component 만들기</h2>
<h3 id="개발-create-react-app-없이-개발하기란-참">개발 (Create-React-App 없이 개발하기란 참...)</h3>
<blockquote>
<p>Class Component를 생성하려 하니 &quot;react unexpected token =&quot; Error 발생</p>
</blockquote>
<h4 id="1-1차-스터디에서-완료되지-못한-babel-설정">1. 1차 스터디에서 완료되지 못한 Babel 설정</h4>
<pre><code class="language-bash">npm install -D @babel/plugin-proposal-class-properties
npm install -D @babel/plugin-transform-runtime
npm install -D @babel/runtime
npm install -D babel-eslint</code></pre>
<pre><code class="language-js">//.babelrc
{
    &quot;presets&quot;: [
        &quot;@babel/preset-env&quot;, 
        &quot;@babel/preset-react&quot;
    ],
    &quot;plugins&quot;: [
        &quot;@babel/plugin-proposal-class-properties&quot;,
        &quot;@babel/transform-runtime&quot;
    ]
}
//.eslintrc.js
    &quot;parser&quot;: &quot;babel-eslint&quot;,</code></pre>
<h4 id="2-서버와의-proxy-설정">2. 서버와의 Proxy 설정</h4>
<ul>
<li>Create-React-App에서는 package.json에서 proxy 설정(server의 host 주소 설정)만 해주면 가능하다.</li>
<li>CRA가 아니라면 webpack.config.js의 devServer에서 proxy 설정 가능하다.</li>
</ul>
<pre><code class="language-js">  devServer: {
    contentBase: &#39;./build&#39;,
    noInfo: true,
    open: true,
    port: PORT,
    proxy: { &quot;/api&quot;: &quot;http://localhost:3000&quot; }
  },</code></pre>
<ul>
<li>Home Component에서 server와 통신한다.</li>
</ul>
<h4 id="3-api-key를-react-server에서-어떻게-숨길-수-있을까">3. API Key를 React Server에서 어떻게 숨길 수 있을까?</h4>
<ul>
<li>답변 : Do not store any secrets (such as private API keys) in your React app! </li>
<li>간단한 express server를 구축하여 open-api server에서 호출하기로 한다.</li>
<li>API Key, Secret Key를 서버의 .env파일에 저장한다.</li>
<li>주된 목적은 React 스터디이므로 Server 설정은 따로 적지 않기로 한다.</li>
</ul>
<h4 id="4-api-로-받아온-row-data-가공-후-component-생성">4. API 로 받아온 Row Data 가공 후 Component 생성</h4>
<ul>
<li>Fetch와 Axios 둘 중 어떤 것을 쓸지 고민하다가 차이점을 알게 되었다.</li>
</ul>
<blockquote>
<p>Fetch API보다 Axios가 더 좋은 장점</p>
</blockquote>
<ol>
<li>구형 브라우저 지원 가능 (Fetch API의 경우는 Polyfill이 필요)</li>
<li>요청을 중단 시킬 수 있음</li>
<li>응답 시간 초과 설정 방법 있음</li>
<li>CSRF 보호 기능 내장</li>
<li>JSON 데이터 자동변환</li>
<li>Node.js에서 사용 가능</li>
<li>status code 다루기 쉬움</li>
</ol>
<ul>
<li>Axios로 가져온 데이터(JSON Object)를 JSX에서 Component Interation를 사용하기 위해 Map 형태로 변환 시켜주는 작업 필요하다.</li>
</ul>
<pre><code class="language-js">const object1 = {
  a: &#39;somestring&#39;,
  b: 42
};

for (let [key, value] of Object.entries(object1)) {
  console.log(`${key}: ${value}`);
}</code></pre>
<blockquote>
<p>Object.entries() : for..in와 같은 순서로 주어진 객체 자체의 enumerable 속성 [key,value] 쌍의 배열을 반환한다.</p>
</blockquote>
<pre><code class="language-react">//TickerList.js
&lt;TableBody&gt;
  {tickers.map(([key, ticker]) =&gt; (
    &lt;Ticker
      key={key}
      id={key}
      min_price={ticker.min_price}
      max_price={ticker.max_price}
      fluctate_rate_24H={ticker.fluctate_rate_24H}
      acc_trade_value_24H={ticker.acc_trade_value_24H}
    /&gt;
  ))}
&lt;/TableBody&gt;</code></pre>
<blockquote>
<p>App -&gt; Home(axios) -&gt; TickerList(Table) -&gt; Ticker Component(TableRow)</p>
</blockquote>
<pre><code class="language-js">//Ticker.js
Ticker.defaultProps = {
  min_price: &#39;0&#39;,
  max_price: &#39;0&#39;,
  fluctate_rate_24H: &#39;0&#39;,
  acc_trade_value_24H: &#39;0&#39;,
};

Ticker.propTypes = {
  id: PropTypes.string.isRequired,
  min_price: PropTypes.string.isRequired,
  max_price: PropTypes.string.isRequired,
  fluctate_rate_24H: PropTypes.string.isRequired,
  acc_trade_value_24H: PropTypes.string.isRequired,
};</code></pre>
<ul>
<li>prop-types를 통해 validation 체크한다.</li>
<li>defaultProps를 통한 component 초기값 설정한다.</li>
</ul>
<h4 id="5-private-api를-호출하기까지">5. Private API를 호출하기까지...</h4>
<ul>
<li>Bithumb Public API는 쉽게 호출이 가능하다. (GET URL)</li>
<li>회원정보를 얻을 수 있는 Private API를 호출하려 했고 Parameter로 Api Key와 Secret Key 등등이 필요했다. 하지만</li>
</ul>
<p><img src="https://images.velog.io/images/denmark-banana/post/019d91d3-db6c-46cc-8cac-7f8d92894207/image.png" alt=""></p>
<ul>
<li>PostMan으로 테스트 시에 값을 가져올 수가 없는 이슈가 발생하였다. (Return 값은 5300 &#39;올바르지 않은 API Key, Secret Key로 호출&#39;)</li>
<li>방법을 찾던 중 데모 프로그램을 다운로드 받아서 소스를 까보았더니 CryptoJS로 암호화 및 헤더 설정이 내부적으로 진행되고 있었다. 해당 소스대로 API를 호출하려다가 NPM에서 bithumb 모듈을 혹시나 찾아보았더니 다행히 있었고 모듈을 적용하여 호출하였다.</li>
</ul>
<p><img src="https://images.velog.io/images/denmark-banana/post/145e390b-857e-45bc-a2fc-846a0961b3dd/image.png" alt=""></p>
<h4 id="6-기초적인-에러처리-구현">6. 기초적인 에러처리 구현</h4>
<ul>
<li>에러는 기본적으로 2가지 종류가 있을 수 있다.<ol>
<li>노드 서버에서 에러 발생 후 클라이언트에서 확인</li>
<li>클라이언트인 리액트 앱에서 에러 발생</li>
</ol>
</li>
</ul>
<ul>
<li>이 중 1번에 대한 구현 내용이다.</li>
<li>서버에서 API 호출 시 catch 문에서 Error 객체를 생성한다.<pre><code class="language-js">//[Node Server]
//apiController.js
</code></pre>
</li>
</ul>
<p>export const getTickers = async (req, res, next) =&gt; {
  try {
    const {
      data: { data },
    } = await axios.get(&#39;<a href="https://api.bithumb.com/public/ticker/ALL_KRW&#39;">https://api.bithumb.com/public/ticker/ALL_KRW&#39;</a>);
    //throw &quot;getTickers Error&quot;;
    res.json({ data });
  } catch (e) {
    next(new Error(e));
  }
};</p>
<p>export const getBalance = async (req, res, next) =&gt; {
  try {
    Bithumb.setApiKey(process.env.API_KEY, process.env.SECRET_KEY);
    const data = await Bithumb.getMyBalance(&#39;BTC&#39;);
    //throw &quot;getBalance Error&quot;;
    res.json( data[2] );
  } catch (e) {
    next(new Error(e));
  }
};</p>
<p>//app.js
app.use((err, req, res, next) =&gt; {
  console.error(err);
  res.status(err.status || 500);
  res.json({
    errors: {
      message: err.message,
    },
  });
  next();
});</p>
<pre><code>&gt; express에서는 모든 route에 대한 Error Handling을 ``오류 처리 미들웨어``로 처리한다. 

```js
//[React Client]
//Home.js

errorHandler = e =&gt; {
  if (e.response) {
    //요청이 이루어졌으며 서버가 2xx의 범위를 벗어나는 상태 코드로 응답
    console.log(e.response);
  } else if (e.request) {
    //요청이 이루어졌으나 응답을 받지 못함
    console.log(e.request);
  } else {
    //오류를 발생시킨 요청을 설정하는 중에 문제가 발생
    console.log(&#39;Error&#39;, e.message);
  }
  console.log(e.config);
}
getTickers = async () =&gt; {
  try {
    const {
      data: { data },
    } = await axios.get(&#39;/api/ticker&#39;);
    this.setState({ tickers: Object.entries(data) });
    console.log(this.state.tickers);
  } catch (e) {
    this.errorHandler(e);
  }
};
</code></pre><blockquote>
<p>Server에서 throw로 에러 객체를 생성해서 보내면 Client에서는 해당 에러를 catch로 받은 후 해당 에러 내용(e.response)을 출력한다. 해당 axios 에러처리는 <a href="https://yamoo9.github.io/axios/guide/error-handling.html">Axios 러닝 가이드</a>를 참고하였다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/denmark-banana/post/4ecd2f25-1ff3-4d4d-9e01-d28a511129de/image.png" alt=""></p>
<blockquote>
<p>React에는 React16부터 ErrorBoundary라는 개념이 생겼다고 한다. &#39;&#39;ErrorBoundary&#39;&#39;란 Component Tree의 자식 컴포넌트 트리에서 발생한 에러를 잡아내고 로그를 남기며, 나머지 컴포넌트에게 영향을 주지 않게 한다는 개념이다. 이 부분을 더 조사해보고 추후 적용해보기로 한다.</p>
</blockquote>
<h4 id="7-ui-구성">7. UI 구성</h4>
<ul>
<li>UI를 적용하는데 있어서 몇가지 후보를 고려해보았다.</li>
<li>React-Bootstrap</li>
<li>React-Core UI</li>
<li>React-Material UI</li>
<li>기타 등등..</li>
</ul>
<p><img src="https://images.velog.io/images/denmark-banana/post/b625bb5e-dafb-450b-a802-91ea4138086d/image.png" alt=""></p>
<ul>
<li>몇가지를 고려하여 Material UI를 선택하였다.</li>
</ul>
<ol>
<li>쓸만한 Component들이 많으며 구글 검색 자료 등이 많다.</li>
<li>React의 장점을 그대로 사용할 수 있다.</li>
<li>사용자 커스터마이징이 쉽다.</li>
</ol>
<ul>
<li>Material-UI 컴포넌트에서는 스타일을 적용할때 스타일 패키지를 이용한다. 스타일 패키지를 적용시키는 3가지 방법이 있다.</li>
</ul>
<ol>
<li>Hook API를 사용하는 방법</li>
<li>Styles Components API를 사용하는 방법</li>
<li>HOC(Higher-order Component) API를 사용하는 방법</li>
</ol>
<ul>
<li>이 중에서 HOC를 선택하였다.</li>
</ul>
<blockquote>
<p>HOC란? 여러 컴포넌트의 기능 상에서 자주 반복되는 코드들을 컴포넌트로 만들어서 반복 문제를 해결하는 개념. (Don&#39;t repeat yourself) 또한 React에서 Mixin을 대체하는 데 쓰인다.</p>
</blockquote>
<pre><code class="language-js">//App.js
import {createMuiTheme, ThemeProvider } from &#39;@material-ui/core/styles&#39;;
const theme = createMuiTheme({
  palette: {
    primary: purple,
    secondary: green,
  },
  background: &#39;#eeeeee&#39;,
  boxShadow: &#39;0 2px 3px 1px gray&#39;,
});

function App() {
  return (
    &lt;ThemeProvider theme={theme}&gt;
      &lt;Home /&gt;
    &lt;/ThemeProvider&gt;
  );
}

//TopChart.js
const styles = theme =&gt; ({
  root: {
    padding: theme.spacing(3),
    //background: theme.background,
    display: &#39;flex&#39;,
    alignItems: &#39;center&#39;,
    justifyContent: &#39;center&#39;,
  },
  paper: {
    minWidth: 200,
    padding: theme.spacing(3),        //8px * 3
    marginLeft: theme.spacing(1),    //8px
    marginRight: theme.spacing(1),
    textAlign: &#39;center&#39;,

    &#39;&amp;:hover&#39;: {
      cursor: &#39;pointer&#39;,
      boxShadow: theme.boxShadow,
    },
  },
});

...
&lt;div className={classes.root}&gt;
  {tickers.map(([key, ticker]) =&gt; (
    &lt;Paper className={classes.paper} key={key}&gt;
...

export default withStyles(styles)(TopChart);</code></pre>
<ul>
<li><p>이 컴포넌트에서는 withStyles Component는 styles라는 인자와 Home이라는 인자를 받아 새로운 컴포넌트를 반환한다. 컴포넌트의 props의 styles에서 정의한 스타일 정보를 적용한 클래스들을 props.classes로 가진다. classes의 root에는 스타일이 적용된 class 이름이 저장되어 있다.</p>
</li>
<li><p>Theme은 React App의 전체적인 스타일을 적용하는데 사용한다. App.js에서 createMuiTheme 메소드를 이용하여 theme을 생성하고 ThemeProvicer 컴포넌트의 theme이라는 속성에 설정한다. 이 컴포넌트에 theme 속성을 설정하면 내부의 모든 컴포넌트에서 Material-UI 컴포넌트의 스타일을 설정할때 theme을 이용할 수 있다.</p>
</li>
</ul>
<h3 id="이슈">이슈</h3>
<ol>
<li>현재 TopChart 컴포넌트가 렌더링을 2번 하는 현상</li>
</ol>
<p><img src="https://images.velog.io/images/denmark-banana/post/4123dad0-a636-4dae-b115-c38a3ce3bb07/image.png" alt=""></p>
<blockquote>
<p>TopChart 컴포넌트의 tickers가 재갱신이 되는 이유가 Home에서 혹은 TickerList에서 tickers를 재갱신하는걸로 보인다. 자세한 내용은 추후 파악해보기로 한다.</p>
</blockquote>
<h3 id="todo">TODO</h3>
<ol>
<li>Client Test (Component)</li>
<li>Router 페이지 처리 필요</li>
<li>또한 Tab에 따라 페이지 이동없이 특정 컴포넌트만 보이게 처리</li>
<li>개인 정보 페이지</li>
<li>가상화폐에 대한 각각의 차트</li>
<li>클라이언트 - 컴포넌트 에러처리</li>
<li>Header - Content - Footer 구조 구성</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[GraphQL]]></title>
            <link>https://velog.io/@denmark-banana/GraphQL</link>
            <guid>https://velog.io/@denmark-banana/GraphQL</guid>
            <pubDate>Tue, 11 Feb 2020 12:59:12 GMT</pubDate>
            <description><![CDATA[<h2 id="graphql">GraphQL</h2>
<h3 id="graphql이란">GraphQL이란?</h3>
<blockquote>
</blockquote>
<pre><code class="language-bash">npm install graphql-yoga</code></pre>
<h3 id="over-fetching">Over-fetching</h3>
<blockquote>
<p>기존에는 사용자가 요청한 영역의 정보보다 많은 정보를 서버에서 받게 된다. Ex) User Object에서 Name만 사용할 예정인데 User를 전부 받아야 할까?
GraphQL은 Over-fetching 없이 개발자가 어떤 정보를 원하는 지에 대해 통제가 가능하다. Frontend가 Database에 사용자명만 요청할 수 있음.</p>
</blockquote>
<h3 id="under-fetching">Under-fetching</h3>
<blockquote>
<p>기존에는 전체를 완성하려고 각각의 많은 REST API(피드, 알림, 사용자 프로필 등등)을 요청해야한다. GraphQL은 한 Query에 정확하게 원하는 다양한 정보를 받을 수 있다. 그러므로 URL 체계가 없으며 End-point가 하나이다.</p>
</blockquote>
<h3 id="resolvers">Resolvers</h3>
<blockquote>
<p>Query가 Problem이라면 Resolvers는 해당 Query를 Resolve(해결)한다고 보면 된다.</p>
</blockquote>
<pre><code class="language-graphql">//schema.graphql
type Query{
    name: String!
}
//사용자가 Query에 name을 보내면 String을 보낸다</code></pre>
<pre><code class="language-js">//resolvers.js
const resolvers = {
    Query: {
        name:() =&gt; &quot;daehyun&quot;
    }
};
export default resolvers;</code></pre>
<p><img src="https://images.velog.io/images/denmark-banana/post/0d65dc0d-e9dd-4b01-8c6f-fcd3296d8648/image.png" alt=""></p>
<blockquote>
<p>localhost:4000 실행후 Playground에서 query name을 작성하면 위와 같이 &quot;daehyun&quot;이라는 String을 받을 수 있다.</p>
</blockquote>
<h3 id="playground">Playground</h3>
<blockquote>
<p>Postman과 같이 Database를 체크할 수 있음</p>
</blockquote>
<pre><code class="language-graphql">//schema.graphql
type Daehyun{
    name: String!
    age: Int!
    gender: String!
}

type Query{
    person: Daehyun!
}</code></pre>
<pre><code class="language-js">//resolver.js
const daehyun = {
    name: &quot;Daehyun&quot;,
    age: 32,
    gender: &quot;male&quot;
}

const resolvers = {
    Query: {
        person:() =&gt; daehyun
    }
};

export default resolvers;</code></pre>
<p><img src="https://images.velog.io/images/denmark-banana/post/141d60d5-bd46-44d4-8edd-35165b73495e/image.png" alt=""></p>
<blockquote>
<p>사용자가 <code>Query</code>에 person을 보내면 Daehyun type을 보낸다. Daehyun type은 name, age, gender를 가진다. <code>Frontend</code>가 이 중에서 age만 받고 싶다면? person에서 age에 서브필드만 포함하면 age 정보만 받아올 수 있다. </p>
</blockquote>
<h3 id="심화">심화</h3>
<pre><code class="language-graphql">//schema.graphql
type Person{
    id: Int!
    name: String!
    age: Int!
    gender: String!
}

type Query{
    people: [Person]!
    person(id: Int!): Person
}</code></pre>
<pre><code class="language-js">//resolver.js
import { people, getById } from &quot;./db&quot;;

const resolvers = {
    Query: {
        people:() =&gt; people,
        person:(_, { id }) =&gt; getById(id)
    }
};

export default resolvers;

//db.js
export const people = [
  {
    id: &quot;1&quot;,
    name: &quot;Daehyun&quot;,
    age: 32,
    gender: &quot;male&quot;
  },
  {
    id: &quot;2&quot;,
    name: &quot;Bom&quot;,
    age: 29,
    gender: &quot;female&quot;
  },
  ...
]

export const getById = id =&gt; {
    const filteredPeople = people.filter(person =&gt; person.id === String(id));
    return filteredPeople[0];
}
</code></pre>
<p><img src="https://images.velog.io/images/denmark-banana/post/c98f14c8-1084-4866-893e-96690c62e026/image.png" alt=""></p>
<blockquote>
<p>사용자가 <code>Query</code>에 person(id: Int)를 보내면 Person을 보낸다. 사용자가 Query에 people을 보내면 Person 배열을 보낸다.
GraphQL Resolvers는 GraphQL 서버로부터 요청을 받는다. GraphQL 서버가 <code>Query</code>나 <code>Mutation</code>의 정의를 발견하면 <code>Resolver</code>를 찾을 것이고 해당함수를 실행한다. person 함수의 첫 인자는 object이고, 두번째 인자를 id로 받아서 찾은 후 person을 반환한다.</p>
</blockquote>
<h3 id="참고">참고</h3>
<blockquote>
<p>노마드 코더 GraphQL 강의
<a href="https://academy.nomadcoders.co/courses/category/KR">https://academy.nomadcoders.co/courses/category/KR</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Routing (and upload Github Pages)]]></title>
            <link>https://velog.io/@denmark-banana/React-Routing-and-upload-Github-Pages</link>
            <guid>https://velog.io/@denmark-banana/React-Routing-and-upload-Github-Pages</guid>
            <pubDate>Wed, 05 Feb 2020 14:25:18 GMT</pubDate>
            <description><![CDATA[<h1 id="react-routing-and-upload-github-pages">[React] Routing (and upload Github Pages)</h1>
<h2 id="github-pages이란">Github pages이란?</h2>
<pre><code class="language-bash">npm i gh-pages</code></pre>
<blockquote>
<p>gh-pages란 github의 page domain에 자신의 프로젝트를 올릴 수 있는 기능이다. 무료로 static 웹사이트 (HTML, CSS, Javascript)를 업로드 할 수 있다.</p>
</blockquote>
<pre><code class="language-js">//package.json
{
    ...
    &quot;homepage&quot;: &quot;https://denmark-banana.github.io/moon&quot;
}</code></pre>
<blockquote>
<p>package.json에 다음과 같이 추가한다. (&quot;https://{userName}.github.io/{projectName}&quot;</p>
</blockquote>
<p><img src="https://images.velog.io/post-images/denmark-banana/15e63640-49ad-11ea-99ce-1b50f86e4e73/image.png" alt="image.png"></p>
<blockquote>
<p>github pages에 프로젝트 업로드를 성공하였다.</p>
</blockquote>
<h2 id="routes">Routes</h2>
<h3 id="react-router-dom">react-router-dom</h3>
<pre><code class="language-bash">npm install react-router-dom</code></pre>
<pre><code class="language-js">//app.js
function App() {
  return (
    &lt;HashRouter&gt;
      &lt;Navigation /&gt;
      &lt;Route path=&quot;/&quot; exact={true} component={Home} /&gt;
      &lt;Route path=&quot;/about&quot; component={About} /&gt;
    &lt;/HashRouter&gt;
  );
}</code></pre>
<blockquote>
<p>react-router에서 /about 링크를 접근 시 위의 &quot;/about&quot;과 &quot;/&quot; 라우트를 동시에 들르게 되므로 exact={true}라는 옵션을 주어서 해당 url이 정확히 &quot;/&quot;일때만 라우트를 접근하게 했다.</p>
</blockquote>
<h3 id="navigation">navigation</h3>
<pre><code class="language-js">//Navigation.js
function Navigation() {
  return (
    &lt;div className=&quot;nav&quot;&gt;
      &lt;Link to=&quot;/&quot;&gt;Home&lt;/Link&gt;
      &lt;Link to=&quot;/about&quot;&gt;About&lt;/Link&gt;
    &lt;/div&gt;
  );
)
export default Navigation;</code></pre>
<blockquote>
<p>Navigation component에서는 <code>&lt;a href&gt;</code> 대신 <code>&lt;Link to&gt;</code> 태그를 사용한다.</p>
</blockquote>
<h3 id="link-to-props">Link to Props</h3>
<pre><code class="language-js">//Movie.js
function Movie({ id, year, title, summary, poster, genres }) {
  return (
    &lt;div className=&quot;movie&quot;&gt;
      &lt;Link 
        to={{
          pathname: `/movie/${id}`,
          state: {
            year,
            title,
            summary,
            poster,
            genres
          }
        }}
      &gt;
        ...
    &lt;/div&gt;
  );
}

//Detail.js
class Detail extends React.Component {
  componentDidMount() {
    const { location, history } = this.props;
    if (location.state === undefined) {
      history.push(&quot;/&quot;);
    }
  }
  render() {
    const { location } = this.props;
    if (location.state) {
      return &lt;span&gt;{location.state.title}&lt;/span&gt;;
    } else {
      return null;
    }
  }
}
export default Detail;
</code></pre>
<blockquote>
<p>이렇게 Link를 통해 Props도 전달할 수 있다. &#39;{{ pathname, state }}&#39; 을 통해 상세 페이지에 Data를 전달하였다. Link를 통해 받은 <code>props</code>는 <code>location</code>을 통해 접근할 수 있다. <code>history</code>는 url에 관련된 정보를 담고 있다.</p>
</blockquote>
<h2 id="마무리">마무리</h2>
<blockquote>
<p>지금까지의 구현은 Home 페이지로 돌아갔을때마다 state(영화 정보)를 로딩해야 하는 단점이 있다. 이러한 문제점은 redux를 통해 해결할 수 있다. redux는 state를 스크린 밖에 있게 한다.</p>
</blockquote>
<p><img src="https://images.velog.io/post-images/denmark-banana/31812e00-4a75-11ea-8803-7ffa54adcf94/image.png" alt="image.png"></p>
<blockquote>
<p>강의는 이렇게 완료! 짧은 시간이었지만 1주일동안 이 강의를 통해 reactJS 기초를 배우고 웹사이트를 만들 수 있었다..!</p>
</blockquote>
<h2 id="참고">참고</h2>
<blockquote>
<p>노마드 ReactJS로 웹 서비스 만들기 강의
<a href="https://academy.nomadcoders.co/courses/category/KR">https://academy.nomadcoders.co/courses/category/KR</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Movie app 만들기]]></title>
            <link>https://velog.io/@denmark-banana/React-Movie-app-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@denmark-banana/React-Movie-app-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Tue, 04 Feb 2020 13:30:27 GMT</pubDate>
            <description><![CDATA[<h2 id="react-movie-app-만들기">[React] Movie app 만들기</h2>
<blockquote>
<p>App.js에서는 axios로 Movie Data를 가져온다. 가져온 data를 state에 set시키고 해당 data를 통해 Component들을 Render하는 구조이다.</p>
</blockquote>
<h3 id="code">Code</h3>
<pre><code class="language-js">//App.js
import React from &quot;react&quot;;
import &quot;./App.css&quot;;
import axios from &quot;axios&quot;;
import Movie from &quot;./Movie&quot;;

class App extends React.Component {
  state = {
    isLoading: true,
    movies: []
  };
  getMovies = async () =&gt; {
    const {
      data: {
        data: { movies }
      }
    } = await axios.get(&quot;URL&quot;);
    this.setState({ movies, isLoading: false });
  };
  componentDidMount() {
    this.getMovies();
  }

  render() {
    const { isLoading, movies } = this.state;
    return (
      &lt;section className=&quot;container&quot;&gt;
        {isLoading ? (
          &lt;div className=&quot;loader&quot;&gt;
            &lt;span className=&quot;loader__text&quot;&gt;Loading...&lt;/span&gt;
          &lt;/div&gt;
        ) : (
          &lt;div className=&quot;movies&quot;&gt;
            {movies.map(movie =&gt; (
              &lt;Movie
                key={movie.id}
                id={movie.id}
                year={movie.year}
                title={movie.title}
                summary={movie.summary}
                poster={movie.medium_cover_image}
                genres={movie.genres}
              /&gt;
            ))}
          &lt;/div&gt;
        )}
      &lt;/section&gt;
    );
  }
}

export default App;

//Movie.js
import React from &quot;react&quot;;
import PropTypes from &quot;prop-types&quot;;
import &quot;./Movie.css&quot;;

function Movie({ year, title, summary, poster, genres }) {
  return (
    &lt;div className=&quot;movie&quot;&gt;
      &lt;img src={poster} alt={title} title={title} /&gt;
      &lt;div className=&quot;movie__data&quot;&gt;
        &lt;h3 className=&quot;movie__title&quot;&gt;{title}&lt;/h3&gt;
        &lt;h5 className=&quot;movie__year&quot;&gt;{year}&lt;/h5&gt;
        &lt;ul className=&quot;movie__genres&quot;&gt;
          {genres.map((genre, index) =&gt; (
            &lt;li key={index} className=&quot;genres__genre&quot;&gt;{genre}&lt;/li&gt;
          ))}
        &lt;/ul&gt;
        &lt;p className=&quot;movie__summary&quot;&gt;{summary.slice(0,180)}...&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

Movie.propTypes = {
  id: PropTypes.number.isRequired,
  year: PropTypes.number.isRequired,
  title: PropTypes.string.isRequired,
  summary: PropTypes.string.isRequired,
  poster: PropTypes.string.isRequired,
  genres: PropTypes.arrayOf(PropTypes.string).isRequired
};

export default Movie;</code></pre>
<blockquote>
<ol>
<li>axios를 이용하여 Movie 정보를 json으로 받은 후에 해당 정보 array를 .map()으로 Movie Component를 생성해준다.</li>
<li>map은 item과 item number 정보를 준다.</li>
<li>axios를 통해 모든 json을 다 받고 난 후 isLoading(state)을 변경하여 새로 render해준다. </li>
</ol>
</blockquote>
<p><img src="https://images.velog.io/post-images/denmark-banana/cbc37990-4751-11ea-8825-4509694ff5e5/image.png" alt="image.png"></p>
<blockquote>
<p>위의 화면</p>
</blockquote>
<h2 id="마무리">마무리</h2>
<blockquote>
<p>다음 포스팅은 CSS를 입힐 예정이다.</p>
</blockquote>
<h2 id="참고">참고</h2>
<blockquote>
<p>노마드 ReactJS로 웹 서비스 만들기 강의
<a href="https://academy.nomadcoders.co/courses/category/KR">https://academy.nomadcoders.co/courses/category/KR</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Akka 정리 (하) ]]></title>
            <link>https://velog.io/@denmark-banana/Akka-%EC%A0%95%EB%A6%AC-%ED%95%98-</link>
            <guid>https://velog.io/@denmark-banana/Akka-%EC%A0%95%EB%A6%AC-%ED%95%98-</guid>
            <pubDate>Tue, 04 Feb 2020 08:58:15 GMT</pubDate>
            <description><![CDATA[<h1 id="akka-정리-하">Akka 정리 (하)</h1>
<h2 id="3-akka-계층구조">#3. Akka 계층구조</h2>
<h3 id="아카-계층구조">아카 계층구조</h3>
<blockquote>
<p>어떤 액터는 다음과 같은 세 가지 동작을 수행한다.</p>
</blockquote>
<ul>
<li>메시지 수신</li>
<li>메시지 송신</li>
<li>다른 액터를 만든다</li>
</ul>
<h3 id="보내고-잊기">보내고 잊기</h3>
<blockquote>
<p>액터시스템에서 tell 메서드를 이용해서 메시지를 전달하는 것은 철저하게 비동기적이다. tell 메서드를 호출하면 메시지가 실제로 목적지에 도달하는가 여부와 무관하게 즉시 리턴되기 때문이다.</p>
</blockquote>
<ol>
<li>작업의 완료 확인 어려움 -&gt; 비동기적 실행</li>
<li>메시지 순서 확인 어려움 -&gt; 보내고 받는 액터 관계가 직접적인 경우에만 확인 가능</li>
</ol>
<h2 id="4-trycatch">#4. try/catch</h2>
<blockquote>
<p>SupervisorStrategy</p>
</blockquote>
<ul>
<li>Resume</li>
<li>Restart</li>
<li>stop</li>
</ul>
<h2 id="5-액터와-상태기계">#5. 액터와 상태기계</h2>
<blockquote>
<p>new Procedure -&gt; become()</p>
</blockquote>
<h2 id="6-라우터">#6. 라우터</h2>
<blockquote>
<p>Java8에서 병렬처리 : stream() 대신 parallelStreaM() 사용
Akka에서 병렬처리 Router</p>
</blockquote>
<h2 id="7-보내고-잊지-않기---future">#7. 보내고 잊지 않기 - future</h2>
<blockquote>
<p>Java8 CompletableFuture 퓨쳐
Akka에서 퓨쳐 사용 예시 </p>
</blockquote>
<pre><code class="language-java">Timeout timeout = new Timeout(Duration.create(5, &quot;seconds&quot;));
Future&lt;Object&gt; future = Patterns.ask(actor, msg, timeout);
String result = (String) Await.result(future, timeout.duration());
//동기로 쓰레드가 기다림</code></pre>
<blockquote>
<p>우리가 메시지를 보내고자 하는 목적지에 해당하는 액터는 ask 메서드에게 인수로 전달된다. 보내려는 메시지와 타임아웃 객체도 인수로 전달된다. Await.result 호출은 현재 스레드가 그 자리에서 답변을 기다리게 만든다. 블로킹 호출이다.</p>
</blockquote>
<pre><code class="language-java">public NobblockingActor() {
  child = context().actorOff(Props.create(CalculationActor.class), &quot;calculationActor&quot;);
  ec = context().system().dispatcher();
}

Future&lt;Object&gt; future = Patterns.ask(child, message, timeout);
// 
future.onSuccess(new SaySuccess&lt;Object&gt;(), ec);
future.onComplete(new SayComplete&lt;Object&gt;(), ec);
future.onFailure(new SayFailure&lt;Object&gt;(), ec);

public final  class SaySuccess&lt;T&gt; extends OnSuccess&lt;T&gt; {
  @Override public final void onSuccess(T result) {
    log.info(&quot;Succeeded with &quot; + result);
  }
}
</code></pre>
<blockquote>
<p>child Actor로 향하는 message를 timeout과 함께 보냈다. 비동기적으로 동작하며 callback과 유사한 방식으로 동작이 끝나고 메시지를 받으면 상황에 맞게 nonblocking 함수 (onSuccess, onComplete, onFailure중 하나)를 실행한다.</p>
</blockquote>
<h3 id="에이전트">에이전트</h3>
<h2 id="8-클러스터">#8. 클러스터</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Akka 정리 (상)]]></title>
            <link>https://velog.io/@denmark-banana/Akka-%EC%A0%95%EB%A6%AC-%EC%83%81-</link>
            <guid>https://velog.io/@denmark-banana/Akka-%EC%A0%95%EB%A6%AC-%EC%83%81-</guid>
            <pubDate>Tue, 04 Feb 2020 06:15:34 GMT</pubDate>
            <description><![CDATA[<h1 id="akka-정리-상">Akka 정리 (상)</h1>
<h2 id="1-akka-특징">#1. Akka 특징</h2>
<ul>
<li>반응성 : nonblocking/asyncrhonous</li>
<li>메시지 중심 : event-driven, 메시지 중심</li>
<li>모듈화 : Akka 세계서의 컴포넌트는 Actor이고, 이 Actor는 서로 완벽하게 독립적이며, 코드의 응집성, 느슨한 결합, 캡슐화와 같은 프로그래밍 원리를 완벽하게 구축한다.</li>
</ul>
<h3 id="처리율">처리율</h3>
<blockquote>
<p>멀티코어를 사용하는 프로그램의 속도는 프로그램 내부에 존재하는 순차적 부분이 사용하는 시간에 의해서 제한된다. - 암달의 법칙</p>
</blockquote>
<p>Thread나 Task를 만들어서 ExecutorService에게 제출하는 식으로 동시성 코드를 작성할면 여러 개의 스레드가 동시에 작업 수행 한다.</p>
<ol>
<li>but 프로그램 안에는 Thread나 Task가 포함하지 않는 코드가 존재</li>
<li>but synchronized 블록이나 데이터베이스, 네트워크 API 호출 등을 만날 때 다른 스레드와 나란히 줄을 서서 순차적으로 작업을 수행해야 하는 경우도 있다. 이러한 순차적 코드의 또 다른 이름은 &#39;블로킹 콜&#39;이다</li>
</ol>
<p>아카는 스칼라 언어로 작성되었지만 더 아래로 내려가면 자바의 동시성 패키지를 사용하기 때문에 아카를 사용하는 것은 궁극적으로 자바의 Thread나 Task를 사용하는 것과 마찬가지다.</p>
<p>하지만 아카를 사용하면 프로그램 곳곳에 존재하는 순차적 부분, 블로킹 콜을 전부 없애거나 적어도 최소한으로 만드는 것이 가능해진다.</p>
<p>아카를 이용해서 프로그램을 설계한다는 것은 블로킹 호출이 일어나는 지점을 난블로킹 호출로 전환하는 작업을 수행하는 것을 의미한다.</p>
<h3 id="스케일-아웃">스케일 아웃</h3>
<p>전통적으로 웹서버가 많은 트래픽을 감당하는 방법은 로드 밸런서 뒤에 여러 대의 서버를 설치하는 방식이다. 다만 이 방법은 각각의 톰캣들이 커뮤니케이션할 수 없는 문제, 하나의 컴포넌트만 떼어서 독립적으로 실행하기 어려운 문제가 있다. </p>
<blockquote>
<p>아카의 경우라면 이야기가 다르다. 아카 세계에서 컴포넌트는 액터이며, 어느 액터 하나만 콕 집어내어 독자적인 JVM으로 실행하는 것은 거의 아무런 노력이 들지 않는다.</p>
</blockquote>
<h3 id="모듈화">모듈화</h3>
<p>액터가 제공하는 가장 강력한 기능의 하나는 모듈화다. 액터는 서로 완벽하게 독립적이며 오로지 메시지를 주고 받는 방식으로만 커뮤니케이션한다.</p>
<h3 id="차세대-동시성-모델">차세대 동시성 모델</h3>
<blockquote>
<p><strong>Design Pattern - 어댑터 패턴</strong> : 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.</p>
</blockquote>
<p>액터 모델은 동시성 코드를 작성하기 위해서 다른 차원의 추상수준을 제공한다. 여기에서는 잠금장치(lock)와 같은 구조물이 없다. 액터 모델에서는 오직 액터만 존재한다. 그들은 서로 독립적인 구조물이며 서로 메서드를 호출할수도 없고 new를 통한 인스턴스를 만들 수 도 없다.</p>
<hr>
<h2 id="2-ping-pong-예제">#2. Ping Pong 예제</h2>
<pre><code class="language-java">//Main.java
public static void main(String[] args) {
  ActorSystem actorSystem = ActorSystem.create(&quot;TestSystem&quot;);
  ActorRef ping = actorSystem.actorOf(Props.create(PingActor.class), &quot;pingActor&quot;);
  ping.tell(&quot;start&quot;, ActorRef.noSender());
}

//PingActor.java
public class PingActor extends UntypedActor {
    private LoggingAdapter log = Logging.getLogger(getContext().system(), this);
    private ActorRef pong; 

    @Override
    public void preStart() {
        this.pong = context().actorOf(Props.create(PongActor.class, getSelf()), &quot;pongActor&quot;);
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            String msg = (String)message;
            log.info(&quot;Ping received {}&quot;, msg);
            pong.tell(&quot;ping&quot;, getSelf());
        }
    }
}

//PongActor.java
public class PongActor extends UntypedActor {
    private LoggingAdapter log = Logging.getLogger(getContext().system(), this);
    private ActorRef ping;

    public PongActor(ActorRef ping) {
        this.ping = ping;
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            String msg = (String)message;
            log.info(&quot;Pong received {}&quot;, msg);
            ping.tell(&quot;pong&quot;, getSelf());
            Thread.sleep(1000);
        }
    }

}


</code></pre>
<ul>
<li>액터 시스템</li>
<li>액터 만들기 (Props, 액터의 이름)</li>
</ul>
<h3 id="props">props</h3>
<blockquote>
<p>액터를 만들기 위한 조리법. 액터를 만드는 데 필요한 구성요소를 담는 일종의 config같은 클래스다.</p>
</blockquote>
<h3 id="액터의-이름">액터의 이름</h3>
<blockquote>
<p>액터들은 트리와 비슷한 계층구조를 형성한다. A라는 액터가 B라는 액터를 만들면 A는 B의 부모가 된다. 그렇기 때문에 경로라는 개념이 있으며 액터의 이름은 이러한 경로에서 의미를 갖는다.</p>
</blockquote>
<h3 id="actorof">actorOf</h3>
<blockquote>
<p>액터를 만들기 위한 &#39;팩토리&#39; 메서드. 첫번째 인수는 액터를 위한 타입, 그 다음에 나열되는 인수는 생성자를 호출할 때 전달되는 인수를 의미한다.</p>
</blockquote>
<h3 id="actorref">ActorRef</h3>
<blockquote>
<p>액터시스템 내에서 사용하는 액터는 모두 ActorRef다. 액터를 가리키는 참조이며 모든 액터는 오직 ActorRef라는 타입에 의해서만 접근될 수 있다. pingActor에 아무리 많은 퍼블릭 메서드를 정의해도 우리가 가지고 있는 것은 pingActor가 아니라 ActorRef이기 때문에 퍼블릭 메서드에 직접 접근할 수 없다.</p>
</blockquote>
<p><img src="https://images.velog.io/post-images/denmark-banana/b70ef760-4718-11ea-a944-efb7a86d3652/image.png" alt="image.png"></p>
<h3 id="장소-투명성">장소 투명성</h3>
<blockquote>
<p>사용할 액터가 물리적으로 어디에 존재하는지 알 필요가 없음을 가리키는 개념이다. 앞에서 본 것처럼 PingActor는 ActorRef에 둘러쌓여서 장소를 알 수 없으며 오직 ActorRef를 가지고 작업을 수행한다.</p>
</blockquote>
<h3 id="메시지-전송">메시지 전송</h3>
<blockquote>
<p>객체지향에서는 &#39;객체를 만든 다음 그 객체가 가지고 있는 메서드를 호출&#39;한다. 액터 세계에서는 &#39;액터를 만든 다음 그 액터에 메시지를 전송&#39;하는 것이 가장 기본이다.
ActorRef는 <code>tell</code>과 <code>ask</code>라는 두 개의 API를 제공한다.</p>
</blockquote>
<h3 id="tell">tell</h3>
<ul>
<li>메시지</li>
<li>발신자</li>
</ul>
<blockquote>
<p>첫번째 인수인 메시지는 임의의 자바 객체(Object)가 될 수 있다. PingActor, PongActor 클래스를 정의할 때 &#39;extends UntypedActor&#39;라고 정의하였기 때문에 액터가 받아들이는 메시지의 타입이 미리 정해져 있지 않음을 의미한다.
발신자의 주소는 반드시 ActorRef 타입을 가져야 한다. 즉 발신자는 어떤 액터다.</p>
</blockquote>
<ul>
<li>getself() : 이 메서드는 액터 자신의 ActorRef 객체를 리턴한다. </li>
<li>getSender() : 포워딩</li>
<li>noSender() : 발신인 주소 null (주소가 의미없을때)</li>
</ul>
<h3 id="메일박스">메일박스</h3>
<blockquote>
<p>액터에 어떤 메시지를 전송하면 그것은 액터마다 가지고 있는 메일박스에 저장됨
액터 하나를 뗴어놓고 생각해보면 Node.js의 이벤트 처리 방식과 유사하다. 전달되는 메시지가 메일박스에 차곡차곡 쌓이고, 액터는 그 메시지를 한 번에 하나씩 처리한다.</p>
</blockquote>
<h3 id="onreceive">onReceive</h3>
<blockquote>
<p>액터시스템은 내부에 스레드풀을 보유하고 있다. 디스패처라고 부르기도 하는데, 액터시스템은 일정한 규칙에 따라 스레드를 액터에게 할당한다. 이렇게 스레드가 할당된 액터는 메시지를 처리하고 스레드를 풀로 반납한다. 액터시스템은 반납된 스레드를 다른 액터에게 할당하는 방식으로 작업을 이어나간다.</p>
</blockquote>
<ul>
<li>메일박스에서 메시지를 하나 꺼낸다.</li>
<li>액터의 onRecieve 메서드를 호출하면서 메시지를 인수로 전달한다.</li>
<li>onReceive의 동작이 완료된다.</li>
<li>스레드를 반납할 시간이 되었는지를 확인한다.</li>
<li>시간이 되었으면 스레드를 반납하고 다음 순서를 기다린다.</li>
<li>아직 시간이 되지 않았으면 메일박스에서 다음 메시지를 꺼내고 위 과정을 반복한다.</li>
</ul>
<blockquote>
<ol>
<li>어느 특정한 시점에서 보았을 때 액터의 onReceive 메서드를 호출하는 스레드는 반드시 1개로 국한된다. 디스패처가 하나의 엑터에 2개 또는 그 이상의 스레드를 동시에 할당하지 않기 때문이다.</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li>하지만 액터의 onReceive 메서드를 호출하는 스레드가 영원히 똑같은 스레드인 것은 아니다. 다른 스레드로 얼마든지 달라질 수 있다.</li>
</ol>
</blockquote>
<h3 id="액터-라이프사이클">액터 라이프사이클</h3>
<p>PingActor는 preStart()에서 PongActor를 만들었다.</p>
<ul>
<li>actorOf를 systemActor가 아니라 context()로부터 호출하고 있다.</li>
<li>Props.create() 메서드가 인수 두 개를 받아들이고 있다.</li>
</ul>
<blockquote>
<p>모든 액터는 자신이 실행되는 액터시스템의 환경이나 문맥, 즉 ActorContext에 접근할 수 있는 context() 메서드를 포함하고 있다. (ActorSystem의 모습을 나타내는 객체)</p>
</blockquote>
<p>모든 액터는 다음과 같은 라이프사이클을 가지고 있다.</p>
<ul>
<li>생성</li>
<li>재시작</li>
<li>멈춤</li>
</ul>
<blockquote>
<p>재시작은 액터시스템의 어딘가에서 에러가 발생해 ActorRef가 내부에 저장된 액터 객체를 버리고, 동일한 객체를 클래스의 생성자를 호출함으로써 액터를 새로 만드는 경우다.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>