<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sootulliyang_dev.log</title>
        <link>https://velog.io/</link>
        <description>developer;  not kim but Young</description>
        <lastBuildDate>Mon, 13 Mar 2023 15:13:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sootulliyang_dev.log</title>
            <url>https://velog.velcdn.com/images/sootulliyang_dev/profile/0ed83d65-e13e-4a89-abac-9d3e01e5e1dd/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sootulliyang_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sootulliyang_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[지속가능한 컴포넌트를 향하여]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EC%A7%80%EC%86%8D%EA%B0%80%EB%8A%A5%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EB%A5%BC-%ED%96%A5%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@sootulliyang_dev/%EC%A7%80%EC%86%8D%EA%B0%80%EB%8A%A5%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EB%A5%BC-%ED%96%A5%ED%95%98%EC%97%AC</guid>
            <pubDate>Mon, 13 Mar 2023 15:13:16 GMT</pubDate>
            <description><![CDATA[<p>📺 <a href="https://www.youtube.com/watch?v=fR8tsJ2r7Eg">토스ㅣSLASH 22 - Effective Component 지속 가능한 성장과 컴포넌트</a></p>
<blockquote>
</blockquote>
<p>제품의 ‘변경’은 언제? =&gt; 고객의 니즈에 의해
그렇다면 우리는 변경을 예측해야 한다.
평소 개발하는 습관은 어떠한가? 규모가 커지면 적당히 분리.. 
“적당히”란? 명확한 기준을 만들기!</p>
<h3 id="변경에-유연한-컴포넌트-만들기">변경에 유연한 컴포넌트 만들기</h3>
<ol>
<li>Headless 기반 추상화<ul>
<li>변하는 것과 vs 상대적으로 변하지 않는 것 분리 
  a. 데이터 추상화<pre><code> ex) 달력 - useCalendar 커스텀 훅을 만든다면
       - 일자들은 변경이 있는 데이터
       - 일~월 요일 UI는 동일
 → hooks로 모듈화하는 방식.. 이러한 패턴을 headless </code></pre>  b. 인터랙션을 추상화</li>
</ul>
</li>
<li>한가지 역할만 하는 컴포넌트로 만들거나 그 조합으로 만들기
 ex) 드롭다운 - isOpen, 상태값들, 노출여부(Menu), 각 메뉴 아이템, ...</li>
<li>도메인 분리<ul>
<li>도메인을 포함하는 것과 / 포함하지 않은 컴포넌트 분리
 ex) SelectFrameWork -&gt; Select
 : 일반적인 인터페이스로 분리해야 컴포넌트의 역할을 이해하기 쉬움</li>
</ul>
</li>
</ol>
<h3 id="action-items">Action Items</h3>
<ol>
<li>인터페이스 먼저 고민<ul>
<li>인터페이스의 의도</li>
<li>컴포넌트가 해야할 기능</li>
<li>어떤 데이터를 다루고 있고 어떻게 표현되어 있는지
=&gt; 변경할 때 파악해야하는 것들이라. 구현 자체보다 중요함</li>
</ul>
</li>
<li><strong>컴포넌트를 나누는 이유</strong><ul>
<li>분리함으로써 복잡도가 줄어드는지 / 바로 재사용 가능한지 / 꼭 분리해야하는 이유가 있는 건지</li>
<li>미래의 나에게 도움이 될 것…!</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[빌드한 파일을 디버깅하는 방법? 소스맵 Source Map]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EB%B9%8C%EB%93%9C%ED%95%9C-%ED%8C%8C%EC%9D%BC%EC%9D%84-%EB%94%94%EB%B2%84%EA%B9%85%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%86%8C%EC%8A%A4%EB%A7%B5-Source-Map</link>
            <guid>https://velog.io/@sootulliyang_dev/%EB%B9%8C%EB%93%9C%ED%95%9C-%ED%8C%8C%EC%9D%BC%EC%9D%84-%EB%94%94%EB%B2%84%EA%B9%85%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%86%8C%EC%8A%A4%EB%A7%B5-Source-Map</guid>
            <pubDate>Sat, 14 Jan 2023 05:13:55 GMT</pubDate>
            <description><![CDATA[<p>*관련 지난 포스트 <a href="https://velog.io/@sootulliyang_dev/%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%97%90%EB%9F%AC%EB%A1%9C%EA%B7%B8-%EC%84%9C%EB%B9%84%EC%8A%A4-Sentry-Datadog-%EA%B3%BC-SourceMap%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">🔗 프론트 에러로그 서비스 Sentry, Datadog</a></p>
<p>개발환경에서는 발생하지 않다가 배포 이후에 버그가 발견된다면? 심히 당황스럽겠지만 이를 위해 개발하면서 수시로 빌드해보며 검증해볼 필요가 있다.</p>
<p>next 프로젝트의 경우에도 스크립트 명령어 <code>next run dev</code> 은 빌드가 포함되지 않고 페이지를 로컬로 띄우는 반면, <code>start</code>나 production 환경으로 실행하는 스크립트에서는 빌드 후 로컬서버로 페이지를 띄운다.</p>
<p>웹앱 서비스가 복잡해지면서 코드의 양도 파일 수도 비대해지게 됨에 따라 요청/응답이 무겁지 않게 즉 클라이언트 측에서 가볍게 다운로드 받을 수 있게끔 파일을 압축해주는 번들러가 필요해졌다.(웹팩, Rollup, Parcel 등이 있고)
번들링 과정 중 &quot;빌드&quot;란 컴퓨터 언어로 컴파일된 소스를 일종의 실행 파일로 변환시켜주는 셈이다.</p>
<p>개발환경에서 없던 서비스 배포 이후에 에러가 발생한다면 빌드 이후의 문제일 수 있고, </p>
<h4 id="❓-그렇다면-빌드된-파일을-디버깅할-수-있는-방법이-있을까">❓ 그렇다면 빌드된 파일을 디버깅할 수 있는 방법이 있을까?</h4>
<h4 id="❗️-source-map을-이용해서-디버깅할-수-있다">❗️ Source Map을 이용해서 디버깅할 수 있다.</h4>
<p>빌드한 파일을 원본과 연결시켜주는 기능이 바로 Source Map 이다.
<strong>&quot;배포용으로 빌드한 파일과 원본 파일을 서로 연결시켜주는 기능&quot;</strong></p>
<p>대표적으로 웹팩을 예를 들면, <code>devtool</code> 이라는 스크립트로 sourceMap을 설정할 수 있다.</p>
<ol>
<li><p>웹팩 config 파일에 devtool 속성을 추가하고 설정 옵션 중 하나를 선택해 지정해주면 된다.</p>
<pre><code class="language-js">// webpack.config.js
module.exports = {
devtool: &#39;cheap-eval-source-map&#39;
}</code></pre>
</li>
<li><p>devtool 옵션</p>
</li>
</ol>
<p>*devtool - this option controls if and how source maps are generated</p>
<ul>
<li><p><code>eval</code> : 개발환경용 빌드에 적합</p>
</li>
<li><p><code>eval-cheap-source-map</code> : 개발환경용 차후 선택으로 나쁘지 않음</p>
</li>
<li><p><code>eval-source-map</code> : 개발환경용 빌드 시 권장됨. 소스맵을 고도로 활용하기에 좋음. 빌드 속도는 느림.</p>
</li>
<li><p><code>source-map</code> : 상용 배포용으로 권장됨. 소스맵 고도 활용 가능. 빌드 속도는 느림. rebuild도 느림.</p>
<p>등등 매우 많은 옵션이 있다.</p>
<ol start="3">
<li>plugin을 사용해도 좋다</li>
</ol>
<ul>
<li><code>SourceMapDevToolPlugin</code> / <code>EvalSourceMapDevToolPlugin</code> 등, 더 자세한 설정이 가능함</li>
<li>다만 웹팩 config파일에서 devtool 옵션을 설정하였으면 plugin을 중복사용하지 말라. (옵션 설정 시 플러그인을 내부적으로 자동 적용하므로)</li>
</ul>
</li>
</ul>
<p><a href="https://webpack.js.org/configuration/devtool/#devtool">🔗 웹팩 공식문서 - Devtool 관련</a></p>
<p>참고
<a href="https://developer.chrome.com/docs/devtools/javascript/source-maps/">https://developer.chrome.com/docs/devtools/javascript/source-maps/</a>
<a href="https://blog.teamtreehouse.com/introduction-source-maps">https://blog.teamtreehouse.com/introduction-source-maps</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트 에러로그 서비스 Sentry, Datadog]]></title>
            <link>https://velog.io/@sootulliyang_dev/%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%97%90%EB%9F%AC%EB%A1%9C%EA%B7%B8-%EC%84%9C%EB%B9%84%EC%8A%A4-Sentry-Datadog-%EA%B3%BC-SourceMap%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@sootulliyang_dev/%ED%94%84%EB%A1%A0%ED%8A%B8-%EC%97%90%EB%9F%AC%EB%A1%9C%EA%B7%B8-%EC%84%9C%EB%B9%84%EC%8A%A4-Sentry-Datadog-%EA%B3%BC-SourceMap%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Fri, 06 Jan 2023 07:57:43 GMT</pubDate>
            <description><![CDATA[<p>유저가 실제 서비스를 사용하다가 에러화면을 맞닥뜨리는 경우는 얼마나 될까?
서비스의 프론트엔드를 개발하면서 에러 케이스를 처리하는 팝업이나 리다이렉트 등의 처리를 해두긴 하지만, 실제 에러 상황에서 유저를 잘 달래줄 수 있는지는 확신이 없다.</p>
<p>CS나 앱스토어/구글플레이를 통해 인입된 이슈들은 유저가 에러케이스에서 불쾌함을 다 느낀 이후 한참 뒤 전달되는 경우일 수 있다. </p>
<p>기기 정보나 당시 배포한 작업이 있는지 등등 추적해보는 시도를 할 수는 있지만 정확한 원인 파악이 어렵다. 유저의 기기를 전달받아 접속해볼 수도 없고, 콘솔로그로 찍힌 에러로그를 유저로부터 전달받을 수도 없기 때문!</p>
<p>서버사이드가 아닌 클라이언트 단에서 발생한 에러를 트래킹할 수 있는 서비스들을 알아보았다.</p>
<h2 id="sentry">Sentry</h2>
<p>애플리케이션에서 오류가 발생하면 메일을 보내주고 슬랙 메시지로 연동할 수도 있다.
javascript, react, angular, vue, node.js, python, django, ios, android, java, php 등 언어를 다양하게 지원하고 있고 에러 리포팅을 연계할 수 있는 서비스도 slack, github 등 다양하게 제공한다.</p>
<p><img src="https://velog.velcdn.com/images/sootulliyang_dev/post/7cce1bd8-7c67-4deb-ac1e-4a20b983e4f4/image.png" alt=""></p>
<p>에러 리포팅은 필수이고 에러를 파악할 수 있는 정보를 전달해주는데</p>
<ul>
<li>디바이스</li>
<li>에러 메시지</li>
<li>앱 정보(id, 앱/빌드 버전 등)</li>
<li>브라우저 정보</li>
<li>OS</li>
<li>breadcrumbs* 에러 발생 시 경로</li>
</ul>
<p>공식문서(리액트용) <a href="https://docs.sentry.io/platforms/javascript/guides/react/">https://docs.sentry.io/platforms/javascript/guides/react/</a></p>
<p>*무료로는 한개의 계정으로 5천개의 에러까지 30일간의 히스토리까지 이용할 수 있다고 한다.</p>
<p>npm 등으로 인스톨 후 셋업 예시로는 다음과 같다.</p>
<pre><code class="language-js">import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import * as Sentry from &quot;@sentry/react&quot;;
import { BrowserTracing } from &quot;@sentry/tracing&quot;;
import App from &quot;./App&quot;;

Sentry.init({
  dsn: &quot;https://examplePublicKey@o0.ingest.sentry.io/0&quot;,
  integrations: [new BrowserTracing()],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

ReactDOM.render(&lt;App /&gt;, document.getElementById(&quot;root&quot;));

// Can also use with React Concurrent Mode
// ReactDOM.createRoot(document.getElementById(&#39;root&#39;)).render(&lt;App /&gt;);</code></pre>
<p>최상위에서 Sentry.init() 메소드로 실행시켜주는 모양새이다.</p>
<p>위 공식문서의 기본 예시 외 다른 예시로는 아래와 같다.</p>
<pre><code class="language-js">Sentry.init({
  dsn: &#39;dsn key&#39;,
  release: &#39;release version&#39;,
  environment: &#39;production&#39;,
  normalizeDepth: 6,
  integrations: [
    new Sentry.Integrations.Breadcrumbs({ console: true }),
    new BrowserTracing(),
  ],
});</code></pre>
<h4 id="configuration">Configuration</h4>
<p>Sentry 기본 설정에 필요한 정보가 더 추가되어 있다.</p>
<ul>
<li><code>dsn</code> : 이벤트 전송을 위한 식별키</li>
<li><code>release</code> : 애플리케이션 버전 *package.json 기준이면 오류 추적에 용이함!</li>
<li><code>environment</code> : 애플리케이션 환경 (dev or development/production 등)</li>
<li><code>normalizeDepth</code> : 컨텍스트 데이터를 해당 뎁스로 정규화 (기본 3)</li>
<li><code>integrations</code> : SDK별 통합 구성 설정 *리액트의 경우 react-router integration설정이 가능하다고 함)</li>
</ul>
<p>여기에 리액트16이상에서 제공하는 Error Boundary를 사용해 예기치 못한 에러가 발생했을 때 보여줄 fallback UI를 함께 구성할 수 있다. 또는 센트리 자체 제공 Error Boundary 컴포넌트가 있는 듯 하다.</p>
<p>*관련 포스팅: <a href="https://velog.io/@sootulliyang_dev/ErrorBoundary%EC%99%80-componentDidCatch">ErrorBoundary와 componentDidCatch</a></p>
<pre><code class="language-js">import React from &#39;react&#39;;
import * as Sentry from &#39;@Sentry/react&#39;;
&lt;Sentry.ErrorBoundary
  fallback={&lt;p&gt;에러가 발생하였습니다. 잠시 후 다시 시도해주세요.&lt;/p&gt;}
&gt;
  &lt;Example /&gt;
&lt;/Sentry.ErrorBoundary&gt;;</code></pre>
<h4 id="methods">Methods</h4>
<p>리액트의 Error Boundary 컴포넌트는 제공하는 componentDidCatch 처럼 센트리가 제공하는 에러 이벤트 전송 api 가 있다.</p>
<ul>
<li><p><code>captureException</code> : error 객체 또는 에러 메시지(문자열)를 보낼 수 있다. </p>
<pre><code class="language-js">import * as Sentry from &#39;@Sentry/react&#39;;
try {
aFunctionThatMightFail(); // 실패할 함수를 의미한다.
} catch (err) {
Sentry.captureException(err);
}</code></pre>
</li>
<li><p><code>captureMessage</code> : 에러메시지(텍스트) 를 보낼 수 있다.</p>
<pre><code class="language-js">Sentry.captureMessage(&#39;000페이지에서 예기치 못한 에러가 발생하였습니다.&#39;);</code></pre>
</li>
</ul>
<h3 id="장점과-활용">장점과 활용</h3>
<ul>
<li><p>scope 단위로 에러이벤트 데이터를 관리한다는 점
  *withScope..</p>
</li>
<li><p>이벤트에 임의 데이터를 연결할 수 있는 기능을 제공(Context) 요청 데이터와 에러응답 데이터를 확인하기 위해서는 context를 이용하여 추가적으로 데이터를 전송해주도록 해야함
  *setContext..</p>
</li>
<li><p>HTTP status의 4<strong>, 5</strong> 등의 에러코드를 수집할 때 기준과 구분이 있어야 분석이 필요한 에러를 잘 골라내 수집할 수 있을 것으로 보인다.</p>
</li>
</ul>
<p>참고 </p>
<ul>
<li><a href="https://tech.kakaopay.com/post/frontend-sentry-monitoring/">카카오 페이FE - Sentry로 우아하게 프론트엔드 에러 추적하기</a></li>
<li><a href="https://teamdable.github.io/techblog/Sentry-Error-Tracking">Sentry를 활용한 에러 모니터링 및 트래킹
</a></li>
<li><a href="https://urbanbase.github.io/dev/2021/03/04/Sentry.html">https://urbanbase.github.io/dev/2021/03/04/Sentry.html</a></li>
</ul>
<br/>

<p>추가로 스터디해볼 요소:</p>
<ul>
<li>Datadog</li>
<li>Source Map</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[useInView와 스크롤 이슈]]></title>
            <link>https://velog.io/@sootulliyang_dev/useInView%EC%99%80-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EC%8A%88</link>
            <guid>https://velog.io/@sootulliyang_dev/useInView%EC%99%80-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EC%9D%B4%EC%8A%88</guid>
            <pubDate>Mon, 02 Jan 2023 03:18:20 GMT</pubDate>
            <description><![CDATA[<p>useInView는 Intersection Observer API 에서 제공되는 hook이다.
(<a href="https://www.npmjs.com/package/react-intersection-observer">react-intersection-observer 모듈</a>)</p>
<p>인스타그램이나, 쇼핑 앱의 홈화면 등 모바일 화면에서 <strong>무한스크롤</strong> 적용을 위해 많이 사용하는 듯 하다.
무한스크롤의 의미를 다시 한번 짚어보자면, 
우리 웹사이트는 첫 화면부터 유저에게 보여줄 내용이 많아요! 하고 모든 데이터를 한번에 다 보여주려고 하면,
유저쪽 클라이언트에 큰 부담이 되어 오히려 느려지게 되거나 데이터 없는 흰 화면만 보여줄 수도 있게 된다. 그래서 <strong>스크롤을 더 내리게 될 때마다 더 필요한 데이터를 호출하는 방식</strong>이 무한스크롤 이다.</p>
<p>useInView 훅은 리액트 컴포넌트의 &quot;inView&quot; 상태를 모니터링해주는 훅이다. 즉 요소가 뷰포트에 진입/제외 되는 시점을 파악시켜준다.</p>
<pre><code class="language-js">import React, { uesEffect } from &#39;react&#39;;
import { useInView } from &#39;react-intersection-observer&#39;;

const Home = () =&gt; {
  const { ref, inView } = useInView({
     threshold: 0,
     triggerOnce: true, // 기본 : false
     // ..
  });

  useEffect(() =&gt; {
    // 예를 들어
    if(inView) onLoadMoreData()
  }, [inView]);

  return (
    &lt;Section ref={ref}&gt;
      {inView &amp;&amp; &lt;Widget /&gt;}
      // ..
    &lt;/&gt;
  );
};
</code></pre>
<p>위 예제를 살펴보면
viewport에 보여질 때를 체크할 element에 ref속성을 걸어주고, 이 요소가 뷰포트 안에 보였을 때 inView state가 true 값이 되는 걸 조건으로 사용하여 특정 컴포넌트나 엘리먼트를 렌더하는 코드이다.</p>
<p><img src="https://velog.velcdn.com/images/sootulliyang_dev/post/75e8dc74-ce95-4080-ab52-c32c34405a33/image.png" alt="https://cross-code.github.io/posts/IntersectionObserver/"><font size=2 color=grey>출처: <a href="https://cross-code.github.io/posts/IntersectionObserver/">https://cross-code.github.io/posts/IntersectionObserver/</a></font></p>
<h4 id="methods">methods</h4>
<ul>
<li><code>observe(targetElement)</code> : 타겟 엘리먼트에 대한 관찰을 시작.</li>
</ul>
<h4 id="props">props</h4>
<ul>
<li><code>root</code> : 타깃 엘리먼트를 관찰하는 viewport element. 기본은 브라우저 뷰포트임.</li>
<li><code>threshold</code> : 0~1 값으로, 뷰포트에 target element가 얼마나 보였을 대 노출되었다고 판단할 것인지에 대한 값. (1로 갈수록 요소가 100% 보일 때 노출되었다고 판단함을 의미)</li>
<li><code>triggerOnce</code> : observer가 한번만 실행됨을 의미. 디폴트가 false.</li>
<li><code>initialInView</code> : inView의 초기값을 설정. 처음부터 target element가 보일 것으로 예사오디면 true부여해주어도 된다. (기본이 false)
이 외에도 더 있음(<a href="https://react-intersection-observer.vercel.app/?path=/story/introduction--page">https://react-intersection-observer.vercel.app/?path=/story/introduction--page</a>)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ErrorBoundary와 componentDidCatch]]></title>
            <link>https://velog.io/@sootulliyang_dev/ErrorBoundary%EC%99%80-componentDidCatch</link>
            <guid>https://velog.io/@sootulliyang_dev/ErrorBoundary%EC%99%80-componentDidCatch</guid>
            <pubDate>Fri, 23 Dec 2022 07:35:16 GMT</pubDate>
            <description><![CDATA[<p>리액트에서는 에러 등의 예외가 발생하면 모든 컴포넌트를 unMount 시킨다.
이 경우 유저에게는 흰 화면만 보이게 되는데, 이러한 조치는 사용자경험에서 좋지 않다.</p>
<p>이를 위해 리액트는 ErrorBoundary 컴포넌트를 제공한다.</p>
<h2 id="errorboundary-컴포넌트">ErrorBoundary 컴포넌트</h2>
<p>App 컴포넌트를 ErrorBoundary로 감싸 리턴한다.
하위 컴포넌트에서 발생한 예외를 감지하여 fallback UI를 보여주는 등의 역할을 한다.</p>
<pre><code class="language-js">&lt;ErrorBoundary&gt;
    &lt;App /&gt;
&lt;/ErrorBoundary&gt;</code></pre>
<p>&lt; ErrorBoundary 컴포넌트 구조 &gt;</p>
<pre><code class="language-js">import React from &quot;react&quot;;

import CustomFallbackUI from &quot;./CustomFallbackUI&quot;;

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 다음 렌더링에서 폴백 UI가 보이도록 상태를 업데이트
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 에러 리포팅 서비스에 에러를 기록
    console.log(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 폴백 UI 렌더
      return &lt;CustomFallbackUI /&gt;;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;</code></pre>
<p><font color=grey>*아직 react hook에서는 componentDidMatch 등의 메소드를 지원하지 않아 클래스형 컴포넌트 구조이다.</font></p>
<br/>

<p>내가 하고 싶었던 작업은
ErrorBoundary 에서 fallback UI (에러 팝업 등)을 보여주기 전
새로고침을 2~3회 정도 시도 후 그 때에도 아직 에러 상태라면 에러 팝업을 보여주도록 하는 것이었다.</p>
<ul>
<li>배경 
이 때 ErrorBoundary에 react-router-dom 의 createBrowserHistory() 메소드로 생성한 값을 history라는 이름으로 넘겨주고 있었고</li>
</ul>
<pre><code class="language-js">&lt;ErrorBoundary history={history}&gt;
    &lt;App /&gt;
&lt;/ErrorBoundary&gt;</code></pre>
<ul>
<li><p>작업
history의 location: { pathname, search } 를 활용하여 홈화면에서의 에러 등을 구분하여 처리하는 게 목적이었다.</p>
<ol>
<li>메인 홈페이지에서 에러가 날 경우: 에러 팝업을 띄움</li>
<li>다른 페이지에서 에러가 날 경우: 새로고침 3회 시도</li>
</ol>
</li>
</ul>
<p>이 처리를 나는 componentDidMatch와 render 중 어디에서 처리해야 하는 것일까?</p>
<h2 id="componentdidmatch">componentDidMatch()</h2>
<p>개발자가 사전에 예외처리를 하지 않은 에러가 발생했을 때 이를 캐치하는 메소드이다.
두개의 인자를 받는데, error (state값) 과 그 외 정보값을 받을 수 있다.</p>
<p>render()메소드에서 state값이 true일 경우 에러팝업 등 fallback UI를 보여주어야 하는 것.</p>
<p>내가 하고 싶은 것은 에러가 발생한 것을 캐치하고 새로고침을 시도하는 것이므로 
componentDidMatch에서 로직을 추가해야 했다. </p>
<pre><code class="language-js"> componentDidCatch(error, errorInfo) {
    const {
      location: { pathname, search },
    } = this.props.history

    if (에러 발생) {
      window.location.reload()
    } else if(새로고침 3회) {
      this.render() // or 홈으로이동()
    }

    const errorData = {..}
    console.log(errorData)
  }

 render() {
    if (this.state.hasError) {
        return (
          &lt;AlertModal show={this.state.hasError} {..} &gt;
            오류가 발생하였습니다. 잠시 후 다시 시도해 주세요.
          &lt;AlertModal&gt;
        )
    }
    return this.props.children
  }
</code></pre>
<p>이렇게 되면 에러 발생 시 무한반복 reload가 있게 되고 중간중간 에러팝업이 보일 것이다.</p>
<h4 id="새로고침-3회-이상-여부를-어떻게-검사할-수-있을까">새로고침 3회 이상 여부를 어떻게 검사할 수 있을까?</h4>
<ul>
<li>state로 관리? X
  ErrorBoundary가 새로고침되면 새로 렌더되어 초기화되므로 카운트 업이 불가하다.</li>
<li>url에 querystring을 누적 ✓
  (좋은 방법인지는 모르겠으나) 새로고침횟수를 url에 search param으로 누적시키고, 카운팅 업하고 읽어들여 무한 새로고침을 막을 수 있도록 하였다.</li>
</ul>
<pre><code class="language-js"> componentDidCatch(error, errorInfo) {
    const {
      location: { pathname, search },
    } = this.props.history

    const parsedSearch = qs.parse(search)      

    if (isNil(parsedSearch[&#39;reload&#39;])) {
      const url = qs.stringifyUrl({
        url: pathname,
        query: {
          ...parsedSearch,
          reload: 1,
        },
      })

      window.location.replace(url)
    } else if (toNumber(parsedSearch[&#39;reload&#39;]) &lt; 3) {
      parsedSearch[&#39;reload&#39;] = toNumber(parsedSearch[&#39;reload&#39;]) + 1

      const url = qs.stringifyUrl({
        url: pathname,
        query: {
          ...parsedSearch,
        },
      })

      window.location.replace(url)
    } else {
      this.render()
    }

    const errorData = {..}
    console.log(errorData)
  }

 render() {
    if (this.state.hasError) {
        return (
          &lt;AlertModal show={this.state.hasError} {..} &gt;
            오류가 발생하였습니다. 잠시 후 다시 시도해 주세요.
          &lt;AlertModal&gt;
        )
    }
    return this.props.children
  }
</code></pre>
<p>이 경우 window.location.replace(<code>url</code>) 메소드를 사용했다. 
(useLocation, useHistory의 소중함을 깨달았던..)</p>
<p>새로고침 3회 이후 else 로 빠지게 되어 render()를 호출하게 되면 에러 팝업이 뜨는 상태가 된다.</p>
<h4 id="새로고침-시에는-에러팝업을-보여주고-싶지-않다">새로고침 시에는 에러팝업을 보여주고 싶지 않다.</h4>
<p>새로고침을 시도 하는 사이사이 ErrorBoundary 컴포넌트 렌더링 결과물이 보이게 되었다.
에러팝업을 최대한 보여주고 싶지 않은 것이 목적이었으므로
새로고침을 3회 시도하는 동안 렌더링 결과물이 null 이거나 빈 div가 되도록 수정하였다.</p>
<h3 id="haserror-true">hasError: true</h3>
<pre><code class="language-js">&lt;ErrorBoundary&gt;
    &lt;App /&gt;
&lt;/ErrorBoundary&gt;</code></pre>
<p>App 컴포넌트를 ErrorBoundary로 감싸 호출하고 있으모로 사실 Errorboundary 컴포넌트는 에러발생과 상관없이 항상 호출되고 있는 것이다.</p>
<p>다만 에러가 발생했을 때 componentDidMatch()가 동작하여 hasError state를 업데이트하고, render조건에 걸려 fallback ui를 리턴하게 되는 것이다.(에러가 난 경우에만 팝업이 보이게 되는 것)</p>
<p><strong>에러인 경우에 대해 뭔가 그려주기 위해서는 this.state.hasError가 true인 상태에서 뭔가 해줘야 한다.</strong></p>
<p>그래서 this.state.hasError 조건과 동등한 수준에서 조건을 추가하려면, 컴포넌트 state를 추가해서만 가능할 것이고,</p>
<p>state가 아닌 값으로 조건을 좌우한다면 hasError 분기 하위에서 처리해야 했다.</p>
<pre><code class="language-js">render() {
    if (this.state.hasError) {
      const parsedSearch = qs.parse(window.location.search)

      if (parsedSearch[&#39;reload&#39;] &gt;= 3) {
         return (
          &lt;AlertModal show={this.state.hasError} {..} &gt;
            오류가 발생하였습니다. 잠시 후 다시 시도해 주세요.
          &lt;AlertModal&gt;
        )
      } else {
        return null // 새로고침하는 동안 에러팝업이 보이지 않음
      }
    }
    return this.props.children
  }</code></pre>
<h4 id="홈에서는-이-전쟁을-끝내고-싶어">홈에서는 이 전쟁을 끝내고 싶어..</h4>
<pre><code class="language-js"> componentDidCatch(error, errorInfo) {
    const {
      location: { pathname, search },
    } = this.props.history

    if (pathname === &#39;/&#39;) {
      this.render()
    }

    const parsedSearch = qs.parse(search)      

    if (isNil(parsedSearch[&#39;reload&#39;])) {
      const url = qs.stringifyUrl({
        url: pathname,
        query: {
          ...parsedSearch,
          reload: 1,
        },
      })

      window.location.replace(url)
    } else if (toNumber(parsedSearch[&#39;reload&#39;]) &lt; 3) {
      parsedSearch[&#39;reload&#39;] = toNumber(parsedSearch[&#39;reload&#39;]) + 1

      const url = qs.stringifyUrl({
        url: pathname,
        query: {
          ...parsedSearch,
        },
      })

      window.location.replace(url)
    } else {
      this.render()
    }

    const errorData = {..}
    console.log(errorData)
  }

render() {
    if (this.state.hasError) {

      const isHomePage = window.location.pathname === &#39;/&#39;
      const parsedSearch = qs.parse(window.location.search)

      if (isHomePage || parsedSearch[&#39;reload&#39;] &gt;= 3) {
         return (
          &lt;AlertModal show={this.state.hasError} onConfirm={this.홈으로이동()} {..} &gt;
            알 수 없는 오류가 발생하였습니다. 홈으로 이동하시겠습니까?
          &lt;AlertModal&gt;
        )
      } else {
        return null // 새로고침하는 동안 에러팝업이 보이지 않음
      }
    }
    return this.props.children
  }</code></pre>
<p> 특정 페이지에서 오류가 나 새로고침으로도 해결이 되지 않는다면
온전한 페이지로 유저를 데려다 놓는 게 그나마 상책일 것이다.</p>
<p>그래서 추가로 새로고침 이후 에러팝업에 홈으로 이동하도록 유도하는 팝업을 보여주고,
(홈으로 이동할 때에 hasError state를 업데이트해주어야 에러팝업을 다시 렌더하지 않을 것이다.) </p>
<p>홈화면에서 에러가 날 경우를 처리하기 위해 componentDidMatch에서 pathname을 읽어 빠르게 에러팝업을 렌더하도록 처리했다.</p>
<br/>
<br/>


<h4 id="참고">참고</h4>
<ul>
<li><a href="https://react.vlpt.us/basic/26-componentDidCatch-and-sentry.html">https://react.vlpt.us/basic/26-componentDidCatch-and-sentry.html</a></li>
<li><a href="https://nukw0n-dev.tistory.com/24">https://nukw0n-dev.tistory.com/24</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js] Hydration 에러 핸들링]]></title>
            <link>https://velog.io/@sootulliyang_dev/Next.js-Hydration-%EC%97%90%EB%9F%AC-%ED%95%B8%EB%93%A4%EB%A7%81</link>
            <guid>https://velog.io/@sootulliyang_dev/Next.js-Hydration-%EC%97%90%EB%9F%AC-%ED%95%B8%EB%93%A4%EB%A7%81</guid>
            <pubDate>Fri, 16 Dec 2022 01:55:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>배경
프론트 주니어로서 웹팩, 바벨 등을 직접 셋업해보며 이해를 기르고자 프로젝트를 시작했다.
React18과 Next.js를 사용하고 있고, TypeScript를 엄격히 적용하고자 한다.
config 파일 등으로 필요한 기본 설정 후 페이지를 구성하고 컴포넌트를 하나씩 만들어 가다 보니 빈 페이지에서는 없던 에러가 많이 등장할 것. 에러핸들링을 하며 알게된 것들을 기록하고자 한다.</p>
</blockquote>
<h3 id="hydration-에러">Hydration 에러</h3>
<p>누군가는 Next.js를 처음 사용할 때 window객체가 undefined라는 에러를 본 적이 있을 것이다.
(window는 브라우저가 제공하는 객체이니, 서버사이드 렌더링과 충돌할 수 밖에 없다.)</p>
<p>나의 경우에는 <code>&lt;table/&gt;</code> 객체를 직접 사용하여 hydration 에러가 발생했다.</p>
<pre><code class="language-jsx">Expected server HTML to contain a matching &lt;table&gt; in &lt;div&gt;.</code></pre>
<ul>
<li>thead 태그 속성<pre><code class="language-jsx">(property) JSX.IntrinsicElements.thead: React.DetailedHTMLProps&lt;React.HTMLAttributes&lt;HTMLTableSectionElement&gt;, HTMLTableSectionElement&gt;</code></pre>
</li>
</ul>
<pre><code class="language-jsx">Hydration failed because the initial UI does not match what was rendered on the server.</code></pre>
<h4 id="hydration-이란">hydration 이란?</h4>
<p>서버사이드에서 pre-rendering한 정적페이지와, 번들링(압축)된 javascript코드를 클라이언트에 보내고, 자바스크립트 코드가 정적페이지 (정확히는 html코드를 파싱한 dom tree) 위에 다시 렌더링되면서 매칭되는 과정</p>
<p>즉 위 에러 &#39;initial UI does not match ... on the server.&#39;가 직관적으로 에러를 알려주고 있는 것.</p>
<blockquote>
</blockquote>
<ul>
<li><p>이 에러는 서버사이드에서 pre-rendering된 React DOM-tree와 클라이언트 사이드의 리액트 돔트리와 달라서 발생</p>
</li>
<li><p>컴포넌트가 어떤 조건에서만 리턴(렌더)하도록 했을 때도 같은 오류. (서버에서 렌더링하여 나오는 결과물인 정적페이지 과정까지에서는 브라우저 내장객체를 당연히 참조할 수 없으니까)</p>
<p>  참고: <a href="https://velog.io/@hyeonq/Next.js-Hydration-failed-error">블로그</a></p>
</li>
</ul>
<ul>
<li><p>해결 방법</p>
<p>  ⇒ <font color=red>Next.js의 <strong>dynamic 컴포넌트</strong>를 사용하거나*</font></p>
<p>  ⇒ 클라이언트 사이드 렌더링 시 실행되는 useEffect 안에서 window 객체 참조</p>
  <br/>

<p>  *다만 dynamic 컴포넌트를 사용해도 해당 <font color=brown>컴포넌트 렌더가 두번 되는 이슈가 발생</font></p>
</li>
</ul>
<pre><code>⇒ dynamic 컴포넌트로 import해올 때 **{ SSR: false } 옵션을 설정해야 함
(클라이언트 사이드 렌더링을 한다는 의미)**</code></pre><p>  <font color=grey> *여기에<code>{ suspense: true }</code> 옵션도 함께 설정해야 한다는 의견도 있음</font> <a href="https://github.com/vercel/next.js/discussions/37631">github 🔗</a></p>
<br/>
<br/>

<h3 id="html--dom">#HTML != DOM</h3>
<p>HTML과 DOM의 차이</p>
<ul>
<li><p>HTML은 태그, 속성(attributes)로 구성하는 규칙이 있는 언어</p>
</li>
<li><p>브라우저가 HTML을 파싱하여 DOM tree를 그린다.</p>
</li>
<li><p>DOM(Document Object Model)은 객체모델로, document에 접근이 가능한 API임</p>
<ul>
<li><p>그래서 텍스트, 스타일, 노드 구조도 바꿀 수 있는 것 (getElmentById, innerText.. 등)</p>
</li>
<li><p>document 는 root node의 추상화된 개념인 반면 getElementById, getElementByClassName, parentNode, removeChild와 같은 메소드는 HTML DOM API에서 비롯되었다고 함</p>
</li>
</ul>
<p>참고 블로그: <a href="https://velog.io/@ddinggu/HTML-DOM-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC">https://velog.io/@ddinggu/HTML-DOM-간단-정리</a>, <a href="https://devlibrary00108.tistory.com/46">https://devlibrary00108.tistory.com/46</a></p>
</li>
</ul>
<p>즉 우리가 웹 페이지의 컨텐츠를 동적으로 수정하고 싶으면 DOM을 수정하는 것임</p>
<br/>

<ul>
<li><p>*React.createElement() 메소드로 만들 수 있는 React element는 dom element의 가상버전이라고 보면된다.</p>
</li>
<li><p>React.createClass메소드를 사용하고 state가 있는게 차이점이다.</p>
</li>
<li><p>HTML스러운JSX블럭은 상태값을 가질 수 있는 render메소드를 반환하고 가장 좋은 것은 state가 바뀔때마다 컴포넌트가 다시 그려진다는 점이다.</p>
<p>=&gt; 동적인 HTML디자인의 매우 좋은 도구이고 Components가 가상돔에 직접접근할 수는 없지만 ReactElement로 쉽게 컨버팅해 사용한다.</p>
</li>
</ul>
<ul>
<li>리렌더링 과정: ReactComponent (상태값을 가지고 있어 변화가 일어나면) → ReactElement* 로 컨버팅 → 변화된 부분을 virtual dom 차원에서 확인 → html dom 으로 변환 → DOM에 업데이트 → 브라우저가 최적화</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 프로젝트에서 yarn start 스크립트를 실행하면 무슨 일이 벌어질까?]]></title>
            <link>https://velog.io/@sootulliyang_dev/Next.js-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C-yarn-start-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%8B%A4%ED%96%89%ED%95%98%EB%A9%B4-%EB%AC%B4%EC%8A%A8-%EC%9D%BC%EC%9D%B4-%EB%B2%8C%EC%96%B4%EC%A7%88%EA%B9%8C</link>
            <guid>https://velog.io/@sootulliyang_dev/Next.js-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C-yarn-start-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%A5%BC-%EC%8B%A4%ED%96%89%ED%95%98%EB%A9%B4-%EB%AC%B4%EC%8A%A8-%EC%9D%BC%EC%9D%B4-%EB%B2%8C%EC%96%B4%EC%A7%88%EA%B9%8C</guid>
            <pubDate>Wed, 28 Sep 2022 12:54:21 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<ol>
<li>CSR(Client-side Rendering)이란 무엇이며, 그것의 장단점에 대하여 설명해주세요.</li>
<li>SPA(Single Page Application)로 구성된 웹 앱에서 SSR(Server-side Rendering)이 필요한 이유에 대하여 설명해주세요.</li>
<li>Next.js 프로젝트를 세팅한 뒤 yarn start 스크립트를 실행했을 때 실행되는 코드를 nextjs github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.
<font size=3><a href="https://nextjs.org/docs/getting-started">https://nextjs.org/docs/getting-started</a> (Next.js 세팅 가이드)
<a href="https://github.com/vercel/next.js/">https://github.com/vercel/next.js/</a> (Next.js Github 레포지토리)</font></li>
</ol>
<h3 id="csr이란">CSR이란</h3>
<p>Client Side Rendering, 웹 페이지의 렌더링이 클라이언트 측에서 일어나는 렌더링 방식이다.</p>
<p>내 컴퓨터의 브라우저는 서버에서 html을 받아오고, 자바스크립트 파일을 다운받아 필요한 데이터를 동적으로 (api 호출 등을 통해) 화면을 그려준다. </p>
<p>우리가 웹 페이지를 방문했을 때 첫 화면을 그려주는 일을 클라이언트에 맡기게 되므로 서버가 갖는 부담이 적어진다.
단점으로는, 웹 크롤러는 html을 읽으므로, 데이터가 없는 뼈대 상태의 html에서는 가져올 데이터가 없어 SEO 검색엔진 최적화에는 불리하다.</p>
<p>추가로 보안 관련해서 쿠키에 사용자 정보를 저장한다는 점도 기억할 부분이다.</p>
<p>*우리가 구글 사이트에 검색어를 입력했을 때 나오는 결과물들은, 대개 웹 크롤러가 html을 읽어 검색 가능한 색인을 만들어낸 것이다. 데이터가 없는 html은 색인을 만들 만한 콘텐츠(데이터)가 없을 수 있다.</p>
<h3 id="spa로-구성된-웹앱에서-ssr이-필요한-이유">SPA로 구성된 웹앱에서 SSR이 필요한 이유?</h3>
<p>Server Side Rendering 방식은, 클라이언트(브라우저) 측에서는 유저(사용자인 나)로부터 요청이 들어오면 
(즉 내가 크롬으로 어떤 웹사이트의 페이지에 접속하게 되면,)
서버로부터 이미 데이터를 포함하고 있는 html을 가져와 만들어져 있는 페이지를 화면에 바로 렌더링해 줄 수 있다.
화면 변경이 될 때마다 계속 서버에 html을 요청해야 하니, 서버에 부담이 있는 셈이다.
CSR 방식이 SEO에 불리한 반면, 사용자에게 보여줄 페이지를 서버에서 완전히 구성한 상태로 가져와 보여주기 때문에 유리하다.</p>
<p> Single Page Application는 말 그대로 하나의 &quot;페이지&quot;로 구성된 애플리케이션이다. SPA로 구성된 웹앱에서는 SSR이 어떤 부분에 필요한 것일까?</p>
<p>웹앱 프론트엔드 개발에 많이 사용되는 프레임워크인 리액트로 우리는 동적 웹앱을 만들 수 있다. 즉 내가 장바구니에서 구매할 상품을 선택할 때마다 페이지 전체가 갱신(렌더)되는 것이 아니라, 선택한 상품들의 총합 가격을 나타내는 UI 딱 그 부분만 업데이트시킬 수 있는 것이다. 리액트로 SPA를 개발하면 네이티브 애플리케이션과 같은 사용자 경험을 줄 수 있고, 결과적으로 앱과 웹이 동일한 서버를 이용하는 셈이 된다.</p>
<p>이렇게 부분부분을 동적으로 그려준다면 그만큼 클라이언트에서 다운 받아야하는 자바스크립트 코드의 양이 많은 셈이므로, 최초 로딩 시에 비교적 시간이 오래 걸릴 수 있다.</p>
<p>SSR 방식은 화면에 그려지는 초기 로딩 속도가 빨라 UX측면에서 좋을 수 있기 때문에 <strong>메인 홈페이지 등 첫 화면만 SSR로 적용해볼 수도 있다.</strong> (그러나 그려주기만 할 뿐, 자바스크립트 파일이 다운받아져야 클릭 등의 기능이 실제 동작할 것이다.)</p>
<h3 id="nextjs-프로젝트에서-yarn-start-스크립트를-실행했을-때-실행되는-코드">Next.js 프로젝트에서 yarn start 스크립트를 실행했을 때 실행되는 코드</h3>
<p>리액트로 웹앱 프로젝트를 시작하기는 보다 수월하다. node를 설치하고 노드 버전 관리 툴 nvm, 자바스크립트 패키지나 모듈, 외부 라이브러리 관리 툴인 npm만 인스톨하고 나면 <code>npx create-react-app</code>과 같은 간단한 cli로 웹앱 프로젝트를 시작할 수 있다. (구체적인 설정은 매뉴얼하게 세팅하더라도) </p>
<p>yarn도 npm 과 같이 패키지 매니저 툴이다. 
우리가 node(javascript)로 프로젝트를 개발하면 package.json을 세팅해야 한다. (npx create-react-app 을 하면 자동으로 기본 구성이 세팅된 파일이 생성되는데,)</p>
<p>이 package.json 파일은 무엇인가? 파일 코드를 보면 역시 json 형식의 파일이다.
노드로 만든 프로젝트에 관련된 메타데이터를 지닌 파일이다.</p>
<p>개발자나 (또는 사용자가) 패키지 매니저인 npm을 통해 프로젝트에 필요한 라이브러리, 모듈 등을 설치하고 또 앱을 띄워 실행하는 등의 작업을 허용하기 위한 설명서 같은 것이다. 
(일부 대략적으로 설명하자면 개발할 때 필요한 라이브러리, 이 프로젝트(웹앱)을 사용하기 위해 필요한 라이브러리 등이 devDependencies, dependencies 로 구분된다고 보면 된다) </p>
<blockquote>
<p>노드 공식문서: <a href="https://nodejs.org/en/knowledge/getting-started/npm/what-is-the-file-package-json/">https://nodejs.org/en/knowledge/getting-started/npm/what-is-the-file-package-json/</a></p>
</blockquote>
<p>대개 단위별 프로젝트 최상위(root) 경로에 생성되는데, (MSA 형식인 경우 특정 디렉토리에서 BFF나 API서비스를 띄우는 구조를 가질 수도 있다.) </p>
<p>Next.js 공식 문서에서 next 프로젝트를 구성할 때 수동으로 package.json을 작성하는 예시를 보여주고 있다. &gt;</p>
<pre><code class="language-json">// example
&quot;scripts&quot;: {
  &quot;dev&quot;: &quot;next dev&quot;,
  &quot;build&quot;: &quot;next build&quot;,
  &quot;start&quot;: &quot;next start&quot;,
  &quot;lint&quot;: &quot;next lint&quot;
}</code></pre>
<p>헷갈릴 지점에서 질문의 핵심을 살펴보면, 우리가 Next.js로 만든 프로젝트에서 <code>yarn start</code> 명령어를 입력하면 &quot;next start&quot; 코드의 실행 내용, 자세한 내막이 과연 무엇인지 궁금한 것이다</p>
<blockquote>
<p>nextjs 깃헙저장소: <a href="https://github.com/vercel/next.js/tree/canary/packages/next/cli">https://github.com/vercel/next.js/tree/canary/packages/next/cli</a></p>
</blockquote>
<p>nextjs의 깃헙이다. 이해 편의를 위해 단순한 관점으로 바라보자면 이 nextjs는 우리의 작고 소중한 프로젝트와 다른, (리액트)프레임워크이다. </p>
<p>따라서 최상위 package.json가 우리의 프로젝트의 그것과 다를 수 있는데,</p>
<p>next로 만든 다양한 프로젝트의 package.json 을 책임지는 코드는 packages 에 정의되었지 않을까 예상해볼 수 있다.</p>
<pre><code class="language-js">#!/usr/bin/env node

import arg from &#39;next/dist/compiled/arg/index.js&#39;
import { startServer } from &#39;../server/lib/start-server&#39;
import { getPort, printAndExit } from &#39;../server/lib/utils&#39;
//..
import { cliCommand } from &#39;../lib/commands&#39;

const nextStart: cliCommand = (argv) =&gt; {
  const validArgs: arg.Spec = {
    // Types
    &#39;--help&#39;: Boolean,
    &#39;--port&#39;: Number,
    &#39;--hostname&#39;: String,
    &#39;--keepAliveTimeout&#39;: Number,
    // ..
  }
  let args: arg.Result&lt;arg.Spec&gt;
  try {
    args = arg(validArgs, { argv })
  } catch (error) {
    if (isError(error) &amp;&amp; error.code === &#39;ARG_UNKNOWN_OPTION&#39;) {
      return printAndExit(error.message, 1)
    }
    // ..
  }

  const dir = getProjectDir(args._[0])
  const host = args[&#39;--hostname&#39;] || &#39;0.0.0.0&#39;
  const port = getPort(args)

  // ..
  startServer({
    dir,
    hostname: host,
    port,
    keepAliveTimeout,
  })
    .then(async (app) =&gt; {
      const appUrl = `http://${app.hostname}:${app.port}`
      Log.ready(`started server on ${host}:${app.port}, url: ${appUrl}`)
      await app.prepare()
    })
    .catch((err) =&gt; {
      console.error(err)
      process.exit(1)
    })
}

export { nextStart }</code></pre>
<p>--help 등 cli로 입력하는 옵션들에 대한 실행 내용이 정의되어 있다. 또 host, port 등을 받아 startServer를 실행하는 코드도 보인다. </p>
<p>프로젝트를 하면서 Socket 등 실시간으로 서버와 소통하는 서비스를 만들어 본 경험이 있다면 <code>createServer</code> 메소드를 본 적이 있을 것이다. 위 &quot;startServer&quot; 함수가 선언된 곳을 보면 http모듈의 createServer를 사용하여 정의되어 있다.</p>
<pre><code class="language-js"> let requestHandler: RequestHandler

 const server = http.createServer((req, res) =&gt; {
    return requestHandler(req, res)
 })</code></pre>
<p>나는 리액트로 프론트엔드 개발을 시작했고 지금도 계속 리액트로 개발하고 있는데, 보다 개발이 편리한 것은 맞지만 웹팩 등을 포함해 프로젝트 단위에서 매뉴얼하게 구축해보는 것이 필요하겠다고 생각이 드는 시점이었다.</p>
<p>우리의 콘솔(터미널)에 &#39;started server on localhost:3000, url...&#39; 과 같은 로그를 남겨주는 코드도 이 안에 있는 것이었다!</p>
<p>근본에 대한 탐구가 중요하다는 것을 이 포스트를 마치며 새기게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[로컬에서 github 계정 2개 쓰기]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-github-%EA%B3%84%EC%A0%95-2%EA%B0%9C-%EC%93%B0%EA%B8%B0</link>
            <guid>https://velog.io/@sootulliyang_dev/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-github-%EA%B3%84%EC%A0%95-2%EA%B0%9C-%EC%93%B0%EA%B8%B0</guid>
            <pubDate>Sat, 12 Feb 2022 12:35:52 GMT</pubDate>
            <description><![CDATA[<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-ZC91RM8375"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-ZC91RM8375');
</script>

<p>다른 에디터를 연다고 해서
쉘(터미널)이 다른 것이 아님</p>
<p>회사에서는 WebStorm을 쓰고 있고, github desktop app을 사용하고 있어서 </p>
<p>구분을 위해서 개인 공부나 프로젝트는 vscode로 작업하려고 하는데 </p>
<p>permission denied를 맥이길래</p>
<p>본 김에 정리해보았다.</p>
<p>다른 블로그를 통해서 설정을 했고, 
거기에 추가해서 알면 좋을 사항을 적어본다</p>
<blockquote>
</blockquote>
<ul>
<li>ssh key 생성 및 등록(local config 파일, github setting)</li>
<li>gitconfig user, host 설정</li>
<li>(mac) keychain access</li>
<li>osxkeychain</li>
<li>터미널(shell)</li>
</ul>
<br/>

<h3 id="ssh-key">ssh-key</h3>
<p>github레포지토리 페이지에 들어가면 clone하기 위한 https 주소와 ssh 주소 2가지 타입이 있는 걸 볼 수 있다.
ssh 프로토콜을 이용해서 public key(.pub)를 github에 등록하고, (private은 로컬에서만 지니고 있음) 매번 접속할 때마다 username 이나 password를 입력하지 않아도 되는 접속 방식이다.</p>
<blockquote>
<ol>
<li>ssh key 생성</li>
<li>ssh key 등록 (ssh-agent/로컬)</li>
<li>ssh key github 등록</li>
<li>.ssh config, .gitconfig 설정파일 일치 확인</li>
</ol>
</blockquote>
<p>*github가 제공하는 <a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh">공식 문서</a>를 보는 것이 좋은 것 같다.  <font size=3 color=grey> 키보드도 돌고 돌아 결국 끝판왕을 사게 되는 것처럼.</font></p>
<h4 id="-generate-ssh-key">| generate ssh key</h4>
<p>  (a)  </p>
<pre><code class="language-shell">  ssh-keygen -t ed25519 -C &quot;your_email@example.com&quot;</code></pre>
<pre><code class="language-shell">  ssh-keygen -t rsa -b 4096 -C &quot;your_email@example.com&quot;</code></pre>
<p><font size=3 color=grey> *ed25519, rsa 등은 암호화 알고리즘이다.</font></p>
<br/>

<p>(b) 다음과 같이 ssh key file이 생성된 위치의 경로, 암호파일명을 확인하고 파일명을 수정할 수 있다.</p>
<pre><code class="language-shell">Generating public/private rsa key pair. Enter file in which to save the key (/Users/&lt;yourpc&gt;/.ssh/&lt;id_rsa 커스텀가능_&gt;):</code></pre>
<br/>

<p>(c) password 설정. <font size=3 color=grey>*그냥 return키(⏎)를 치면 빈 값으로 들어간다.</font></p>
<pre><code class="language-shell">Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]</code></pre>
<br/>

<h4 id="-ssh-agent-등록">| ssh-agent 등록</h4>
<p>(d) ssh-agent 등록</p>
<pre><code class="language-shell">  ssh-add -K ~/.ssh/id_rsa_어쩌구</code></pre>
<p><font size=3 color=grey>* <code>-K</code> 와 같은 옵션은 ssh-agent에 ssh key에 대한 암호(passphrase) 입력 여부와 관련된 플래그이다.</font></p>
<br/>

<p>(e) 회사 계정, 개인 계정 등 멀티 account를 쓰고 싶다면 (a)~(d) 과정을 각각 2번 진행</p>
<br/>

<h4 id="-github-ssh-key-등록">| github ssh key 등록</h4>
<p>github 각 계정 settings &gt; ssh key 항목에서 public key를 복사&amp;붙여넣어 등록한다.</p>
<br/>

<h4 id="-config-설정">| config 설정</h4>
<p>(g) <code>~/.ssh/config</code> 설정
config는 configuration, 설정 파일이며 없으면 touch 등 명령어로 생성하면 된다.
nano 커맨드로 config 내용을 편집 가능하다.</p>
<pre><code class="language-shell">#company
Host company-github.com *로컬에서 git init 후 remote 레포지토리 연결 시 ssh 주소를 이렇게 바꾸어야 함
HostName github.com
User git
  AddKeysToAgent yes
  UseKeychain yes  *이 옵션을 삭제하면 터미널에서 push할 경우 등에서 암호 입력을 요구하지 않음
  IdentityFile ~/.ssh/id_ed25519

#personal
Host personal-github.com
HostName github.com 
User git *로컬에서 git init 후 remote 레포지토리 연결 시 ssh 주소를 이렇게 바꾸어야 함
  IdentityFile ~/.ssh/id_personal</code></pre>
<p><font size=3 color=grey>*참고로 <code>~/.ssh</code> 는 숨겨진 디렉토리로 최상위 루트에 존재함</font></p>
<br/>

<p>(g) <code>~/.gitconfig</code> 설정</p>
<pre><code class="language-shell">[user]
    name = &lt;username아무거나&gt;
    email = &lt;github계정 이메일&gt;</code></pre>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/83290e73-d2fe-4bdf-903a-1dc43feb9615/%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%202022-02-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.35.10.png" alt=""></p>
<p>ssh 주소를 보면 <code>User@HostName:user.name/repositoryName.git</code> 의 형식을 이루고 있다</p>
<br/>

<h4 id="-ssh-키가-등록되었는지-확인">| ssh 키가 등록되었는지 확인</h4>
<p><code>ssh-add -T ~/.ssh/암호키파일명</code>를 입력하면 터미널에</p>
<pre><code class="language-shell">Hi username! You&#39;ve successfully authenticated, but GitHub does not provide shell access.</code></pre>
<p>이런 응답을 볼 수 있다면 등록된 것, 하지만 shell access는 없다..!
(<code>-T</code> 플래그가 terminal access를 제외한다는 옵션이었다..)</p>
<br/>


<h4 id="-error">| Error</h4>
<p>(에디터별로 계정 연결은 할 수 있으나, 터미널은 별개임을)</p>
<p>에러 확인:</p>
<pre><code class="language-shell">ERROR: Permission to userA.name/test.git denied to userB.name.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.</code></pre>
<p>로컬에서 작업 후 push 시 이런 에러를 발견했다면, 계정 간 충돌이 일어난 것이다.
회사계정-개인계정 간 크로스로 commit 및 push를 해도 상관 없다면 ssh-key를 하나씩 더 만들어 서로 추가해도 될 것이다.</p>
<p>.gitconfig-personal 등 개별 설정파일을 생성하여 global config 파일에 명시해주는 방법도 있다. 
(참고 🔗 <a href="https://yosuniiiii.com/github-%EA%B3%84%EC%A0%95-%EC%97%AC%EB%9F%AC%EA%B0%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-on-mac-6588237f9671">블로그</a>)</p>
<p>결론적으로 본인은 회사업무는 github desktop app 에 로그인 고정되어 있으니 그걸로 작업하고, 로컬에서는 shell cli를 사용하려 했는데</p>
<p>로컬 global이 회사 계정으로 되어 있는 듯하다 ..^^ 
.
.
.
to be continued..</p>
<br/>


<h2 id="🌞">🌞</h2>
<br/>

<h4 id="-ssh-접속">| ssh 접속</h4>
<p>ssh public key를 접근할 서버(github, gitlab, bigbucket)에 등록하여 인증하는 방법은 비밀번호 입력없이 로그인 하는 방법으로 많이 사용되며, 이 서비스들은 <strong>ssh 프로토콜에서 모두 같은 ID(git)로 접속하되</strong> 공개키를 다르게 하여 실제 사용자를 구별한다.</p>
<p>ssh로 해당서비스를 접근할 때 사용자 이름을 git 으로 하면, 서비스에 가입한 ID를 화면에 출력하고 <strong>바로 접속을 끊는다.</strong></p>
<p>아!</p>
<pre><code class="language-shell">Hi JIYEONGYANGdev! You&#39;ve successfully authenticated, but GitHub does not provide shell access.</code></pre>
<p>요 문구 나오는 게 정상이구나.</p>
<p>참고🔗 <a href="https://coolengineer.com/entry/ssh-access-git-repository">블로그</a></p>
<br/>
회사 계정은 webstorm을 스니
sourcetree로 vscode를 쓰고, 개인 레포지토리를 쓰기 위해 sourcetree 로 다시 접근해봤다.(GUI를 쓰면 알아서 해주지 않을까라는 생각에..)

<p>sourcetree에 개인 계정 연결을 했고, sourcetree 가 생성해준 public key (<code>~/.ssh/config</code>에도 자동 등록해줌) 를 해당 github계정에 등록해주었지만</p>
<p>gui를 통해 remote repository를 만드는 것에는 자꾸 실패했다.
error message was :
<code>message: You need at least read:org scope or user scope to list your organizations.</code></p>
<p>계정 소유자를 불러오는 데 실패했다고 한다..</p>
<br/>

<h3 id="-credentialshelper-keychain">| credentials.helper (keychain)</h3>
<p>본인은 mac Pro M1을 사용 중이고, mac os는 인증정보를 keychain access 에 저장한다.</p>
<p>ssh key 같은 경우 또한 git에서 매번 유저 계정을 확인(password입력, 계정정보 주소별로 cli입력 등)하는 번거로움이 없도록 인증정보를 저장하는 것이다.</p>
<p>참고🔗 <a href="https://director-joe.kr/78">블로그</a></p>
<p>공식문서🔗 <a href="https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage">credential storage- custom</a></p>
<br/>

<p>push, pull 등 어떤 key를 사용했는지 확인해보자</p>
<p>참고🔗 <a href="https://www.lesstif.com/gitbook/ssh-config-ssh-key-20776092.html">블로그</a></p>
<br/>

<h3 id="-conditional-inlcude로-특정-디렉토리만의gitconfig-설정">| conditional inlcude로 특정 디렉토리만의<code>.gitconfig</code> 설정</h3>
<p>두번째 결론아닌 결론은</p>
<p>github desktop app 과 같은 GUI를 이용해서 local repository 마다 계정을 정해주는 게 보다 명확할 것 같다.</p>
<p>.gitconfig (Global)에 글로벌 계정을 설정해두고,
.gitconfig-personal 등 다른 gitconfig를 볼 수 있도록 includesIf 등의 옵션을 global .gitconfig 파일에 명시해두면 될 것 같다.</p>
<p>본인은 헷갈려서 결국 
개인 git 계정을 터미널에서 사용하도록 global 로 개인계정을 global로 설정해두었고,</p>
<p>gui(github desktop app)로 회사계정을 쓰기로 했다..^^</p>
<blockquote>
<ol>
<li>로컬 디렉토리 를 나누어 gitconfig를 관리</li>
<li>global .gitconfig 설정하고, 
  개별 계정을 [includeIf] 옵션? 으로 추가함</li>
<li>conditional setting option 추가
글로벌 <code>.gitconfig</code> 파일 내용에</li>
</ol>
</blockquote>
<pre><code class="language-shell">[includeIf &quot;gitdir:~/상위디렉토리/개별계정설정하고싶은디렉토리/&quot;]
   path = ~/상위디렉토리/개별계정설정하고싶은디렉토리/디렉토리명.inc</code></pre>
<p>추가</p>
<p>*<code>gitdir:</code> 은 glob 패턴을 따르는 문자열로, git directory 가 해당 패턴과 일치하면, path에 있는 파일을 include 한다.
<code>.gitconfig</code> 파일은 하위 디렉토리의 설정이 글로벌을 덮어쓰기 때문에 해당 경로의 파일에 특정 계정(user email, name) 설정해두면 덮어쓰여져 해당 설정을 사용하게 될 것이다.</p>
<p>여기까지 설정하여 각 디렉토리에서
<code>git config --get user.email</code> 를 입력하여 출력된 이메일이 알맞게 적용되어 있는지 확인할 수 있었다.</p>
<p>나는 터미널 각 디렉토리에서 다른 github 계정, 레포지토리를 쓰고 싶었던 것이라 이 config conditional 세팅이 필요했고,</p>
<p>gui 나 ssh 접속은 또 따로 확인해줘야할 것이다.</p>
<p>참고🔗 <a href="https://til.younho9.dev/log/2021/gitconfig-conditional-include/">블로그</a></p>
<br/>

<h3 id="성공하다">성공하다</h3>
<p>여전히 터미널에서 git ssh접속이 원하는 계정으로 되지 않았다.</p>
<p><strong>| credentials.helper, osxkeychain..</strong>
github.com 에 대한 keychain 이 등록되어 있었다. 회사계정의 access token이 등록되어 있었고, 이 때문에 ssh key가 먹히지 않은 건지는 확신할 수 없으나, 우선 github.com에 대한 키체인과 github 에서 access token을 삭제했다.</p>
<p>[참고] credentials.helper config 관련 <a href="https://confluence.atlassian.com/bitbucketserver078/permanently-authenticating-with-git-repositories-1037993924.html">🔗링크</a> </p>
<p>[참고] <a href="https://ccambo.blogspot.com/2020/12/git-macos-githubcom.html">https://ccambo.blogspot.com/2020/12/git-macos-githubcom.html</a></p>
<p>찾아본 바로 ssh key 로 접속하기 때문에 access token이 반드시 필요한 것 같지는 않았는데, 더 확인이 필요.
keychain 은 2개 이상 등록할 수 없을까? </p>
<p><strong>| remote url 을 정확히 분리하여 입력</strong>
~./ssh config 에 host를 회사, 개인 계정용 다르게 등록하고 
이를 remote url을 그에 맞게 수정해야 한다.
<img src="https://images.velog.io/images/sootulliyang_dev/post/f774d178-78a9-4283-bcaf-f89e400bc7fa/%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%202022-02-27%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.51.36.png" alt=""> 캡처에 표시한 형광 연두색 박스는 ssh config에 등록한 <strong><strong>Host</strong></strong> 이다.</p>
<br/>

<p>정리하자면,</p>
<ol start="0">
<li>github.com 에 대한 키체인 확인 &amp; 삭제
깃헙에서 access token 삭제
<FONT SIZE=3.5>*(이 계정만으로 쓸 것이 아니라 난 그렇게 진행해보았다. 두 계정에 각각의 ssh 키로 접속을 할 것이므로)</FONT></li>
<li>ssh-key 생성</li>
<li>등록 (<code>ssh-add --apple-use-keychain ~/.ssh/&lt;personal_key_file_name&gt;</code>)</li>
<li>~./ssh config 설정 (host, hostName, ssh key path..)</li>
<li><em>remote url 알맞게 등록</em> *!</li>
</ol>
<ul>
<li>git config 도 설정</li>
</ul>
<p>개인 계정으로 리모트 repo에 push 하고 싶어서 다시 찾아보고 해결을 시도하게 되었다.
2일 전 커밋을 오늘 push 해냈다.</p>
<p>*회사 계정 개인 레포지토리 push나 clone 등의 경우도 
예를 들어
내 repository의 ssh 주소를 복사해서 ssh config host 에 맞게
<code>github.com-company:JIYEONGYANGdev/~repository.git</code> 등 주소로 수정해서 remote url을 등록해야 함!</p>
<p>=&gt; 근데 또 이번엔 개인 계정으로 회사계정에 커밋을 한 셈이 됨</p>
<p>to be continued...
<br/></p>
<h3 id="결론-헷갈리면-다시-한번-config-등록">결론 헷갈리면 다시 한번 config 등록</h3>
<p>터미널에서 나의 개인 레포지토리에 push 되는 걸 확인하고 나서
회사 계정을 등록한 디렉토리로 옮겨가 테스트 레포를 clone 후 수정,commit, push 진행해보았을 때 또 개인계정으로 Push가 되었었다.</p>
<ol>
<li><code>ssh-add --apple-use-keychain ~/.ssh/&lt;personal_key_file_name&gt;</code> 
<font size=3 color=grey>(해도되고 안해도 되고.. 그냥 해봤다)</font></li>
<li>(터미널) 해당 디렉토리에서 <code>git config --get user.email</code> 커맨드 입력으로 내가 의도한 git 계정이 맞는지 확인</li>
<li>다른 계정이라면 다시 한번 등록 해준다 (전역x 옵션 <del>--global</del> 제외) 
<code>git config user.email &lt;내가의도한계정이메일&gt;</code></li>
</ol>
<p>결론적으론, 계정을 옮겨다닐 때(터미널 상에서 속한 계정이 다른 디렉토리로 이동할 때)는 해당 디렉토리에서 다시 한번 git 계정을 확인하는 것이 좋겠다!</p>
<p>적어도 ssh key를 크로스로 등록하거나, git config 상 host 등을 제대로 구분했다면
회사 레포지토리에는 개인 계정으로 Push될 일이 없도록 할 수 있을 것.</p>
<br/>


<p>[참고] 관련 <a href="https://velog.io/@yund_272/Mac%EC%97%90%EC%84%9C-Git-token-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0">🔗링크1</a> <a href="https://meaownworld.tistory.com/78">🔗링크2</a> <a href="https://stackoverflow.com/questions/24275375/how-can-i-store-keychain-credentials-for-multiple-github-accounts">🔗링크3</a></p>
<p><img src="https://notion-ga.ohwhos.now.sh/collect?tid=G-ZC91RM8375&host=velog.io&page=/@sootulliyang_dev/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-github-%EA%B3%84%EC%A0%95-2%EA%B0%9C-%EC%93%B0%EA%B8%B0" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TWIL : useEffect 가이드]]></title>
            <link>https://velog.io/@sootulliyang_dev/TWIL2022-01-30-2022-02-02-useEffect-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@sootulliyang_dev/TWIL2022-01-30-2022-02-02-useEffect-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Sun, 06 Feb 2022 11:38:19 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 key point</p>
<ul>
<li>리액트에 effect hook을 구분하게 하기</li>
<li>dependency를 거짓말하지 않기</li>
</ul>
</blockquote>
<br/>

<h4 id="✧-동기화">✧ 동기화</h4>
<p>클래스형의 lifecycle 중심 사고를 벗어나야 한다. 함수형에서는 동기화 synchronization 이다. 렌더링된 컴포넌트가 그 순간의 prop, state 를 잡고 있다.(&#39;보고 있다&#39;)</p>
<p>따라서 함수형에서 useEffect hook 내 로직으로 &#39;최초로 mount된 경우&#39;와 &#39;아닌 경우&#39;가 다르게 작동하는 코드를 작성하는 것은 거의 불가하다고 봐야한다. </p>
<p><font size=3 color=grey>(카카오 소셜로그인 뒤로가기 이슈 관련하여 작업해보면서 내가 제자리 걸음하는 것이라 느끼긴 했다. 먼저 공부하고 새로운 시각을 찾는 것도 중요함을 깨달음.)</font></p>
<br/>

<h4 id="✧-그렇다면-useeffect를-비교하는-방법이-있을까">✧ 그렇다면 useEffect를 비교하는 방법이 있을까?</h4>
<ol>
<li>flag(state 값) 걸기</li>
<li>의존성 배열 dependency array 에 거짓말하지 않기
dependency에 걸린 상수나 string 값을 가지는 변수는 <strong>렌더링된 그 순간의 상수, string 등의 원시값</strong>인 셈이다. <em>&#39;means constant or string value&#39;, 리액트는 렌더링된 컴포넌트 그 순간의 값을 &#39;보는&#39; 것</em>
<img src="https://images.velog.io/images/sootulliyang_dev/post/6513734c-e41d-45c8-8d2a-893b862a3207/deps-compare-correct.gif" alt="">
 • effect가 self-sufficient하게 만들기
 • dependency가 없도록 만드는 방법: callback형태 만들기, useReducer</li>
</ol>
<br/>

<h4 id="✧-무엇을-언제-clean-up">✧ 무엇을 언제 clean up?</h4>
<p>   cleanup: 새 prop을 본(observe) 다음에 이전prop을 cleanup한다.</p>
<h4 id="✧-prop이나-다른-state와-연산이-있는-state가-dependency에-걸려있다면">✧ prop이나 다른 state와 연산이 있는 state가 dependency에 걸려있다면?</h4>
<h4 id="✧-action과-update-분리하기">✧ action과 update 분리하기</h4>
<br/>

<p>참고 🔗 <a href="https://overreacted.io/a-complete-guide-to-useeffect/">A complete guide to useEffect</a></p>
<p><img src="https://notion-ga.ohwhos.now.sh/collect?tid=G-ZC91RM8375&host=velog.io&page=/@sootulliyang_dev/TWIL2022-01-30-2022-02-02-useEffect-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL : history]]></title>
            <link>https://velog.io/@sootulliyang_dev/TIL-2022-01-20-history</link>
            <guid>https://velog.io/@sootulliyang_dev/TIL-2022-01-20-history</guid>
            <pubDate>Sun, 06 Feb 2022 11:37:38 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 key point</p>
<ul>
<li>history.replace(<code>&#39;/path&#39;</code>)</li>
<li>window 브라우저와 react-router-dom의 history, location</li>
<li>onpopstate? bfc(backforward cache)?</li>
</ul>
</blockquote>
<br/>

<h4 id="✧-로그인-후-뒤로가기-막기-with-react-javascript">✧ 로그인 후 뒤로가기 막기 (with React, javascript..)</h4>
<p>push는 히스토리 스택을 쌓는다, &#39;stack&#39;이므로 방금 들어온 것이 먼저 나갈 수 있다.
replace는 가장 최근의 스택을 갈아치우면서 그 path로 이동한다.</p>
<p>만약 <code>메인페이지</code>에서 <code>로그인페이지</code>로 이동하고, 로그인 시 <code>마이페이지</code>로 리다이렉트되도록 라우팅 구조를 설계했다면,
로그인 완료(성공) 후 랜딩한 마이페이지에서 뒤로가면 <code>로그인페이지</code>가 나온다, 그럼 또 다시 <code>마이페이지</code>로 리다이렉트된다,
이러한 동일한 페이지의 연속적인 중복 노출 현상을 막기 위해 history.replace를 쓸 수 있다.
(물론 라우팅 구조가 복잡한 큰 규모의 앱이라면 단순한 문제가 아니다)</p>
<pre><code class="language-js">history.replace(&#39;/path&#39;)</code></pre>
<pre><code class="language-js">history.replace({
  pathname: &#39;/path&#39;,
  state: {
    ..location.state,
    redirect: &#39;/somewhere&#39;
    },
})</code></pre>
<p>그리고 소셜로그인인 경우 oauth나 bridge 페이지가 스택에 쌓여 히스토리 스택을 replace처리하는 데 한계가 있다. 
+서치하던 중 react-router-dom 의 버전 6 이상의 경우 <code>navigate</code> 기능이 추가되었다고 해서 좀 더 찾아보는 중. 현재 개발 중인 앱은 버전 5라서 적용해보지 못했다.
시중 다양한 서비스를 봐도 로그인 후 뒤로가기를 하면 로그인 화면이 노출되는 경우는 많은 것 같다. 사용자 경험에 있어 크리티컬하지 않다고 판단되어서일 수 도.</p>
<p><font size=3 color=grey>*아이폰의 경우 스와이프 시 onpopstate 이벤트가 일어나지 않고 이전 상태의 뷰만 보이는 경우가 있는 걸 발견했다. 웹뷰 앱임에도 .. ? 이건 ios를 공부해봐야할 것 같음.</font></p>
<h4 id="✧-뒤로가기-액션으로-모달-창만-닫기">✧ 뒤로가기 액션으로 모달 창&#39;만&#39; 닫기</h4>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/f6fc292b-be27-4f87-9593-60e2b043e922/%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%202022-02-06%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.05.37.png" alt=""></p>
<br/>

<p>참고</p>
<ul>
<li>replaceState, pushState 는 주소만 바꾸어주고 이벤트는 일어나지 않는다.</li>
<li>🔗 <a href="https://velog.io/@bclef25/%EC%9B%B9%EC%97%90%EC%84%9C-%EB%92%A4%EB%A1%9C%EA%B0%80%EA%B8%B0%EB%A5%BC-%EB%A7%89%EA%B3%A0-%EB%AA%A8%EB%8B%AC%EC%9D%84-%ED%81%B4%EB%A1%9C%EC%A6%88-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-%EC%9C%84%ED%95%9C-%EB%B0%A9%EB%B2%95">웹에서 뒤로가기를 막고 모달을 클로즈 처리하기 위한 방법</a></li>
</ul>
<p><img src="https://notion-ga.ohwhos.now.sh/collect?tid=G-ZC91RM8375&host=velog.io&page=/@sootulliyang_dev/TIL-2022-01-20-history" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST API]]></title>
            <link>https://velog.io/@sootulliyang_dev/REST-API</link>
            <guid>https://velog.io/@sootulliyang_dev/REST-API</guid>
            <pubDate>Mon, 04 Oct 2021 02:46:36 GMT</pubDate>
            <description><![CDATA[<p>Keyword &amp; overview</p>
<ul>
<li><strong>What is &#39;Representation&#39; in REST API?</strong>
http 표현 헤더를 생각해보면, 요청/응답 되는 메시지(리소스/데이터) 의 데이터형식 등이 담겨 있음. 그 &#39;표현&#39; (= representation) 이란?
<font color=grey size=3> [원문] ... REST <strong>uses various representations to represent a resource</strong> where Text, JSON, XML. The most popular representations of resources are XML and JSON.</font>
  예시(request-response)</li>
</ul>
<pre><code class="language-json">    //요청메시지
        GET https://example.org/greeting
        Host: example.org
        Accept: text/plain, text/html; q=0.9 *; q=0.1
        Accept-Language: en, ko; q=0.9, *; q=0.1</code></pre>
<pre><code class="language-json">    //응답메시지
        HTTP/1.1 200 OK
        Content-Length: 6
        Date: Sun, 19 Mar 2017 10:20:47 GMT
        Last-Modified: Sun, 19 Mar 2017 08:00:00 GMT
        Content-Type: text/plain
        Content-Language: en

        hello World // body(본문)</code></pre>
<ul>
<li><p>서버가 전송해준 응답(body)은 사실 리소스가 아님. representation data이다.</p>
</li>
<li><p>GET 메서드 정의: The GET method requests <strong>transfer of a current selected representation for the target resource</strong>.
URI가 가리키는 타깃 리소스 대한 특정 시점의 상태를 반영하고 있는 정보를 응답</p>
</li>
<li><p>응답 메시지 body(본문)이 &quot;hello world&quot;라는 text라면 이건 representaion data.
표현 헤더에 <code>&quot;Content-Type: text/plain&quot;</code> 와 같은 → representation <strong>meta</strong>data
🔗  참고 <a href="https://blog.npcode.com/2017/04/03/rest%EC%9D%98-representation%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80/">블로그(2017)</a></p>
</li>
<li><p>이러한 representational data는 선택되는 것 (사전 협상- <code>&#39;Accept-Language: ko&#39;</code> 과 같 헤더를 포함시켜 GET요청을 보낸다면, 서버가 한국어로 된 적절한 representation data를 응답으로 전송</p>
</li>
<li><p>URI가 동일하다면 같은리소스이다. 여러 리소스 중 하나가 선택된 것이 아님</p>
<ul>
<li>이 representation은 REST에서 온 것. Representational State Transfer 의미를 살펴보면 웹 앱의 <em>상태를 전송</em> 한다는 것  </li>
</ul>
</li>
<li><p>transfer: network component 간 전송</p>
</li>
</ul>
<p>주의) state라는 동일한 단어로 표현하지만, 웹앱의 상태와 리소스의 상태는 다름. 웹앱 상태는 페이지A를 렌더링하다가 B를 렌더링하는 것으로 바뀐 그 상태</p>
<blockquote>
<p><strong>URI vs URL</strong>
-URI(uniform resource identifier)는 네트워크 상 리소스의 위치를 알려주기 위한 규약? *인터넷 프로토콜 관련
-URL(uniform resource locator)는 인터넷에 있는 리소스의 유일한 주소? URI가 상위 개념, URL이 포함된다고 보면 됨</p>
</blockquote>
<ul>
<li><p>좋은 예인지는 모르겠지만: 
<a href="https://example.com/one?id=123">https://example.com/one?id=123</a> 의 경우 URL은 <a href="https://example.com/one">https://example.com/one</a> 까지이고, 내가 원하는 정보에 도달하기 위해서는 <code>?id=123</code>이라는 식별자가 필요한 것.  이 또한 URI이지만 URL은 아닌것.</p>
</li>
<li><p><strong>semantic 의미론적</strong></p>
<p>  이름에서 &#39;역할&#39;을 유추할 수 있는 명명 형식.</p>
<p>  그냥 <div> tag를 쓰기보다는 <section> tag로 쓴다든지 </p>
</li>
<li><p><strong>retrieve 검색하다</strong></p>
<p>  API란 앱의 소프트웨어를 구성하고 통합하기 위한 프로토콜 및 정의들의 모이다.</p>
<p>  정보 제공자와 사용자 간의 정보를 주고받는(요청-응답) 계약으로도 볼 수 있고.</p>
<p>  예를 들어 날씨 서비스의 경우 사용자는 zipcode를 요청에 보내고 제공자는 최고기온, 최저기온 으로 응답을 전송할 수 있다. </p>
<p>  정보를 검색하거나 어떤 기능을 수행하기 위해 컴퓨터나 시스템과 커뮤니케이션이 필요할 때 API가 그 기준이 되어 토대로 요청을 이해하고 충족하는 응답을 전송시켜줄 것이다.</p>
</li>
</ul>
  <br>
  </br>


<h3 id="restful-한-api-란">RESTful 한 API 란?</h3>
<ul>
<li>클라이언트-서버 구조(클라이언트, 서버, 리소스로 구성된)에서, http를 통해 요청 및 응답 전송</li>
<li>&#39;무상태성 Stateless&#39; 서버에 클라이언트 상의 정보 state가 저장되면 안되며, 각 요청은 독립적임</li>
<li>클라이언트가 응답을 캐싱할 수 있어야 함</li>
<li>컴포넌트 간 일관된 인터페이스. 정보가 일관된 형식으로 전송되어야 함<ul>
<li>요청된 리소스는 개별적으로 식별가능해야 하며, 클라이언트에 전달된 표현데이터와 분리되어야 함</li>
<li>표현데이터만으로도 클라이언트 상에서 리소스를 조작가능하다. 표현데이터가 리소스를 다루는 정보를 충분히 포함하고 있음.</li>
</ul>
</li>
<li>서버의 계층구조는 클라이언트 측에서 알 수 없음.</li>
</ul>
<h3 id="why-use-url-parameters-over-request-body-in-api">Why use URL parameters over request body in API?</h3>
<ul>
<li><p>url 파라미터와 body 파라미터는 서로 다른 목적으로 사용</p>
</li>
<li><p>GET 메서드는 데이터를 검색(조회)해 오고(retrieve back) 싶을 때 쓰는 메소드로. 데이터 레코드를 변경하지 않음, 그러므로 body parameter를 passing하지 않는다.
<font size=3 color=grey> 원문(스택오버플로우) The GET method will not pass body parameter and hence whatever filter parameters passed to API will be through URL parameters.</font></p>
</li>
<li><p>정보를 변경(update)하는 목적: POST나 PUT 메서드 사용, parameter 값은 ? input이 없거나 single parameter 가 될 수 있다.</p>
</li>
</ul>
<blockquote>
<p>🤔  고민해볼 주제들..</p>
</blockquote>
<ul>
<li>What are the best practices: args in query string vs in request body vs url path</li>
</ul>
<ol>
<li><p>In the request body - As part of a json body, or other MIME type</p>
</li>
<li><p>In the query string - e.g. <code>/api/resource?p1=v1&amp;p2=v2</code></p>
</li>
<li><p>As part of the URL-path - e.g. <code>/api/resource/v1/v2</code></p>
<p>⇒  Path Variable과 Query Parameter를 각각 언제 사용해야 하는가? </p>
<p>만약 어떤 <strong>resource를 식별</strong>하고 싶으면 <strong>Path Variable</strong>을 사용하고, <code>// (a)</code></p>
</li>
</ol>
<p><strong>정렬이나 필터링</strong>을 한다면 <strong>Query Parameter</strong>를 사용하는 것이 Best Practice이다. <code>// (b)</code></p>
<pre><code class="language-json">/users  # 사용자 목록을 가져온다.
/users?occupation=programer  # 프로그래머인 사용자 목록을 가져온다.  // (b)
/users/123  # 아이디가 123인 사용자를 가져온다.  // (a)</code></pre>
<p><em>기본적인 CRUD 기능을 위해서, 또 다른 URL이나 query parameter를 정의할 필요는 없음! 대신 원하는 *</em>기능에 맞게 HTTP 메소드를 바꾸어** 사용하면 됨!</p>
<pre><code class="language-json">/users [GET] # 사용자 목록을 가져온다.
/users [POST] # 새로운 사용자를 생성한다.
/users/123 [PUT] # 사용자를 갱신한다.
/users/123 [DELETE] # 사용자를 삭제한다.</code></pre>
<p>거의 모든 CRUD 프로세스를 추가적인 endpoint(예를 들어 <code>users/create</code>) 또는 query parameter(예를 들어 <code>users?action=create</code>) 없이 수행할 수 있는 것임. 메서드의 구분으로 단순화되고, 예측이 가능하다.</p>
<p>참고 <a href="https://ryan-han.com/post/translated/pathvariable_queryparam/">🔗 <u>블로그</u></a>  <a href="https://medium.com/@fullsour/when-should-you-use-path-variable-and-query-parameter-a346790e8a6d">🔗 <u>원문</u></a></p>
  <br>
  </br>

<h4 id="읽어볼-자료">읽어볼 자료</h4>
<ul>
<li><a href="https://blog.restcase.com/5-basic-rest-api-design-guidelines/">5 Basic REST API Design Guidelines</a></li>
<li><a href="https://yuda.dev/250">REST API 파라미터 종류 및 개요</a></li>
<li><a href="http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api">Best Practices for Designing a Pragmatic RESTful API</a></li>
<li><a href="https://hackernoon.com/restful-api-designing-guidelines-the-best-practices-60e1d954e7c9">RESTful API Designing guidelines — The best practices</a></li>
<li><a href="https://phauer.com/2015/restful-api-design-best-practices/">RESTful API Design. Best Practices in a Nutshell</a></li>
</ul>
<br>
</br>


<hr>
<p>본문</p>
<h2 id="rest">REST</h2>
<h3 id="1-rest-란">1. REST 란?</h3>
<p><strong>Representational State Transfer</strong>  🔗  <a href="https://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_constraints">Wikipedia</a></p>
<p>www 개발 및 설계를 위한 <strong>소프트웨어 아키텍처</strong>이다. </p>
<p><strong>웹</strong>과 같은 Internet-scale <strong>distributed</strong> hypermedia system의 아키텍처가 어떻게 (behave)해야하는지 <strong>제약조건들의 모음</strong>이다.</p>
<ul>
<li><p>자세히</p>
<p>  컴포넌트 간 상호작용의 확장성, uniform 인터페이스, 컴포넌트의 독립적 배포<del>(재사용성?)</del> 을 강조하는 형식임, 층층이 레이어된 구조를 생성하고, <strong>캐싱을 활용</strong>함으로써 사용자가 느끼는 latency를 감소하고 보안을 강화 + encapsulate legacy system</p>
</li>
<li><p>엄격한 의미로 REST는 네트워크 아키텍처 원리의 모음이다. 여기서 &#39;네트워크 아키텍처 원리&#39;란 <strong>리소스를 정의하고 리소스에 대한 주소를 지정하는 방법</strong> 전반을 일컫는다.</p>
</li>
<li><p>간단한 의미로는, 웹 상의 자료를 HTTP위에서 SOAP이나 <strong>쿠키를 통한 세션 트랙킹 같은 별도의 전송 계층 없이 전송하기 위한 아주 간단한 인터페이스</strong>를 말한다.</p>
</li>
</ul>
<p>REST원리를 따르는 시스템을 RESTful하다고 말한다.</p>
<h4 id="rest의-주요-목표"><strong>REST의 주요 목표</strong></h4>
<ul>
<li>구성 요소 상호작용의 규모 확장성(scalability of component interactions)</li>
<li>인터페이스의 범용성 (Generality of interfaces)</li>
<li>구성 요소의 독립적인 배포(Independent deployment of components)</li>
<li>중간적 구성요소를 이용해 응답 지연 감소, 보안을 강화, 레거시 시스템을 인캡슐레이션 (Intermediary components to reduce latency, enforce security and encapsulate legacy systems)</li>
</ul>
<h4 id="6가지-제약-조건-architectural-constraints"><strong>6가지 제약 조건 (Architectural constraints)</strong></h4>
<p>When these constraints are applied to the system architecture, it gains desirable <a href="https://en.wikipedia.org/wiki/Non-functional_requirement">non-functional properties</a>, such as performance, scalability, simplicity, modifiability, visibility, portability, and reliability. A system that complies with some or all of these constraints is loosely referred to as <strong><em>RESTful</em></strong></p>
<ul>
<li><strong>Client-Server architecture</strong> : 아키텍처를 단순화시키고 작은 단위로 분리(decouple)함으로써 클라이언트-서버의 각 파트가 독립적으로 개선될 수 있도록 해준다.</li>
<li><strong>Statelessness</strong> : 각 요청 간 클라이언트의 콘텍스트가 서버에 저장되어서는 안 된다.(무상태성)</li>
<li><strong>Cacheability</strong>: www에서와 같이 클라이언트는 응답을 캐싱할 수 있어야 한다.
❇︎<em>잘 관리되는 캐싱은 클라이언트-서버 간 상호작용을 부분적으로 또는 완전하게 제거하여 scalability(확장성)와 성능을 향상</em>시킨다.</li>
<li><strong>Layered system</strong> : 클라이언트는 보통 대상 서버에 직접 연결되었는지, 또는 중간 서버를 통해 연결되었는지를 알 수 없다. 중간 서버는 로드밸런싱 기능이나 공유 캐시 기능을 제공함으로써 시스템 규모 확장성을 향상시키는 데 유용하다.</li>
<li><strong>Uniform Interface</strong> : 일관된 인터페이스로 <strong><em>분리</em></strong>되어야 함<ul>
<li>Resource identification in requests - URI를 사용하는 등의 요청request 내 개별 리소스를 식별 가능해야 함. 예를들어 서버는 db데이터 자체를 전송x, 레코드를 html, xml, json 등의 형식으로 전송. 즉 클라이언트가 받는 응답 내 정보와 리소스는 별개라는 의미같다. 개념적으로 분리되어 있다는.</li>
<li>Resource manipulation through representations - 메시지를 통한 리소스 조작이 가능하다. 클라이언트가 리소스를 지칭하는 메시지와, 어떤 특정 메타데이터를 가지고 있으면 서버 상의 해당 자원 변경, 삭제를 할 수 있는 충분한 정보를 가진 것임</li>
<li>self-descriptive messages - 각 메시지는 자신을 어떻게 처리해야 하는지에 대한 충분한 정보를 포함해야 한다.</li>
</ul>
</li>
<li>Code on demand(optional)</li>
</ul>
<br>
</br>

<h4 id="architectural-structure"><strong>Architectural Structure</strong></h4>
<p>: 클라이언트는 URI를 통해서만 리소스에 접근이 가능함.
<strong>클라이언트는 URI 를 가지고 요청을 보내고, 서버는 리소스의 표현데이터를 응답으로 전송</strong></p>
<p>REST API 구조는 인터넷계층에서 사용할 수 있도록 설계 되었으므로, 클라이언트-서버 간 결합이 경량(loose)이어야 함. → 대규모 채택이 용이하도록. 이는 엔티티를 캡슐화하여 리소스를 정의함으로써 서버측에 추상화된 계층을 형성함으로써 가능한 것.</p>
<p><font size=3 color=grey> [원문]
it is designed for Internet-scale usage, so the coupling between the user agent (client) and the origin server must be <strong>as lightweight (loose) as possible to facilitate large-scale adoption.</strong> This is achieved by creating a layer of abstraction on the server by defining resources that encapsulate entities (e.g. files) on the server and so hiding the underlying implementation details (file server, database, etc.).
...중략
Clients can only access resources using URIs. In other words, <strong>the client requests a resource using a URI</strong> and <strong>the server responds with a representation of the resource.</strong> Thus, a resource is manipulated through hypertext representations transferred in messages between the clients and servers.
...후략</font></p>
<br>
</br>

<h3 id="2-restful-api">2. RESTful API</h3>
<p>: REST(아키텍처)원리의 조건을 따르는 API </p>
<p>-A REST API (RESTful API) is an application programming interface (API or web API) that conforms to(adheres to) the constraints of REST architectural style and allows for interaction with RESTful web services</p>
<p>-Web service APIs that adhere to the REST architectural constraints are called RESTful APIs</p>
<p> 클라이언트에서 RESTful API를 통해 요청을 보내면, requester나 엔드포인트로 리소스의 (현재)state에 대한 표현데이터를 전송(transfer)함</p>
<p> 이 표현데이터라는 정보는 http를 통해 여러 포맷 중 하나로 전달됨(JSON/ HTML 등등) -JSON이 자연어와 기계어 모두 readable하므로 흔히 쓰임</p>
<ul>
<li>RESTful API http요청에 있어서 <strong>헤더</strong>와 <strong>parameter</strong>가 중요. <em>메타데이터나, 인증권한, URI, 캐시, 쿠키 등의 식별자이므로.</em></li>
</ul>
<blockquote>
<p><strong>🌟 RESTful 하게 API를 작성한다는 것 🌟</strong> 
: RESTful한 api 란</p>
</blockquote>
<ul>
<li>클라이언트-서버 구조(클라이언트, 서버, 리소스로 구성된)에서, http를 통해 요청 및 응답 전송</li>
<li>&#39;무상태성 Stateless&#39; 서버에 클라이언트 상의 정보 state가 저장되면 안되며, 각 요청은 독립적임</li>
<li>클라이언트가 응답을 캐싱할 수 있어야 함</li>
<li>컴포넌트 간 일관된 인터페이스. 정보가 일관된 형식으로 전송되어야 함<ul>
<li>요청된 리소스는 개별적으로 식별가능해야 하며, 클라이언트에 전달된 표현데이터와 분리되어야 함</li>
<li>표현데이터만으로도 클라이언트 상에서 리소스를 조작가능하다. 표현데이터가 리소스를 다루는 정보를 충분히 포함하고 있음.</li>
</ul>
</li>
<li>서버의 계층구조는 클라이언트 측에서 알 수 없음.
<a href="https://www.redhat.com/en/topics/api/what-is-a-rest-api">🔗 원문</a></li>
</ul>
<ul>
<li>http 기반 RESTful APIs 예<ul>
<li>a base <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier">URI</a>, such as <code>http://api.example.com/</code>;</li>
<li>standard <a href="https://en.wikipedia.org/wiki/HTTP_method">HTTP methods</a> (e.g., GET, POST, PUT, and DELETE);<p></li>
</ul>
</li>
<li><strong>Semantics</strong> of HTTP methods</li>
<li>semantic:&#39;의미론적&#39;, 즉 메서드 이름에서 역할이 드러나는
The following table shows how HTTP methods are intended to be used in HTTP APIs, including RESTful ones.
<code>[Http method]</code> : <code>[description]</code><ul>
<li>GET: get a representation of the target resource&#39;s state</li>
<li>POST: let the target resource process the representation enclosed in the request.</li>
<li>PUT: create or replace the state of the target resource with the state defined by the representation enclosed in the request.</li>
<li>DELETE: delete the target resouce&#39;s target</li>
</ul>
</li>
</ul>
<p><img src="https://notion-ga.ohwhos.now.sh/collect?tid=G-ZC91RM8375&host=velog.io&page=/@sootulliyang_dev/REST-API" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[http StatusCode]]></title>
            <link>https://velog.io/@sootulliyang_dev/http-StatusCode</link>
            <guid>https://velog.io/@sootulliyang_dev/http-StatusCode</guid>
            <pubDate>Sun, 26 Sep 2021 08:35:17 GMT</pubDate>
            <description><![CDATA[<h4 id="데이터-없음이-404-not-found-로-처리될-일이-맞는지-에-대해"><em>데이터 없음이 404 Not Found 로 처리될 일이 맞는지? 에 대해</em></h4>
<p>=&gt; 204(No Contents) 또는 501(Not Implemented)로 대체 </p>
<p>회원가입-로그인 로직에서, 유효하지 않은 유저가 로그인할 때 (db에 등록되어 있지 않은 미가입 이메일로 로그인 시도 시)
errormessage(뷰 렌더링 상)로 &#39;사용자 없음&#39; 이런 걸 렌더하고싶었는데
404 처리가되면서 클라이언트(리액트)를 건들 수가 없는 거임.
: 즉  4xx는 실패 처리로 응답이 클라이언트에 전송되지 않음.</p>
<p>서버에서(<code>/signin</code>) 응답코드를 2xx 로 처리 해야지 응답이 들어옴</p>
<p>⇒ <strong>204 (No contents, 데이터 없음</strong>)을 활용해서 해결</p>
<p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/2ed2614a-b408-4d3d-a55e-315e29ec2016/204_errorMessage.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210926T083225Z&X-Amz-Expires=86400&X-Amz-Signature=af74299e635ff9c083e55652a20dd93bdfcd27fdb1451ff20f1bca8250e4d706&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22204%2520errorMessage.png%22" alt=""><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/e3bdd224-2b97-4dbb-abc4-b7d8c14e0d71/signup_errormessage.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210926T083259Z&X-Amz-Expires=86400&X-Amz-Signature=737bb1e62ded51d13ae9667fdd12251296cf025d695514ff8e10b2c17f68e471&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22signup%2520errormessage.png%22" alt="">
Signup 컴포넌트 에서도 비슷한 수정 성공</p>
<p>그런데 <em>이미 등록된 이메일</em>  이런 경우는 status code를 뭐로 설정해야 적절할까? ← 더 찾아보기.</p>
<p>🔗  참고 <a href="https://luckyyowu.tistory.com/377">블로그링크</a> ⭐️</p>
<ul>
<li><p>임시</p>
<p>  이런 식으로 해보려했는데. 서버에러로 넘어감.. </p>
</li>
</ul>
<pre><code class="language-jsx">    data.length &gt; 0 ? (
        res.status(200).send({ maessage: &#39;ok&#39; })
        ) : (
            res.status(204).send({ message: &#39;No registered information&#39; })
    )</code></pre>
<pre><code class="language-jsx">    if (data.length &gt;= 0) {
      const accessToken = generateAccessToken(data.dataValues);
          sendAccessToken(res,accessToken);
        res.status(200).send({ maessage: &#39;ok&#39; });
        }
        res.status(204).send({ message: &#39;No registered information&#39; })</code></pre>
<ul>
<li><p>참고</p>
<ul>
<li><p>정말 존재하지 않는 uri 임: 404 Not Found</p>
</li>
<li><p>특정 리소스가 있어야하는데 없음 (로직, 내부 오류): 500 Internal Server Error</p>
</li>
<li><p>특정 리소스가 있을 수도 있고, 없을 수도 있음: 204 No Content</p>
</li>
<li><p>클라이언트가 말도 안되는 파라미터로 리소스를 요청함: 400 Bad Request</p>
<p><img src="https://notion-ga.ohwhos.now.sh/collect?tid=G-ZC91RM8375&host=velog.io&page=/@sootulliyang_dev/http-StatusCode" alt=""></p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[useEffect]]></title>
            <link>https://velog.io/@sootulliyang_dev/useEffect</link>
            <guid>https://velog.io/@sootulliyang_dev/useEffect</guid>
            <pubDate>Sun, 26 Sep 2021 04:49:39 GMT</pubDate>
            <description><![CDATA[<h4 id="keyword">keyword</h4>
<ul>
<li>implicit promise</li>
<li>clean up function</li>
</ul>
<p>useEffect 에서 비동기 처리 방식들의 차이. 안에서 함수를 선언하고 호출하는 것과.. 밖에서 정의하고 호출하는 것과 .. 등등</p>
<h3 id="⌑-비동기-제어">⌑ 비동기 제어</h3>
<p>: useEffect 내부에서 함수로 감싸서(선언해서) call 하는 것과 예를 들어 그냥 바로 axios 요청하는 것과 차이</p>
<ul>
<li>관련 에러</li>
</ul>
<pre><code class="language-jsx">    index.js:1 Warning: **An effect function must not return anything besides a function, which is used for clean-up.**

    It looks like you wrote useEffect(async () =&gt; ...) or returned a Promise. Instead, **write the async function inside your effect and call it immediately**:

    useEffect(() =&gt; {
      async function fetchData() {
        // You can await here
        const response = await MyAPI.getData(someId);
        // ...
      }
      fetchData();
    }, [someId]); // Or [] if effect doesn&#39;t need props or state

    Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching
        in App (at src/index.js:9)
        in Router (created by BrowserRouter)
        in BrowserRouter (at src/index.js:8)</code></pre>
<p>위와 같이  Warning이 뜸. async + await 로 비동기 제어해주고 fetchData() 이런 식으로 함수를 호출(실행)해주는 형태를 권고함</p>
<p>async 함수는 promise 객체를 리턴함(implicit), 그러나 effect hook은 아무것도 리턴하지 않거나 clean up 함수 자체를 리턴해야 하므로, 바로 async 함수를 작성하지 않고 함수를 내부에서 정의해서 call하는 것임</p>
<br>

<p>🔗  <strong>참고 <a href="https://www.robinwieruch.de/react-hooks-fetch-data">링크</a></strong> 🌟 *good!</p>
<p><strong>정리</strong></p>
<ul>
<li>외부 API 요청하여 데이터를 fetch해오고 이를 ⇒ local state로 사용(update)하기 위해 useEffect hook을 이용.</li>
<li>dependency <code>[]</code> 에 의해 무한히 useEffect 가 호출될 수 있음(component가 update될 때마다)</li>
<li><code>[]</code>비어 있을 때만 최초 렌더 시 (when component mounts) fetch해 온다.<h4 id="에러-관련-핵심">에러 관련 핵심!</h4>
</li>
<li>async/await를 쓰는 이유는 외부 api 콜을 요청하기 때문임. 비동기로 처리하기 위해.(<em>using async/await to fetch data from a third-party API)</em></li>
</ul>
<blockquote>
<h4 id="결론">결론</h4>
</blockquote>
<ul>
<li><strong>async함수는 비동기함수 객체 즉 promise 객체를 리턴함.(implicit promise)</strong></li>
<li><strong>effect hook은 아무것도 반환하지 않거나 clean up 함수를 리턴해야 함</strong></li>
<li><strong>그래서 이런 오류가 뜨는 것이고, async함수를 useEffect에서 바로 사용하지 말라고 warning이 뜨는 것.</strong></li>
</ul>
<p><strong>원문</strong>
<font size = 2.5> The effect hook called useEffect is used to fetch the data with axios from the API and to set the data in the local state of the component with the state hook&#39;s update function. The promise resolving happens with async/await.
However, when you run your application, you should stumble into a nasty loop. The effect hook runs when the component mounts but also when the component updates. Because we are setting the state after every data fetch, the component updates and the effect runs again. It fetches the data again and again. That&#39;s a bug and needs to be avoided. <strong>We only want to fetch data when the component mounts.</strong> That&#39;s why you can provide an empty array as second argument to the effect hook to avoid activating it on component updates but only for the mounting of the component.</p>
<pre><code class="language-jsx">function App() {
  const [data, setData] = useState({ hits: [] });
  useEffect(**async** () =&gt; {
    const result = **await** axios(
      &#39;https://hn.algolia.com/api/v1/search?query=redux&#39;,
    );
    setData(result.data);
  }, **[]**);</code></pre>
<p>The second argument can be used to define all the variables (allocated in this array) on which the hook depends. If one of the variables changes, the hook runs again. If the array with the variables is empty, the hook doesn&#39;t run when updating the component at all, because it doesn&#39;t have to watch any variables.
There is one last catch. In the code, <em>we are using async/await to fetch data from a third-party API</em>. According to the documentation every function annotated with async <strong>returns an implicit promise</strong>: *&quot;The async function declaration defines an asynchronous function, which <strong>returns an AsyncFunction object</strong>. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. &quot;<em>. <strong>However, an effect hook should return nothing or a clean up function.</strong> That&#39;s why you may see the following warning in your developer console log: *07:41:22.910 index.js:1452 Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () =&gt; ...) are not supported, but you can call an async function inside an effect..</em> That&#39;s why using <strong>async directly in the <code>useEffect</code> function isn&#39;t allowed.</strong> Let&#39;s implement a workaround for it, by <strong>using the async function inside the effect.</strong></p>
<pre><code class="language-jsx">function App() {
  const [data, setData] = useState({ hits: [] });
  useEffect(() =&gt; {
   ** const fetchData = async () =&gt; {**
      const result = await axios(
        &#39;https://hn.algolia.com/api/v1/search?query=redux&#39;,
      );
      setData(result.data);
    };
   ** fetchData();**
  }, []);</code></pre>
</font>

<br>

<h4 id="useeffect-내부에서-함수를-정의해야-하나-표현식const과-선언식function-의-차이는">useEffect 내부에서 함수를 정의해야 하나? 표현식(<code>const=()=&gt;{}</code>)과 선언식(<code>function(){}</code>) 의 차이는?</h4>
<blockquote>
<p>useEffect 내부에서 함수를 정의하는 이유*효과
    1. 외부에 정의 시 useCallback으로 감싸야 함
    2. 렌더 할 때마다 함수가 선언될 필요가 없다. useEffect 에서만 사용하는 함수라면 특히.
    3. useEffect 내부에서 변수나 함수를 선언함으로써 비동기 제어+ cleanup이 더 쉬움.</p>
</blockquote>
<p>🔗  참고 링크(스택오버플로우)</p>
<p>Why do we define function inside useEffect?
: reasons</p>
<ol>
<li>By definining the function outside of the use effect, you either need to disable exhaustive-deps and risk accidentally having a stale function or you need to useCallback to make the function not-update every render</li>
<li>If the function is only used in the useEffect, you don&#39;t need to recreate the function on every render as that&#39;s just wasted cycles</li>
<li>It&#39;s easier to work with cleanup on the asynchronous functions by defining it within useEffect as you can define variables that are able to be modified within the effect.</li>
</ol>
<p>On that last one, for instance, you can do some actions to <em>prevent state being called when the effect cleans up.</em></p>
<p><strong>주의</strong> arrow function (<code>const functionname = () ⇒ {}</code> *표현식 + arrow ) 는 hositing 되지 않음! </p>
<p> handleLogout 정의 시 선언식 으로. (<code>function name () {}</code>)</p>
<p><strong>*useEffect 내부에서 선언식으로 표현식으로 하는 것의 차이? 스코프 차이인가?</strong>
선언식은 호이스팅되면서 전역변수화?
es6 이후로 sugar syntax 되어 상관없다고 함, same scope를 가짐!
리액트 hook은 기본적으로 순수함수(형 컴포넌트)에서 쓸 수 있음을 기억</p>
<hr>
<h3 id="✪-clean-up">✪ clean up</h3>
<p>🔗  참고 <a href="https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup">공식문서</a></p>
<ul>
<li><p>cleanup이 필요한 side effect 의 경우, 메모리 누수를 방지하기 위해 clean up 함수 필요</p>
<p>  important to clean up so that we <strong>don’t introduce a memory leak</strong></p>
</li>
<li><p>clean up 이라 함은 useEffect 내 return 이 있는 것</p>
<p>  외부로부터 데이터를 구독하는 경우? (set up a <em>subscription</em> to some external data source)</p>
</li>
</ul>
<blockquote>
<p><strong>클래스 컴포넌트의 경우</strong>
 <code>componentWillUnmount</code>로 clean up을 처리함(<code>componentDidMount</code> 에서 외부데이터리소스 구독을 처리하고)
<em>Lifecycle methods force us **</em>to split this logic*** even though conceptually code in both of them is related to the same effect.</p>
</blockquote>
<blockquote>
<p><strong>by using Hooks</strong>
useEffect Hook 자체가 두 상황?을 다룰 수 있도록 고안됨
: (구독 해제-<code>componentWillUnmount</code> 구독 처리-<code>componentDidMount</code> 의 경우) 
‣subscription 추가, 제거 코드는 결합도가 높기 때문에.
effect가 함수를 리턴하면 리액트는 cleanup 필요 시 그 함수를 실행함.
<font size=2.5 color=grey> You might be thinking that we’d need a separate effect to perform the cleanup. But code for <em>adding and removing a subscription is so tightly related that useEffect is designed to keep it together</em>. If your effect <strong>returns a function, React will run it</strong> when it is time to clean up</font></p>
</blockquote>
<br>

<h3 id="when-exactly-does-react-clean-up-an-effect"><strong><em>when exactly does React clean up an effect?</em></strong></h3>
<p>컴포넌트가 unmount 될 때 또 한번의 effect 실행 전 <strong>이전 렌더에서의 effect를 지우는 것</strong>이다.</p>
<p>React performs the cleanup when the component unmounts. .. effects run for every render and not just once. This is <strong>why React also cleans up effects from the previous render before running the effects next time.</strong></p>
<p>사실 componentDidUpdate 가 있어야 확실한 보완?이 됨 🔗 [참고] <a href="https://reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update">공식문서</a></p>
<p>⇒ 클래스 컴포넌트에서 생길 수 있는 bug를 방지하고 <strong>consistency를</strong> <strong>보장</strong>할 수 있는 방법임</p>
<p>*여기서 말하는 버그란: 컴포넌트가 뷰에 렌더된 상태에서 props값이 변동이 생겼을 때, 이전 데이터를 계속 보여주는 상태 일 수 있음. memory leak나 crash.</p>
<p><strong>ensures consistency by default and prevents bugs</strong> that are common in class components <em>due to missing update logic.</em></p>
<p>effect 발생 시나 cleanup 시에 이러한 버그 있을 수 있으므로,  DidUpdate 에서 <code>prevProps</code> 나 <code>prevState</code> 를 사용해서 effect를 skip 하도록 처리하기도 .. </p>
<ul>
<li><p>참고 링크(<a href="https://stackoverflow.com/questions/58495238/getting-error-after-i-put-async-function-in-useeffect">스택오버플로우</a>)</p>
<p>  You&#39;re returning the result of calling <code>getResponse()</code> from the <code>useEffect</code> function. If you return anything from <code>useEffect</code>, it has to be a function. Changing your code to this should fix it because you&#39;re no longer returning anything from the <code>useEffect</code> function.</p>
</li>
</ul>
<pre><code class="language-jsx">    useEffect(() =&gt; {
      getResponse();
    });</code></pre>
<h4 id="the-useeffect-cleanup-function">The <code>useEffect</code> Cleanup Function</h4>
<hr>
<p>If you return anything from the <code>useEffect</code> hook function, it must be a <em>cleanup function</em>. This function will run when the component unmounts. This can be thought of as roughly equivalent to the <code>componentWillUnmount</code> lifecycle method in class components.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[정규표현식 RegExp]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-RegExp</link>
            <guid>https://velog.io/@sootulliyang_dev/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-RegExp</guid>
            <pubDate>Sun, 22 Aug 2021 13:05:38 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.notion.so/RegExp-7a394f282cbd42f7a2ef3a75c1013a11">📒 노션</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux]]></title>
            <link>https://velog.io/@sootulliyang_dev/Redux</link>
            <guid>https://velog.io/@sootulliyang_dev/Redux</guid>
            <pubDate>Sun, 11 Jul 2021 12:36:56 GMT</pubDate>
            <description><![CDATA[<p>Thumbnail: <font size=2> <font color=grey>The Prestige(2006)</font></font></p>
<h4 id="achievement-goals">Achievement Goals</h4>
<ul>
<li>상태관리 라이브러리의 필요성 이해</li>
<li>Redux( or Flux Pattern) 에서 사용하는 Action, Reducer, Store의 의미와 특징 이해</li>
<li>Redux의 3가지 원칙, 주요 개념과의 연결 이해</li>
<li>Presentational Component 와 Container Component의 개념 이해</li>
<li>Redux hooks(useSelector, useDispatch)를 사용해 store를 업데이트</li>
</ul>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/b9af0ad3-fd9a-4812-9843-a6ed83dbd203/redux.png" alt=""><font color=grey font size=2> 출처: Code States</font></p>
<p>React-state, props 이용한 컴포넌트 단위 개발 아키텍처
Redux에서는 컴포넌트와 상태를 분리하는 패턴, 로직을 분리한다면 컴포넌트에서는 표현(UI)에 집중한 단순 함수 컴포넌트를 만들 수 있을 것.
Redux는 react없이도 사용 가능한 상태 관련 라이브러리임</p>
<blockquote>
<p>Redux의 3가지 원칙</p>
</blockquote>
<ul>
<li><ol>
<li>sinlgle source of truth: 동일 데이터는 같은 곳에서 가져옴(Store)</li>
</ol>
</li>
<li><ol start="2">
<li>state is read-only: action 객체를 통해서 state변경이 가능함(action)</li>
</ol>
</li>
<li><ol start="3">
<li>changes are made with pure functions: 순수함수로만 변경이 가능하다(reducer)</li>
</ol>
</li>
<li>pure functions
동일한 인자값을 받으면 항상 동일한 값을 리턴
어디서든 호출되든 동일한 결과를 보여줌
외부에 영향을 주지도 받지도 말아야 함</li>
</ul>
<p>App =&gt; ShoppingCart =&gt; CartItem
부모에서 상태를 관리한다면 state에 접근해서 정보공유가 가능하므로 자식 컴포넌트에서 전달이 불가했다.</p>
<p>store는 전역상태를 담고 있음, 상태를 관리하는 하나의 공간
state를 store에서 관리하면 정보 공유, 데이터 전달이 용이
action 이란 자바스크립트 객체로, store에 데이터를 운반한다. type을 꼭 지정해줘야 함
reducer는 action 객체가 dispacth메서드에 전달되면 reducer를 호출하고, reducer는 store에서 새로운 state를 생성한다
이것은 react의 단일방향 데이터흐름 특성에 기인</p>
<blockquote>
<p>Redux는 순수 함수라 다음 상태가 어떤 상태일지 예측이 가능하게 하고,
유지보수가 용이, 디버깅에 유리(action, state log 기록 시)&lt;- redux dev Tool 설치*
테스트를 붙이기에도 쉽다</p>
</blockquote>
<p>Redux의 store로 관리하지 않아도 됨, 
하나의 컴포넌트에서만 사용하는 state라면 따로 쓸 수도 있음
<br></p>
<h3 id="✯-what-is-redux">✯ What is Redux?</h3>
<h4 id="🔗--basics-in-redux-without-react"><a href="https://www.robinwieruch.de/react-redux-tutorial#what-is-redux">🔗  BASICS IN REDUX WITHOUT REACT</a></h4>
<p><font color=grey font size = 3>위 글을 읽고 다시 한번 정리하자면,(process나 관계를 설명하는 말풀이는 원어로 받아들이는 것이 더 납득이 된다)</font></p>
<ul>
<li>action을 executing 하는 것이 &quot;dispatching&quot;</li>
<li>store의 state를 변경(update)하기 위해서 action을 dispatch하면 된다. You can dispatch an action to alter the state in the Redux store. </li>
<li>웹앱 UI(view)화면 상에서 버튼을 클릭하는 등의 단순한 이벤트가&gt;action dispatching&lt;을 일으킴(trigger)</li>
</ul>
<blockquote>
<p>View(click or .. events) → dispatching action → Reducer → state update in Store → View(새로운 화면 render)
<img src="https://images.velog.io/images/sootulliyang_dev/post/4e440797-9187-4f9a-8791-961525be114f/redux%20%E1%84%80%E1%85%A2%E1%84%8B%E1%85%AD.png" alt=""><font color=grey font size=2>출처: CodeStates </font></p>
</blockquote>
<ul>
<li>action이 dispatching 되면 모든 reducer를 통과한다.</li>
</ul>
<p><font color = grey font size = 3>Executing an action is called dispatching in Redux. You can dispatch an action to alter the state in the Redux store. You only dispatch an action when you want to change the state. The dispatching of an action can be triggered in your View. It could be as simple as a click on a HTML button. In addition, the payload in a Redux action is not mandatory. You can define actions that have only an action type. In the end, once an action is dispatched, it will go through all reducers in Redux. </font></p>
<ul>
<li>reducer는 pure function이고 state와 action이라는 input이 같으면 항상 같은 output(new state)을 반환</li>
<li>reducer는 이전 state를 새로운 state로 &#39;reduce&#39;응축해준다.
the reducer reduces the previous state and incoming action to a new state.</li>
</ul>
<blockquote>
<p>＊ [reducer의 immutability]
(<a href="https://daveceddia.com/react-redux-immutability-guide/">https://daveceddia.com/react-redux-immutability-guide/</a>)</p>
</blockquote>
<ul>
<li>React에서 state를 변경하기 위해서는 this.state에 바로 할당하는 것이 아닌 this.setState를 통해 state를 변경해주어야 했던 이유를 생각*</li>
<li>기존 state를 트래킹하고 로그할 수 있도록, immutable하게 변경해야 함</li>
<li>react의 virtual DOM으로 렌더 후 real DOM에 전달하는 것이 역할과도 관련</li>
</ul>
<blockquote>
<p>react + flux라는 redux는 기존 flux의 store가 여러개 였다는 점, reducer가 하나였다는 점에서 차이가 있다.</p>
</blockquote>
<ul>
<li>Redux는 전역상태의 state를 관리하는 하나의 store를 가지고 있고,</li>
<li>reducer는 여러 개를 정의할 수 있다</li>
</ul>
<br>

<ul>
<li>useSelector</li>
<li>useDispatch</li>
</ul>
<br>

<ul>
<li><a href="https://www.notion.so/Redux-overview-fae978a050d44e2d85098afa93023a44">📒 미들웨어 thunk 및 Redux review</a>
<img src="https://images.velog.io/images/sootulliyang_dev/post/83035b98-d9f3-4b36-b603-a878038e0c80/Hnet-image.gif" alt=""><font color=grey font size=2> 출처: Code States</font></li>
</ul>
<p>💬 참고
<a href="https://daveceddia.com/react-redux-immutability-guide/">🔗 Immutability in React and Redux: The Complete Guide
</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL  👩🏻‍💻]]></title>
            <link>https://velog.io/@sootulliyang_dev/TIL-dppd9k3x</link>
            <guid>https://velog.io/@sootulliyang_dev/TIL-dppd9k3x</guid>
            <pubDate>Sat, 03 Jul 2021 06:35:06 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>＊same origin 기준 : 프로토콜(http/https), 도메인(주소), 포트port 이 셋이 모두 같은 것이 same origin!
＊promise일 때만 await가 의미가 있음, 필요없다면 굳이 쓸 이유가 없다.</p>
<h3 id="❖-express">❖ Express</h3>
<p>express.js는 node.js 환경에서 웹서버/API 서버 제작을 위해 사용되는 프레임워크</p>
<ul>
<li><h4 id="응답을-json-데이터타입으로-주는-방법-resend-ressend-resjson">응답을 json 데이터타입으로 주는 방법: <code>res.end()</code>, <code>res.send()</code>, <code>res.json()</code></h4>
</li>
</ul>
<ol>
<li><p><code>res.json({객체}들어감)</code></p>
<ul>
<li><code>res.send()</code>와의 차이: <code>res.json()</code>은 받은 인자를 json 문자열로 변환해서 헤드에 &#39;Content-Type&#39;: &#39;application/json&#39;으로 셋팅해주고, <strong>body인자에 저장해서 내부적으로 <code>res.send</code>를 호출해서 body인자로 넘겨줌</strong></li>
</ul>
</li>
<li><p><code>res.send()</code></p>
<ul>
<li>express 문법, JSON.stringify 써야함</li>
<li>header 붙이기 위해 응답 바디 내에 res.send(&#39;Content-Type&#39;, &#39;application/json&#39;) 작성해야 할까? 
<font color=red>→ 이미 __ <code>res.jsonp([body])</code> __ 가 있음! </font>
Sends a JSON response with JSONP support. This method is identical to res.json(), <strong>except that it opts-in to JSONP <font color=red>callback support</font>.</strong>
<a href="http://expressjs.com/ko/api.html#res.jsonp">express 공식문서</a></li>
</ul>
</li>
</ol>
<ul>
<li>라우터 <code>app.use(&#39;/&#39;,routerFile명)</code></li>
</ul>
<blockquote>
<ul>
<li><h4 id="미들웨어">미들웨어</h4>
http요청 인수해서 로드(?) 찍기 - cors 헤더 추가 - 바디parse -&gt; http 응답 인수까지 - 컨베이어 벨트와 같은 process에서 이 중간 과정들을 미들웨어로 처리</li>
</ul>
</blockquote>
<ul>
<li><p>express의 큰 장점</p>
</li>
<li><p><strong>get, use 등</strong></p>
</li>
<li><p>미들웨어 사용할 때:</p>
<ul>
<li>모든 요청/응답에 CORS헤더를 추가할 때: <code>app.use(cors())</code></li>
<li>요청(<code>POST /</code>등)에 포함된 body(payload)를 쉽게 얻는 방법, bodyParser 미들웨어 사용: <code>app.use(express.json())</code></li>
<li>req.method  또는 req.url 확인</li>
<li>요청 header 내 사용자의 인증 정보 포함 여부 확인
...</li>
</ul>
</li>
</ul>
<ol>
<li><h4 id="next-에러처리-미들웨어">next: 에러처리 미들웨어</h4>
<ul>
<li>(.then 과 같은 느낌, 콜백을 인수?호출?한다는 점에서.)</li>
<li>next()를 호출하지 않으면 파이프라인이 그 미들웨어에서 종료되고, 이후의 라우트 핸들러와 미들웨어가 호출되지 않음<pre><code class="language-js">// 예시를 들자면
app.use((req, res, next) =&gt; {
console.log(&#39;내가 추가한 공정&#39;);
next(); // &lt;- 호출
});</code></pre>
<pre><code>&gt;❗️ __next를 호출하지 않는다면 클라이언트에게 어떤 응답이라도 보내야 함__
```js
app.use((req, res, next) =&gt; {
console.log(req.body)
res.status(404).send(&#39;Not Found!&#39;); // &lt;- 응답 처리
});</code></pre><pre><code class="language-js">app.use((err, req, res, next) =&gt; {
console.error(err.stack);
res.status(500).send({ // &lt;- 응답 처리
message: &#39;Internal Server Error&#39;,
stacktrace: err.toString()
});
});</code></pre>
</li>
</ul>
</li>
</ol>
<ul>
<li>요청/응답 인수
<font color=grey><font size=2>＊req === request, res === response</font></font></li>
</ul>
<ol>
<li><h4 id="reqparams-vs-reqqeury"><code>req.params</code> vs <code>req.qeury</code></h4>
<code>req.params</code>는 라우팅({path})이 <font color=grey> user/:name</font>와 같이 <font color=grey>{:id}</font> 형태인 경우
<code>req.query</code>는 <font color=grey>/flight?departur=ICN&amp;destination=CJU</font> 와 같은 쿼리스트링이 객체로.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 👩🏻‍💻]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EC%84%9C%EB%B2%84-node.js-CORS</link>
            <guid>https://velog.io/@sootulliyang_dev/%EC%84%9C%EB%B2%84-node.js-CORS</guid>
            <pubDate>Wed, 30 Jun 2021 13:57:02 GMT</pubDate>
            <description><![CDATA[<p>http요청을 처리하여 알맞은 응답을 보여주는 프로그램을 웹 서버라고 함</p>
<h3 id="❖-cors">❖ CORS</h3>
<p>=== Cross-origin resource sharing
이전에는 서버에서 다운로드된 클라이언트으로 통신하였으나, 웹앱이 고도화되면서 <strong>외부의 api를 가져오는 등 여러 곳의 리소스를 활용할 필요성 증가</strong>
*same origin이 아닌 <strong>다른 cross-origin에 request를 보내고 response를 받기 위해 허용한 범위 내 가능하도록 수정됨</strong>
웹어플리케이션, 브라우저의 클라이언트를 보호하기 위한 보안정책</p>
<h3 id="❖-node-server-구현">❖ node server 구현</h3>
<p>=== node.js 내장 http모듈을 사용하여 단순한 서버 구현</p>
<ul>
<li><p>일종의 문법(http 요쳥, 응답을 처리하는 문서 작성)</p>
<ul>
<li>createServer, writeHead 등</li>
<li>.on 으로 (addEventListener과 같은 느낌으로 이벤트 발생 시 콜백 수행) <blockquote>
<p>Express 에서 <strong>.next</strong>가 .then 과 같은 느낌</p>
</blockquote>
</li>
<li>.end() (요청이 끝남, &#39;endgame&#39;, .json(), .send()<font color=grey>**express</font> 과 차이를 논하는 글이 많은 걸 보니 유사한 듯)<ul>
<li><font color=navy> <strong>data는 여러번 올 수 있음, end는 한번만!(stream, buffer개념), chunk는 buffer, request객체는 stream임.</strong>(공식문서 참고)</font>
buffer : 데이터의 조각들이 쌓여서 스트리밍할 데이터가 완전히 다운로드됨(요청이 한번에 가지 않음, 사진img데이터 하나만 요청하여도 <pre><code class="language-js">.on(&#39;data&#39;, (chunk) =&gt; {
body. push(chunk);
}.on(...</code></pre>
⏏︎ 이 부분이 반복되는 것임<p>
<font color=grey> * Node.js 의 buffer 크기는 일반적으로 사용자의 메모리 크기까지 유동적으로 커진다? fs 모듈의 stream 관련 함수들은 기본적으로 64kb이고 highwartermark로 따로 크기를 지정해줄 수 있다고.</font>
</li>
</ul>
</li>
</ul>
</li>
<li><p>🔗 <a href="https://nodejs.org/ko/docs/guides/anatomy-of-an-http-transaction/">Nodejs 공식문서의 HTTP 요청/응답 해부</a></p>
<pre><code class="language-js">const http = require(&#39;http&#39;);
http.createServer((request, response) =&gt; {
// const { headers, method, url } = request;
let body = [];
request.on(&#39;error&#39;, (err) =&gt; {
  console.error(err);
}).on(&#39;data&#39;, (chunk) =&gt; {
  body.push(chunk); // 버퍼 축적
}).on(&#39;end&#39;, () =&gt; {
  body = Buffer.concat(body).toString(); // 축적된 Buffer데이터 concat
  response.on(&#39;error&#39;, (err) =&gt; {
    console.error(err);
  });
  response.writeHead(200, {&#39;Content-Type&#39;: &#39;application/json&#39;})
//  const responseBody = { headers, method, url, body };
  response.end(JSON.stringify(responseBody))
});
}).listen(8080); // 8080port에서</code></pre>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/2ba8b93b-9a28-47e3-98b0-a2f26fbdb1a2/http%20transaction.png" alt=""></p>
</li>
<li><p>헤더 세팅</p>
<pre><code class="language-js">const defaultCorsHeader = {
&#39;Access-Control-Allow-Origin&#39;: &#39;*&#39;, // 모든 주소를 클라이언트로 허용
&#39;Access-Control-Allow-Methods&#39;: &#39;GET, POST, PUT, DELETE, OPTIONS&#39;, // 허용하는 요청메소드
&#39;Access-Control-Allow-Headers&#39;: &#39;Content-Type, Accept&#39;,
&#39;Access-Control-Max-Age&#39;: 10 // preflighted request는 10초까지만 허용, 10초 이내에 요청이 왔다갔다 하는 경우는 preflight 안 보낸다는 의미
};</code></pre>
<p>** cors 헤더도 express를 이용하면 미리 일일이 선언하지 않아도 된다.</p>
</li>
</ul>
<p>🔎 header 내 <code>&#39;Access-Control-Allow-Origin&#39;</code>에 다른 도메인주소를 넣는다면? 
❗️ 특정 origin(클라이언트 주소) 지정 시, 다른 포트에서는 접근 불가
    <a href="https://github.com/vercel/serve">serve 유틸리티</a>를 활용하여 origin을 설정 <code>npx serve -l 3000</code> &gt; serve listen (Specify a URI endpoint on which to <strong>listen</strong>)</p>
<pre><code class="language-js">  // client 서버가, 지정된 origin과 불일치 시 콘솔창에서 확인되는 에러
  Access to fetch at &#39;http://localhost:3000/upper&#39; from origin &#39;~~&#39; has been blocked by CORS policy: 
  Response to preflight request doesn&#39;t pass access control check: No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource. 
  If an opaque response serves your needs, set the request&#39;s mode to &#39;no-cors&#39; to fetch the resource with CORS disabled.</code></pre>
  <br>

<blockquote>
<p>💱➿ When Harry met <del>not Sally</del> it&#39;s <strong><font color=deeppink>Error</strong></font> 🔣 ⚠️
<font color=grey> 내가 만난 에러 </font></p>
</blockquote>
<ul>
<li>Content-type 관련 
<code>Uncaught (in promise) SyntaxError: Unexpected token</code> <font color=grey> ${sth}</font> <code>in JSON at position 0</code>
json 데이터를 보내주는 서버에서 데이터타입이 json 형식임을 명시하지 않아서 뱉는 에러
→ fetch 함수 내 header 항목의 Content-type, Accept를 설정해줌 &#39;application/json&#39;으로 해결
🔎 &#39;<em>text/plain&#39;으로 설정한다면?</em> preflighted request(OPTIONS) 보내지 않음 즉 데이터 타입을 정확히 써줘야 된다는 의미로 보임
❗️ options요청은 cross-origin request가 들어왔을 때, 서버가 allow하는 조건을 충족하는지 사전에 확인하는 &#39;preflighted request&#39;이다. <a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/OPTIONS">MDN</a><p></li>
<li>Error 핸들링 관련<pre><code class="language-js">// node terminal에서
xxxx.js:$$$
    throw er; // Unhandled &#39;error&#39; event
    ...
Emitted &#39;error&#39; event on Server instance at:
...</code></pre>
🤔 에러를 throw하고 있으나 에러를 핸들링하는 게 없다는 뜻, createServer사용한 http요청/응답 처리 함수 내 로직에서 조건이 잘못 걸린 것으로 보여짐.
구현한 서버의 테스트케이스로는 에러발생할 로직이나 이벤트가 없어서 &#39;에러&#39;로서 핸들링하지 않고, 요청에 대한 응답을 에러 코드(http status code 400, 404, ..etc.,)를 writeHead로 처리.(?)<pre><code class="language-js">// console 창에서
ERR_STREAM_WRITE_AFTER_END</code></pre>
🤔 들어오는 요청의 형태(GET/POST/..)와 주소path에 따른 조건별로 응답을 end처리 할 것임(<strong>조건에 따른 분기, 라우팅</strong>), 따라서 조건 외 함수 내 젤 바깥 스코프에서 end로 응답처리를 해버린 것(조건 로직 위에서든 맨 마지막에서든)이 에러를 냄<del>(조건을 다 거치고도 마지막 응답처리가 뒤집어씌워지는 것처럼 발견되었음)</del> <strong><font color=red>응답을 한번만 할 수 있다</strong></font>고 생각하면됨. 실수 방지를 위해 <code>return;</code>을 해주기도 함</li>
</ul>
<br>


<h4 id="❖-웹-서버와-앱-서버">❖ 웹 서버와 앱 서버</h4>
<blockquote>
<p>웹 서버 (Web Server)
    App Server는 웹 서버(Web Server), 웹 앱 서버(WAS, Web Application Server)를 포괄하는 상위 개념
    웹 서버는 정적인 페이지 (이미지, html, js 등 컴퓨터 내 파일)를 반환,
    동적 페이지는 들어온 요청에 맞게 동적으로 만들어진 컨텐츠
WAS는 Database, 로직을 거쳐야 하므로 정적인 컨텐츠는 Web Server에 처리하여 빠르게 제공하도록 =&gt; 기능을 분리하여 서버 부하를 방지
    그 외 물리적으로 분리하여 보안을 강화하는 등 결론적으로, 자원 이용의 효율성 및 장애 극복, 배포 및 유지보수의 편의성을 위해 Web Server, WAS를 각기 사용한다.
<br></p>
</blockquote>
<ul>
<li><p>디버깅
(에디터 내 디버깅 기능과 크롬(웹브라우저) 개발자 도구의 node.js)
package.json에서 dependency</p>
<ul>
<li>nodemon <ul>
<li>&quot; --inspect; 디버깅</li>
<li>&quot; --inspect-brk ; 코드 최초 로드(실행) 때 브레이크 포인트 잡음</li>
</ul>
</li>
</ul>
</li>
<li><p>주소창에 입력하는 것: GET 요청임</p>
</li>
<li><p>요청 body 받기</p>
<ul>
<li>응답 body 받기와 달리 어려움</li>
<li>개념 두 가지 등장 <ul>
<li>stream</li>
<li>buffer</li>
</ul>
</li>
</ul>
<br>

</li>
</ul>
<blockquote>
<p>👩👩🏻‍💻 💻
  내일은 Express Library로 mini node 서버를 리팩토링할 예정.
  오늘 fetch로직과 http요청,응답 처리를 작성하는 등의 방식으로 서버를 구현해본 것과 달리 <strong>Express라이브러리가 단순화시켜주는 작업이 무엇인지</strong>, 그리고 <strong>미들웨어</strong>를 중점을 두고 학습</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 👩🏻‍💻]]></title>
            <link>https://velog.io/@sootulliyang_dev/TIL-gjac4oc3</link>
            <guid>https://velog.io/@sootulliyang_dev/TIL-gjac4oc3</guid>
            <pubDate>Mon, 28 Jun 2021 13:14:54 GMT</pubDate>
            <description><![CDATA[<h3 id="1-useeffect-hook">1. useEffect Hook</h3>
<p>&amp; side effect [React]</p>
<ul>
<li><p><code>useEffect(() =&gt; {}, [])</code></p>
<ul>
<li>첫번째 인자는 함수, side effect를 일으킴</li>
<li>두번째 인자는 어떤 값의 변경이 일어날 때를 의미하는 조건을 담고 있음(배열)</li>
</ul>
</li>
<li><p>컴포넌트 내부에서 useEffect hook 씀으로써 =&gt; causing side effect in a functional Component, and state&amp;props 접근 가능</p>
</li>
<li><p>effect를 쓰는 경우: requesting React <em>to execute function that is passed as an <em>_argument</em></em> _ <font color=blue> everytime the Component renders.</font></p>
<ul>
<li><code>useEffect</code> runs after every render of the Component.</li>
</ul>
</li>
<li><p>class component; initial &amp; update both run after first render and after every update</p>
</li>
<li><p>최상위 컴포넌트에서만 hook을 호출해야하며 React 함수 내에서 hook을 호출해야 함</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/d929692a-ca6d-46ee-8e12-6926e9c41ebf/useEffect%20.png" alt=""></p>
<p>
</p>

<blockquote>
<h4 id="conditionally-run-effects">Conditionally run effects</h4>
<p><a href="https://youtu.be/8DYlzVUTC7s">Codevolution - React Hook Tutorial 영상 6번~8번</a></p>
</blockquote>
<p>
</p>

<blockquote>
<h4 id="상태-끌어올리기lifting-state-up">상태 끌어올리기(lifting state up)</h4>
<p>: <font color=blue><strong>하위 컴포넌트에서의 클릭 등의 이벤트가 상위(부모) 컴포넌트의 상태를 바꾼다.</strong> </font>
상위 컴포넌트의 상태를 변경할 함수 자체를 (마치 콜백처럼) <strong>handler로 하위 props로 전달</strong>, 이 함수를 하위 컴포넌트가 실행한다.</p>
</blockquote>
<br>

<h3 id="2-algorithm">2. Algorithm</h3>
<ul>
<li><p>코딩테스트문제 - 이진탐색(Binary Search) *재귀로도 가능(구현해보기)</p>
</li>
<li><p>big O 시간복잡도 <a href="https://youtu.be/BEVnxbxBqi8">nomad coder</a> <img src="https://images.velog.io/images/sootulliyang_dev/post/a6cec660-b33e-4e77-9cdb-55be48a7ff2c/IMG_0126.PNG" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[비동기] 콜백 & Promise & async]]></title>
            <link>https://velog.io/@sootulliyang_dev/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BD%9C%EB%B0%B1-Promise-async</link>
            <guid>https://velog.io/@sootulliyang_dev/%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BD%9C%EB%B0%B1-Promise-async</guid>
            <pubDate>Sat, 26 Jun 2021 08:40:48 GMT</pubDate>
            <description><![CDATA[<h3 id="비동기">비동기</h3>
<p>자바스크립트는 <strong>single-threaded</strong> 프로그래밍 언어이다. 그렇기 때문에 동기적이다. 동기적 synchronous이란 의미는 다음의 동치와 같다.
synchronous === one call stack === one piece of code at a time
하지만 우리는 이를 비동기적으로도 작동시킬 수 있다. 
이 포스트에서 자바스크립트에서 코드를 비동기적(asynchronous)으로 작성하기 위한 3가지 방법을 학습 및 리뷰할 것이다: 콜백, Promise 객체, async&amp;await</p>
<blockquote>
<ul>
<li>콜스택(Call Stack) is basically a data structure <strong><em>which records where in the program we are</em></strong>.
우선 콜 스택은 우리가 브라우저 등에서 &#39;실행&#39;시킨 즉 함수의 호출, &#39;invoke&#39;관점에서 작동할 기능들이 들어오는 &#39;스택&#39;이다. 스타벅스에서 주문 후 &quot;음료 제조 중&quot;에 들어간 것이다. 
If we step into a func, we push sth on the stack,
return from a func, we pop off the top of the stack<font color=grey>
</li>
</ul>
</blockquote>
<ul>
<li><strong>&#39;maximum call stack size exceeded&#39;</strong>: 코드를 작성하면서 이와 같은 에러메시지를 본 적이 있다. 콜백 안의 콜백으로 마치 엘레베이터 내 양쪽벽면이 거울로 둘러쌓여 무한대의 거울상이 생기는 것과 같다. 브라우저는 사용자에게 당신이 같은 콜백을 수천번, 수만번을 호출했을 리가 없으니 이를 끝내겠다고 오류로 뱉는 것이다. </font>
<img src="https://images.velog.io/images/sootulliyang_dev/post/0cd50e2d-9d29-4010-a9dd-3bd2428096d6/range%20error.png" alt=""><p>

</li>
</ul>
<blockquote>
<ul>
<li><strong>blocking vs Non-blocking: 브라우저가 느려지는 이유는?</strong>
만약 동기적으로 작동하는 코드베이스로 인해 콜 스택에 들어온 함수가 내부 콜백에 setTimeout으로 타이머가 걸려있어, 우리는 브라우저의 다른 부분을 클릭하거나 해당 페이지로 넘어가거나 등등 다른 수행을 할 수 없는 이러한 경우 콜 스택이 blocking 된 것이다.
리액트 등으로 만드는 컴포넌트형 웹앱이 대세라고 하지만? 아직까지 한국에서는 페이지 전체를 reRender 하는 형태가 꽤나 남아있다.
<a href="https://sungmooncho.com/2012/12/04/gmail-and-ajax/">🔗 관련 글: 지메일이 핫메일을 이긴 진짜 이유 (Ajax가 가져온 유저 인터페이스의 혁신)</a>
개발자로서 코드의 최적화를 위한 사고는 &quot;브라우저가 왜 느려질까?&quot;라는 질문부터 시작된다.
<font color = grey>  *setTimeout에서 걸어주는 타이머는 minimum을 걸어준 것이지, 0으로 한다고 바로 실행된다, 이런 의미로 활용하는 것은 아니다.</font></li>
</ul>
</blockquote>
  <p></p>


<ul>
<li><h4 id="event-loop-🔄">Event Loop 🔄</h4>
이벤트 루프는 심플하게 딱 한가지의 역할을 한다. task queue에 쌓인 함수를 콜스택이 비었을 때 이제 실행하라고 넘겨주는 것이다.
&quot;queue&quot;인 만큼 먼저 들어온 대기 기능(함수)가 먼저 나가는 선입선출이다.
<img src="https://images.velog.io/images/sootulliyang_dev/post/53faeaac-8d55-4066-8149-a8efe85f24b5/EventLoop.gif" alt="">🔗 <a href="https://youtu.be/8aGhZQkoFbQ">참고 영상: What the heck is the Event Loop? | JSConf EU</a><p></p>

</li>
</ul>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center"></th>
</tr>
</thead>
<tbody><tr>
<td align="center">call <strong>stack ⇪</strong>(실행)</td>
<td align="center"></td>
</tr>
<tr>
<td align="center"><strong><font color=blue>Event Loop 🔄 </font></strong></td>
<td align="center">콜스택이 비었을 때 task queue에 대기하고 있던 실행할 내용을 콜스택으로 넘겨줌</td>
</tr>
<tr>
<td align="center">task <strong>queue</strong>↩︎</td>
<td align="center"></td>
</tr>
</tbody></table>
<blockquote>
<p>💡 <font color = crimson> Question<br>  Node.js는 single-thread인가?
  그렇다면 <strong>Event Loop는 왜 필요한가?</strong> </font></p>
</blockquote>
  <br>
  ⏤
  </br>

<h3 id="❖-콜백함수">❖ 콜백함수</h3>
<p>자바스크립트에서 <strong>함수는 객체</strong>이다, 
<strong>함수는 변수를 담은 채로 함수를 리턴할 수 있고(closure), 
리턴할 함수를 인자로서 받아 다른 함수에 전달할 수도 있고, 
변수에 할당할 수 있다.</strong>
함수가 인자로 콜백함수를 받아서 들어오는 배열의 각 요소나 객체의 key/value에 함수를 적용하여 그 결과를 성공 시 또는 실패 시(error) 결과를 되돌려 리턴해주는 것이라 &#39;callback&#39;이란 네이밍의 의미를 따져볼 수 있다. 
따라서 콜백함수 안에 콜백함수, 또 그 안에 콜백함수..가 있을 수 있다.</p>
<blockquote>
<p>callback hell case 🧻
_예제로 다음과 같은 과정의 코드가 있을 경우, _</p>
</blockquote>
<ol>
<li>사용자에게 id, pw 받아오기</li>
<li>로그인 시도</li>
<li>로그인 성공 시 id 받아오고</li>
<li>역할 받아오기(admin 등)</li>
<li>성공적으로 받아온다면 사용자의 object를 갖게 되는 것<pre><code class="language-js">// class객체는 생략함
const userStorage = new UserStorage(); // class 만들고 서버와 통신
const id = prompt(&#39;enter your id&#39;); // 사용자가 입력
const password = prompt(&#39;enter your pssword&#39;); // 사용자가 입력
userStorage.loginUser(id, password, (user) =&gt; { // ⓐ콜백 사용자가 입력한 user정보를 다음 콜백에 넘김
 userStorage.getRoles(user, (userWithRole) =&gt; { // ⓑ콜백 이 콜백은 사용자의 Role정보를 받아오는 함수
     alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`)
 }, (error) =&gt; { // 에러가 날 경우 에러 핸들링(ⓑ콜백)
     console.log(error)
 })
}, (error) =&gt; { // 에러 핸들링(ⓐ콜백)
 console.log(error)
})</code></pre>
<font size =3><font color=grey>드림코딩by엘리 유튜브 무료강의 예제 참고</font></font> <p></li>
</ol>
<p>예제는 콜백 안에서 콜백을 한번 더 전달하는 두 겹의 중첩뿐이긴 하지만, 
이렇게 콜백 안에서 콜백을 전달하고, 또 전달, 또 전달하게.. 되면 콜백지옥이 되는데, 이러한 코드 문제점: 가독성 현저히 낮고, 로직 파악이 불편하며 디버깅도 어려움, 유지보수에 꽝이다.
따라서 <strong>병렬적으로 작성할 수 있고, 네트워크와 효율적으로 통신할 수 있도록 Promise객체와 async &amp; await를 사용하여 비동기 코드를 작성</strong>한다. (곧 비동기적으로 코드를 작성해야 하는 이유)</p>
  <br>


<p>콜백함수를 인자로 받는 map, filter, forEach 등 배열 메소드
아래 gif 이미지에서 forEach를 async하게 만들어 실행하는 경우를 보여주고 있다.</p>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/1417e7af-56a7-4e5c-beb5-c8cb138563fa/async-forEach.gif" alt="">앞서 말한 blocking 현상과 non-blocking을 여기서 확인할 수 있다.
비동기적으로 코드를 작성하면, 코드가 실행되는 사이사이마다 브라우저는 render할 수 있다.(render queue가 <font color=tree>초록색으로 깜빡이는 것</font>)</p>
<br>
  ⏤
  </br>

<h3 id="❖-promise">❖ Promise</h3>
<p>Promise는 <strong>비동기를 간편하게 처리할 수 있도록 도와주는 &quot;object&quot;</strong>이다.</p>
<p><font color = #8B700C>☝🏻 예를 들어 오픈될 수강에 대한 이메일 공지 알림받고싶어 이메일 구독 신청하는 경우, 뒤늦게 사전공지창을 발견했을 때 이메일 등록 시 수업은 이미 오픈되었으니 기다리지 않아도 바로 메일로 공지가 옴 : 이미 성공적으로 처리된 promise인 것!</font></p>
<p>promise 객체는 <strong>promise객체를 리턴한다.</strong> <font color = grey>(처음 배울 때 코드를 직접 작성하는 기술,적인 면에서는 중요한 포인트라고 생각한다.)</font></p>
<pre><code class="language-js">const getDataPromise = path =&gt; {
  return new Promise((resolve, reject) =&gt; {
    fs.readFile(path, &quot;utf8&quot;, (err, data) =&gt; {
      if(err) {
      reject(err);
      }
      resolve(data);
    })
  })
};</code></pre>
<p>  수행 결과 값이 있으면 <code>resolve</code> 콜백인자로 넘겨주고, .then 메소드로 resolve 콜백인자 또는 리턴 값을 콜백에 또 넘긴다.
콜백 결과 리턴에 실패 시, 즉 에러가 있으면 에러를 <code>reject</code> 콜백인자로 넘겨준다.
  ＊.try/ .catch 메소드로 에러를 잡음.</p>
<p>  <font color=grey>＊여기서 말하는 콜백은 콜백함수와 같이 작동하는 기능을 말함.
    프로미스는 콜백을 쓰지 않고 비동기로 깔끔한 코드를 작성하도록 하는 객체이다.</font></p>
<blockquote>
<p><font color = #111 > <em>Promise is a JavaScript object for asynchronous operation.</em> </font></p>
</blockquote>
<h4 id="❗️-two-points-pp">❗️ Two points <p></p></h4>
<ol>
<li><font color=red><strong>상태 state＊</strong></font> : pending -&gt; <strong>fulfilled</strong> (수행 성공 완료) or <strong>rejected</strong>
:프로세스가 operation을 수행하고 있는 중인지 / 기능을 다 수행하여 성공했는지 실패했는지
<font color=grey>  (정해진 장시간의 기능을 수행 후 기능이 정상적으로 수행되었으면 성공 메시지 + 처리된 결과값 전달하고(resolve), 수행 중 에러가 발생하면 에러를 전달(reject)한다.)</font>    *resolve 와 reject는 executor라고 부른다.
리턴하는 것이 없으면 &#39;pending&#39; 상태<p></p></li>
<li><strong>producer</strong>(정보 제공) vs <strong>consumer</strong>(소비)
: promise객체를 만든다. 이것이 producer이고, 이 promise 인스턴스를 사용하는 .then/ .catch/ .finally 메소드를 consumer로 본다.
.then 등의 메소드를 통해 <strong>여러 다른 비동기를 묶어서 병렬적으로 처리가 가능</strong>한 것이다.</li>
</ol>
<p>예제</p>
<pre><code class="language-js">// 1. producer
const promise = new Promise((resolve, reject) =&gt; { // 두가지 콜백이 또 인자로 들어옴 (resolve, reject : executor)
  // 파일을 읽거나(fs.readfile) 네트워크와 통신하는 등의 시간이 걸리는 작업 → 비동기적으로 처리(곧 비동기가 필요한 이유!)
    console.log(&#39;doing something...&#39;);

    setTimeout(() =&gt; {
        resolve(&#39;success&#39;); // 수행 성공 시 resolve 콜백 호출(, 인자 전달)
    //  reject(new Error(&#39;no network&#39;))
    }, 2000)
})</code></pre>
<pre><code class="language-js">// 2. consumer
promise
    .then((value) =&gt; { // promise 값이 잘 수행되었으면 어떤 값(value)을 받아와서 (인자를 넘겨줘서) 콜백을 수행할 것
  // 여기서 value는 위 producer 코드의 resolve콜백을 통해 전달한 &#39;success&#39;
        console.log(value);
    }) // ! then은 성공한 수행결과값을 전달하거나, promise를 전달할 수 있음, 여기서는 똑같은 promise를 리턴함
    .catch(error =&gt; { // ! 그 리턴된 promise에 catch를 또 호출할 수 있음
        console.log(error);
    })
    .finally(() =&gt; { // 성공실패 여부 상관없이 마지막에 호출 가능. 인자 따로 받지 않아도 ok
        console.log(&#39;finally&#39;);
    });
// 이렇게 consumer(메소드)를 사용하여 promise를 chaining</code></pre>
<p><font size =3><font color=grey>드림코딩by엘리 유튜브 무료강의 참고</font></font> </p>
<p></p>

<ul>
<li><p>new 키워드로 Promise 인스턴스가 만들어지는 &#39;순간&#39;, 콜백이 executing됨
즉, 생성 즉시 실행 (hoisting?된다)</p>
<pre><code class="language-js">const getHen = () =&gt;
  new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(&#39;🐓&#39;), 1000);
  });
const getEgg = hen =&gt;
  new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(`${hen} =&gt; 🥚`), 1000); // ⓐ
  //  setTimeout(() =&gt; reject(new Error(`${hen} =&gt; 🥚`)), 1000); ⓑ
  });
const cook = egg =&gt;
  new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(`${egg} =&gt; 🍳`), 1000);
  });</code></pre>
<p></p>
</li>
<li><p>resolve로 넘겨준 것이 없어도, 따로 반환<code>return</code>하는 것을 지정해주면 메소드로 chaining 가능 </p>
</li>
</ul>
<pre><code class="language-js">getHen() //
    .then(getEgg)
    .catch(error =&gt; { // !직전에서 발생한 에러를 캐치하고 싶을 때는 바로 다음에 catch
        return &#39;🥖 &#39; 
    }) // ! getEgg가 성공하지 않아도, return값을 지정하여 대신 전달해줘서 실패하지 않음(error뜨지 않음)
  // 위 producer 코드에서 ⓐ를 주석 처리, ⓑ를 주석해제한 다음
 // 이 consumer코드 실행 시 콘솔 출력값은 &quot; 🥖  =&gt; 🍳  &quot;
    .then(cook)
    .then(console.log)
    // 에러 핸들링하고 있지 않기 때문에 마지막에 걸어줌
    .catch(console.log)
// 콘솔 출력값 &quot;🐓 =&gt; 🥚 =&gt; 🍳 &quot; </code></pre>
<p><font size =3><font color=grey>드림코딩by엘리 유튜브 무료강의 참고</font></font> <p></p></p>
<blockquote>
<p>tip ＋</p>
</blockquote>
<pre><code class="language-js">getHen()
    .then(hen =&gt; getEgg(hen)) // .then(getEgg)로 줄일 수 있음. 한 가지 인자만 받아오는 경우엔.
    .then(egg =&gt; cook(egg))
    .then(meal =&gt; console.log(meal));</code></pre>
<br>
⏤
</br>


<h3 id="❖-async--await">❖ async &amp; await</h3>
<p>Promise의 경우에도 chaining이 길어지면 복잡하다.
Promise를 좀 더 간결하게, <strong>비동기를 동기적으로 실행되는 것처럼 (코드를) 보이게 만들어주는</strong> async&amp;await 조합을 사용
async와 await는 synctatic sugar이자 유용한 API이다.</p>
<p>＊경우에 따라 promise가 적합할 때가 있고, async &amp; await를 써야할 때가 있다.</p>
<p>  함수 앞에 async를 붙이고, async가 붙은 함수 내에서
  await를 쓸 수 있다.</p>
<p>  예제</p>
<pre><code class="language-js">function fetchUser() { // 서버에서 userdata를 받아오는 함수
// do network request in 10secs...
    return new Promise((resolve, reject) =&gt; {
        resolve(&#39;received&#39;); 
    }) 
}
// * async
async function fetchUser() {
    return &#39;received&#39;;
}
const user = fetchUser(); // ! 함수 선언된 곳으로 함수의 블럭 수행 한줄씩.. 10초 동안 머무름
console.log(user); // 동기적이라 위 함수호출 수행 완료 후 넘어오는 것
// 비동기적인 처리를 안하면 사용자정보를 가져오는 데 10초가 걸리는데
// 이 이후 웹페이지에 표시되는 UI 를 로드하는 코드가 있다면
// 사용자는 10초 동안 텅텅 빈 브라우저 화면을 봐야함
</code></pre>
<pre><code class="language-js">// * await
function delay(ms) {
    return new Promise(resolve =&gt; setTimeout(resolve, ms))
}

async function getApple() {
    await delay(1000); // delay(3000) 호출 (&#39;3초가 지나는 수행&#39;) 이 끝날 때까지 기다려
//  throw &#39;error&#39;; // &lt; catch 
    return &#39;🍎&#39;;
}

async function getBanana() {
    await delay(1000); // .then 역할
    return &#39;🍌&#39;;
}</code></pre>
<pre><code class="language-js">
async function pickFruits() {
          const apple = await getApple(); // ! delay(1000)
        const banana = await getBanana(); // ! delay(1000) 이 각 각 걸려있어(서로 상관없어 비동기적으로 이루어져도 됨)
    return `${apple} + ${banana}`;
}

pickFruits().then(console.log)</code></pre>
<p>  <font size =3><font color=grey>드림코딩by엘리 유튜브 무료강의 참고</font></font> 
  <p></p>
</p>

<ul>
<li>Promise.all
위 코드와 같이 사과를 받는 함수와 바나나 받는 함수와 서로 상관없이 동시다발적으로 이루어진다면? Promise.all이라는 api 사용
모든 프로미스객체가 병렬적으로 받아짐. (배열 등의 형태로 넘겨주고 리턴함)<pre><code class="language-js">function pickAllFruits() {
return Promise.all([getApple(), getBanana()]) // 배열로
    .then(fruits =&gt; fruits.join(&#39; + &#39;));
// ! 모든 프로미스들이 병렬적으로 다 받아질 때까지 기다림
// 배열 형태 등이 넘겨짐
}</code></pre>
<strong>→ Promise.all을 async &amp; await와 함께 사용하여 효율적 코드 작성</strong>.
＊Promise.race 도 있음, 가장먼저 수행결과값을 리턴하는 프로미스만 전달됨</li>
</ul>
<p><br></br></p>
<blockquote>
<p><font color=crimson>💡 Question
  다음 코드의 실행 순서는?</font></p>
</blockquote>
<pre><code class="language-js">const p = new Promise((resolve, reject) =&gt; {
  console.log(&quot;p&quot;);
  setTimeout(() =&gt; {
    resolve(&quot;res&quot;);
    console.log(&quot;res&quot;);
  }, 2000);
});
p.then((val) =&gt; {
  console.log(val + &#39;ⓐ&#39;); // ⓐ
});
console.log(&quot;here&quot;);
p.then((val) =&gt; {
  console.log(val + &#39;ⓑ&#39;); // ⓑ
});
/* 출력 값
p 
here 
res 
resⓐ 
resⓑ
*/</code></pre>
<table>
<thead>
<tr>
<th align="center">process⇪</th>
<th align="center">call stack</th>
<th align="center">Task Queue</th>
<th align="center">Web APIs</th>
</tr>
</thead>
<tbody><tr>
<td align="center">5</td>
<td align="center"><font color=crimson>console.log(val + &#39;ⓑ&#39;)</font></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center">4</td>
<td align="center"><font color=green>console.log(val + &#39;ⓐ&#39;)</font></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center">3</td>
<td align="center">console.log(&quot;res&quot;)</td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center"><font color=navy><strong>anonymous</strong></font><font color=grey><strong>*2000ms after</strong></font></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center"><font color=crimson>p.then ⓑ</font></td>
<td align="center"></td>
</tr>
<tr>
<td align="center">2</td>
<td align="center">console.log(&quot;here&quot;)</td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center"><font color=green>p.then ⓐ</font></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center">setTimeout(<font color=navy><strong>anonymous</strong></font>)</td>
</tr>
<tr>
<td align="center">1</td>
<td align="center">console.log(&quot;p&quot;)</td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"></td>
<td align="center"></td>
<td align="center">promise</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">*중요한 것은 비동기는 동기가 끝나고 작동한다는 것</td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
<tr>
<td align="center"><br></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
<p><a href="https://www.notion.so/ae8ad4a6a865472192e8edabbc8409f0">노션노트 참고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로토타입과 클래스]]></title>
            <link>https://velog.io/@sootulliyang_dev/%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EA%B3%BC-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@sootulliyang_dev/%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EA%B3%BC-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Tue, 15 Jun 2021 13:08:30 GMT</pubDate>
            <description><![CDATA[<p>참고
<a href="">[Code States]</a>
<a href="">[코어 자바스크립트 by 정재남 | 위키북스]</a></p>
<p>클래스와 프로토타입 이 둘은 자바스크립트의 객체지향 성격과 관련되어 있다.</p>
<h4 id="⚀-객체지향-프로그래밍">⚀ 객체지향 프로그래밍</h4>
<p>객체지향이란 하나의 모델(class)이 되는 청사진을 만들고 그것을 바탕으로 한 객체(instance object)를 만드는 프로그래밍 패턴. 일종의 패러다임.
절차적 프로그래밍이 불편함을 느껴, 보다 실제 기능과 코드가 닮아있는 즉 실생활 모습, 사람의 생각과 유사한 객체지향 프로그래밍으로 전향.</p>
<blockquote>
<p>❓ 자바스크립트는 객체지향 언어인가요
<strong>No.</strong> 하지만 객체지향 패턴으로 프로그래밍할 수 있다. 언어가 탄생된 방식은 객체지향이 아니다. ES6에서 도입.
<strong>자바스크립트는 프로토타입 기반 언어이다. __
클래스 기반 언어는 상속 inheritance를 사용하나 프로토타입 기반에서는 원형 객체를 참조함으로써 비슷한 효과를 지닌다. 이를 __프로토타입 체이닝</strong>을 통해 확인할 수 있다.
(참고) 리액트에서도 변할 수 있는 값인 this의 사용을 줄이고자 함수형 컴포넌트로 전환</p>
</blockquote>
<br>

<h3 id="⚁-클래스">⚁ 클래스</h3>
<h4 id="생성자-함수-constructor">생성자 함수 Constructor</h4>
<p>클래스는 모팔모가 칼을 찍어내는 거푸집(틀)이다. die 또는 mold이다.
생성자함수는 칼의 브랜드나 이름, 색상 등을 부여하는 parameter를 정의하는 것이다.</p>
<pre><code class="language-js">// 클래스 생성
class Student {
  constructor(name, age, enrolled, score) { // 생성자 함수로 속성 멤버 정의
    this.name = name; // this는 이 클래스 틀을 가지고 만들 인스턴스객체를 가리킴
    this.age = age;
    this.enrolled = enrolled;
    this.score = score;
  }
}
// new 연산자를 사용해 만든 인스턴스 객체를 요소로 갖는 배열
const students = [ 
  new Student(&#39;A&#39;, 29, true, 45), 
  new Student(&#39;B&#39;, 28, false, 80),
  new Student(&#39;C&#39;, 30, true, 90),
  new Student(&#39;D&#39;, 40, false, 66),
  new Student(&#39;E&#39;, 18, true, 88),
];
</code></pre>
<p>이렇게 생성자함수와 new 연산자를 사용해 생성한 각각의 인스턴스는 클래스의 고유한 속성과 메소드를 지니게 된다.
<a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Inheritance#ecmascript_2015_%ED%81%B4%EB%9E%98%EC%8A%A4">[(참고) MDN 공식문서의 클래스 상속 실습 예제]</a>
<img src="https://images.velog.io/images/sootulliyang_dev/post/ce38da8f-07aa-4d4b-acef-4ca76568d30e/%E1%84%8F%E1%85%B3%E1%86%AF%E1%84%85%E1%85%A2%E1%84%89%E1%85%B3%20%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%A5%E1%86%BC%E1%84%8C%E1%85%A1%E1%84%92%E1%85%A1%E1%86%B7%E1%84%89%E1%85%AE%20%E1%84%83%E1%85%A9%E1%84%89%E1%85%B5%E1%86%A8.png" alt=""><font size=3><font color=grey>(출처: 코어 자바스크립트 | CodeStates(재구성))</font></font></p>
<br>

<pre><code class="language-js">class Human {
  constructor(name, age) {
      // 속성
    this.name = name;
    this.age = age;
  }
// 메소드
  eat() { // 생략 // };
  sleep() { // 생략 //};
  :
  :
}

let human = new Human(&#39;Jay&#39;, 22);

Human.prototype.constructor === Human; // true
Human.prototype === human.__proto__; // true
Human.prototype.sleep === human.sleep; // true</code></pre>
<br>

<p>❗️ constructor가 자기자신을 참조하므로, 인스턴스객체의 원형객체를 찾을 수 있음을 위와 같이 확인할 수 있다.
❗️ 인스턴스 human의 ._<em>proto_</em>(속성, *객체임)를 통해 Human.prototype(객체)에 접근이(참조) 가능하다.</p>
<pre><code class="language-js">Human.prototype.constructor === human.__proto__.constructor
// 이것은 같은 주소를 가리킨다.</code></pre>
<p>❗️ .__proto__는 생략 가능하다. 따라서 인스턴스도 원형객체의 메소드를 마치 자신의 것처럼 쓸 수 있는 것이다.
이렇게 인스턴스에서는 __proto__속성을 거슬러 올라가보면 원형객체(클래스.prototype)에 도달한다.</p>
<p><font color=burgun><strong>✮ 프로토타입 기반 언어인 자바스크립트에서 클래스 상속을 잘 구현했다는 건 프로토타입 체이닝을 잘 연결한 것을 의미한다.</strong></font> <font color=grey>(이에 대한 샘플을 다음 프로토타입 문단의 콘솔창 스크린샷에서 확인해보자.)</font></p>
<br>

<blockquote>
<ul>
<li>속성은 속성끼리, 기능(메소드)은 기능끼리 모아서 실제 모습과 비슷하게 코드를 작성하는 것, 이것부터 <strong>캡슐화 encapsulation</strong> 라고 할 수 있다. </li>
</ul>
</blockquote>
<ul>
<li>클래스 내부에서 속성과 기능을 모아두었으니 이 class의 속성들은 해당 class 내부의 메소드로만 변경 가능하게 하는 것이 <strong>은닉화 hiding</strong>이다.</li>
<li>클래스 내부에서 정의한 메소드 등의 인터페이스, 이것이 <strong>추상화</strong>이다.
<font size=3><font color= grey>클래스 내부를 완벽히 만들면 그 이후엔 우리는 내부 구현에 더 이상 신경 쓰지 않고 보다 비즈니스 로직에 집중하면 되는 것이다.</font></font></li>
</ul>
<br>

<br>

<h3 id="⚂-프로토타입">⚂ 프로토타입</h3>
<p><strong>자바스크립트는 객체, 함수에(함수도 객체이다.) 자동으로 &quot;prototype객체&quot; 프로퍼티를 생성해놓는다.</strong></p>
<p>MDN에 따르면 이렇게 정의되어 있다.</p>
<ul>
<li>prototype(객체)의 속성은 <font color=navy><strong>상속시키려는 멤버(속성property, 메소드)들이 정의된 객체</strong></font>를 가리킨다.
<font color = grey>prototype <u>a property</u> containing an object on which you define memebers that you want to be inherited.</font></li>
<li>prototype객체는 <font color=navy><strong>(.\</strong>proto_<em>)속성으로 접근 가능한 내장 객체_</em></font>이다.</li>
</ul>
<p><img src="https://images.velog.io/images/sootulliyang_dev/post/c74c0cd2-d895-42ee-b7a2-3e4fd2362309/prototype%E1%84%80%E1%85%AA%20__proto__.png" alt=""><img src="https://images.velog.io/images/sootulliyang_dev/post/7bab998f-afb1-4451-b43c-3b7cc4aa3b70/new%20%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%89%E1%85%A1%E1%86%AB%E1%84%8C%E1%85%A1%E1%84%8B%E1%85%AA%20%E1%84%92%E1%85%A1%E1%86%B7%E1%84%81%E1%85%A6%20Constructor(%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%A5%E1%86%BC%E1%84%8C%E1%85%A1)%E1%84%92%E1%85%A1%E1%86%B7%E1%84%89%E1%85%AE%E1%84%85%E1%85%A9%20%E1%84%89%E1%85%A2%E1%86%BC%E1%84%89%E1%85%A5%E1%86%BC%E1%84%92%E1%85%A1%E1%86%AB%20instance%E1%84%8B%E1%85%B4%20__proto__%E1%84%82%E1%85%B3%E1%86%AB%20%E1%84%80%E1%85%A1%E1%87%80%E1%84%8B%E1%85%B3%E1%86%AB%20%E1%84%80%E1%85%A2%E1%86%A8%E1%84%8E%E1%85%A6%20%E1%84%8E%E1%85%A1%E1%86%B7%E1%84%8C%E1%85%A9.png" alt="">
객체나 배열의 생성자함수constructor 속성을 찾기 위해 살펴보면, _<em>proto_</em> 속성 안에서(하위) 찾을 수 있다.
<font color=burgun> constructor(생성자<strong>함수</strong>)의 프로퍼티인 prototype객체 내부에 &#39;constructor&#39; 프로퍼티가 또 있다. </font>
_<em>proto_</em> 속성 안에는 또 _<em>proto_</em> 속성이 있다. 
→ 여기서 우리는 클래스의 프로토타입, 원형 객체인 constructor 생성자함수가 자기 자신을 참조하는 것을 다시 한번 확인할 수 있고, 
따라서 클래스의 프로퍼티를 상속받은 실존 개체인 인스턴스에서 원형객체를 어떻게든 찾아갈 수 있는 것이다. ↩︎ </p>
<p><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes">[MDN 공식문서의 프로토타입 상속 실습 예제]</a></p>
<br>
<br>

<p>위 내용들의 근본은 
__ &quot; 기본적으로 모든 . _<em>proto_</em> 를 쫓아 올라가면 Object.prototype이 연결되어 있다&quot;__ 는 것이다.
임의의 배열 또한, Array의 prototype객체가 Object이기 때문이고, &quot;prototype객체&quot; 또한 &#39;객체&#39;이므로 그러하다.
이를 그림으로 표현하면 아래와 같다.
<img src="https://images.velog.io/images/sootulliyang_dev/post/3d811185-6824-4dbe-8429-97d4672ea435/%E1%84%91%E1%85%B3%E1%84%85%E1%85%A9%E1%84%90%E1%85%A9%E1%84%90%E1%85%A1%E1%84%8B%E1%85%B5%E1%86%B8%20%E1%84%83%E1%85%A9%E1%84%89%E1%85%B5%E1%86%A8_03.png" alt=""><font size=3><font color=grey>(출처: 코어 자바스크립트)</font></font></p>
<blockquote>
<h4 id="💪---advanced-issues">💪   advanced issues</h4>
<p>✘ constructor로 생성자 정보를 알아내기가 안전하지는 않음
✘ 어떤 클래스의 속성을 부여받은 인스턴스는 클래스프로토타입의 속성에 접근 가능 및 메소드 호출이 가능하지만, 클래스의 static 프로퍼티와 메소드에는 접근 불가
→ Array의 경우 static property로 length, static method로 isArray() 등. 
＊ .filter(), .map() 등의 메소드들은 prototype(객체) 내부의 속성이라 인스턴스가 호출 가능하다.
✘ 클래스 자체에 구체적인 데이터값을 지니지 않게 하는 방법
✘ 자바스크립트 엔진은 데이터 자신의 프로퍼티를 검색해서 원하는 메소드를 찾으면 해당 메소드를 실행하고, 없으면 .__proto__를 검색해서 실행하고, 없으면 다시 .__proto__를 검색하고 (...) 
→ 이것은 <strong>메서드 오버라이드</strong>와 관련되어 있다. 
현재 위치(객체)에서 접근 가능한 가장 가까운 메서드가 덮어씌워진다. ↩︎</p>
</blockquote>
<br>

<blockquote>
<p>🆘  리액트 과제에서의 source.soucre.src 사태를 프로토타입과 클래스에 대한 개념 정리로 정리할 수 있었다. R.I.P. ✞</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>