<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>0_right.log</title>
        <link>https://velog.io/</link>
        <description>차근차근 성장하는 개발자입니다</description>
        <lastBuildDate>Mon, 25 Mar 2024 10:09:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>0_right.log</title>
            <url>https://velog.velcdn.com/images/0_right/profile/ff221f14-9c65-4c5e-b260-696bd971acac/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 0_right.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/0_right" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Next에서 MSW]]></title>
            <link>https://velog.io/@0_right/Next%EC%97%90%EC%84%9C-MSW</link>
            <guid>https://velog.io/@0_right/Next%EC%97%90%EC%84%9C-MSW</guid>
            <pubDate>Mon, 25 Mar 2024 10:09:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/0_right/post/28d73595-1f9a-4901-93eb-75c53fe1f189/image.png" alt=""></p>
<h3 id="msw를-사용하는-이유">MSW를 사용하는 이유..</h3>
<p>현재 우리 회사에는 FE 개발자인 Dominick(나), BE 개발자이신 Kevin 이렇게 두명이 있다. 거기에 이 두명이서 관리하는 프로젝트가 5개가 있다.
여기서 이번에 프로젝트를 진행하기로 했는데 해당 프로젝트는 다음과 같다.</p>
<ul>
<li>외주를 통해 PHP로 개발된 협회 페이지 리뉴얼<ul>
<li>나와 Kevin은 둘 다 PHP 코드에 대해 익숙하지 않다.</li>
<li>우리 프로젝트의 대부분은 typeScript로 이뤄져 있다.</li>
<li>Angular를 학습하기에 리소스가 충분하지 않은 상황이다.</li>
</ul>
</li>
</ul>
<p>위와 같은 상황으로 인해 우리는 typeScript를 사용하여 NextJs로 프로젝트를 진행하기로 했다.
먼저 협회에서 사용하는 기능에 대해 파악을 전체적으로 진행했고, 파일 구조를 잡았다. 이제 개발에 들어가려고 하는데, 다른 프로젝트에서 서버단에서 오류가 나면서 BE 개발이 지연되는 상황에 쳐했다. 나는 해당 부분을 ClubStudy에서 프로젝트를 진행하면서 겪었고, 그 문제를 해결하기 위해 MSW를 협회 사이트에 적용시키려 했다.</p>
<p>하지만 인간은 망각의 동물이라 했나.... ClubStudy를 진행할 때 Next -&gt; React로 마이그레이션한 이유를 까먹고있었다.</p>
<blockquote>
<p>Next 안녕
<a href="https://velog.io/@0_right/TIL-23.03.13">https://velog.io/@0_right/TIL-23.03.13</a></p>
</blockquote>
<p>저때는 나도 개발을 시작한지 초창기였고, 리서칭이나 해결하는 방법이 무식했던 것 같다. 이번에는 달라졌다는 것을 느낄 수 있게 한번 해결해보려고 했다.</p>
<h4 id="문제점">문제점</h4>
<ul>
<li><p>NEXT는 CORS에러 해결을 위해 rewrite()이라는 기능을 이용해서 API 주소를 숨겨서 해결할 수 있는데, 나도 해당 기능을 사용하고 있었다.</p>
</li>
<li><p>해당 기능을 통해서 우리의 코드를 보면 아래의 순서대로 이뤄진다.</p>
<pre><code>  1. &lt;FE url&gt;/api/v1/rfidGet 호출
  2. Next reWrite()
  3. &lt;BE url&gt;/api/v1/rfidGet 호출
  4. FE에 &lt;BE url&gt;/api/v1/rfidGet return
  4. 브라우저에 &lt;BE url&gt;/api/v1/rfidGet return</code></pre></li>
<li><p>같은 API를 호출하더라도 환경에 따라서 브라우저 환경에서는 <FE url>로 로컬 환경에서는 <BE url>로 호출하기에 위와같은 에러가 발생했다.</p>
</li>
<li><p>해당 부분을 해결한 다른 분의 코드를 참조했다.</p>
<pre><code>// MockRestClient는 RESTful API 작업을 Mocking하기 위한 Client
const MockRestClient = (() =&gt; {
    // 환경(서버/클라이언트)에 따라 적절한 URL을 반환하는 함수
    const resolveURL = (url: string): string =&gt; {
        if (typeof window === &quot;undefined&quot;) {
            // 노드 환경이면 서버 URL을 붙여서 반환한다.
            return `${서버주소}${url}`;
        }
        // 클라이언트 환경이면 그대로 반환한다.
        return url;
    };

    // 주어진 URL이 FULL URL인지 확인하는 함수
    const isExternalUrl = (url: string): boolean =&gt; {
        return url.match(/^(https|http)/g) !== null;
    };

    // Mocking API URL을 정재하여 반환하는 함수
    const getMockApiUrl = (url: string): string =&gt; {
        // 외부 URL이면 그대로 반환하고 아니면 Mocking API URL로 변환하여 반환한다.
        return isExternalUrl(url) ? url : resolveURL(url);
    };

    // Mocking API를 위한 Client
    const _mockRestClient: IMockRestClient = {
        get: (url, resolver) =&gt; rest.get(getMockApiUrl(url), resolver),
        post: (url, resolver) =&gt; rest.post(getMockApiUrl(url), resolver),
        put: (url, resolver) =&gt; rest.put(getMockApiUrl(url), resolver),
        patch: (url, resolver) =&gt; rest.patch(getMockApiUrl(url), resolver),
        delete: (url, resolver) =&gt; rest.delete(getMockApiUrl(url), resolver),
        options: (url, resolver) =&gt; rest.options(getMockApiUrl(url), resolver),
    };

    return _mockRestClient;
})();</code></pre><ul>
<li>local 환경일 때는 <BE url>을 반환하고, 브라우저 환겨일 경우에는 <FE url>을 반환하도록 설정했다.</li>
<li>해당 부분을 해결한 뒤 현재는 프로젝트가 잘 마무리 되어서 현재 LIVE 되었다!!</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[# 프레임워크 선택]]></title>
            <link>https://velog.io/@0_right/%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%84%A0%ED%83%9D</link>
            <guid>https://velog.io/@0_right/%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%84%A0%ED%83%9D</guid>
            <pubDate>Fri, 08 Dec 2023 02:43:41 GMT</pubDate>
            <description><![CDATA[<h1 id="프레임워크">프레임워크</h1>
<ol>
<li><p>React</p>
<pre><code class="language-jsx"> React란 &quot;지속적으로 데이터가 변화하는 대규모 애플리케이션 구축&quot;, 오로지 VIEW만 담당하는 라이브러리</code></pre>
<ul>
<li><p>언어 : JavaScript &amp; TypeScript</p>
</li>
<li><p>장점</p>
<ul>
<li><p>자바스크립트의 문법을 그대로 사용함</p>
</li>
<li><p>컴포넌트를 비교적 더 간단하고 단순하게 정의 가능함</p>
</li>
<li><p>성능이 뛰어난 garbage collector, 메모리 관리 기능 제공</p>
</li>
<li><p>UI 수정과 재사용성이 좋으며, 코드 가독성을 높일 수 있다.</p>
</li>
<li><p>사용자가 많고, 역시 Facebook에서 만들었다보니 확실히 커뮤니티나 자료가 굉장히 방대하다.</p>
</li>
<li><p>Component를 사용해서 효율적으로 재사용이 가능하고 높고 유지보수가 용이</p>
<pre><code class="language-jsx">  Component는 UI를 구성하는 개별적인 뷰 단위로 전체 앱은 각 Component들이 결합해서 만들어 지게 되는데 무엇보다 각 Component들은 앱의 다른 부분, 
  또는 다른 앱에서 쉽게 재사용이 가능하다. Redux의 창시자이며, 현재는 Facebook React Core팀의 일원인 Dan Abramov는 
  React의 목표가 성능보다는 유지가능한 앱을 만드는 것에 있다고 설명한다.</code></pre>
</li>
<li><p>가상 돔 (Virtual DOM)</p>
<pre><code class="language-jsx">  가상 돔이란 렌더링 과정에서 리플로우와 리페인트가 자주 수행되는 문제를 해결하기 위해 화면에 표시되는 DOM과 동일한 DOM을 메모리상에 만들고 
  DOM 조작이 발생하면 메모리상에 생성한 가상 돔에 모든 연산을 수행한 후, 실제 DOM을 갱신하여 리플로우/리페인트 연산을 최소화 하는 것이다.</code></pre>
</li>
<li><p>단방향 데이터 바인딩</p>
<pre><code class="language-jsx">  단방향 데이터 바인딩은 단 하나의 Watcher가 자바스크립트의 데이터 갱신을 감지하여 사용자의 UI 데이터를 갱신합니다. 
  사용자가 UI를 통해 자바스크립트의 데이터를 갱신할 때는, 이벤트를 통해 갱신하게 됩니다. 
  이처럼 단방향 데이터 바인딩은 하나의 Watcher를 사용하기 때문에 양방향 데이터 바인딩이 가지는 성능적인 이슈를 해결하고 더 확실하게 데이터를 추적할 수 있게 해줍니다.</code></pre>
</li>
<li><p>Hook</p>
<pre><code class="language-jsx">  함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수입니다. Hook은 class 안에서는 동작하지 않습니다. 대신 class 없이 React를 사용할 수 있게 해주는 것입니다.</code></pre>
</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li><p>(치명적) 로딩시간이 길.</p>
</li>
<li><p>데이터 모델링, 라우팅, Ajax 등 기능이 지원 안된다.</p>
</li>
<li><p>IE8 이하 버전은 지원하지 않는다.</p>
</li>
<li><p>프레임워크의 MVC 와 비교하였을때 V(View)만을 관리한다.</p>
<pre><code class="language-jsx">  View 부분만을 관리하기 때문에 다른 부분은 써드파티 라이브러리(Third party library, 패키지)를 이용하거나 직접 구현해야한다.</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Angular</p>
<pre><code class="language-jsx"> Angular란 확장가능한 컴포넌트 구조로 웹 애플리케이션을 만드는 프레임워크입니다.
 라우팅, 폼 관리, 클라이언트-서버 통신 등 웹 개발에 필요한 라이브러리를 조화롭게 통합한 모음집입니다.
 완전한 프레임 워크로, 프로젝트의 생성, 테스트, 빌드, 배포를 위한 모든 기능을 제공합니다.</code></pre>
<ul>
<li><p>언어 : TypeScript</p>
</li>
<li><p>장점</p>
<ul>
<li><p>Angular CLI를 제공하여 개발환경을 지원합니다. 파일 생성, 빌드, 패키징, 라이트 서버 기능 등 개발에 필요한 거의 모든 기능을 자체적으로 제공합니다.</p>
</li>
<li><p>모듈과 컴포넌트 기반으로 동작합니다.</p>
</li>
<li><p>유지 관리가 용이하다.</p>
<pre><code class="language-jsx">  코드 유지 관리 성을 높이기 위해 TypeScript를 사용하고, (일단은) 당분간은 안정적으로 지속적인 기술 지원이 이루어지고 있기 때문에 유지 측면에서 장점이 있습니다.</code></pre>
</li>
<li><p>Angular-cli</p>
<pre><code class="language-jsx">  프로젝트 생성을 도와줍니다. 명령어 하나로 프로젝트를 생성하고 알아서 모든 의존성 패키지를 함께 설치해줍니다. 
  모듈/컴포넌트/디렉티브/서비스 등을 생성하는 역할 또한 Angular cli로 할 수 있습니다.
  라이트 한 서버를 제공합니다. 별다른 설정에 대한 노력 없이 간단하게 서버를 실행하여 개발을 진행할 수 있습니다. 코드를 수정하면 즉시 변경사항이 반영되어 웹페이지에서 렌더링 됩니다. 
  Node.js의 nodemon이나 기존 client의 livereload와 비슷하게 생각하면 될 것 같습니다.
  기본적으로 Webpack을 내장하고 있으며 알아서 빌드까지 수행합니다. Typescript를 컴파일하고 자바스크립트를 압축하는 것까지 자동으로 해주며, (저와 같이) 웹팩에 대한 지식이 전혀 없어도 사용 가능합니다.
  테스트도 할 수 있어요!</code></pre>
</li>
<li><p>양방향 데이터 바인딩</p>
<pre><code class="language-jsx">  모델 상테는 해당 UI 요소의 모든 변경 사항을 반영합니다. 반대로 UI 상태는 모델 상태의 모든 변경 사항을 바인딩합니다.
  =&gt; 이 기능을 통해 프레임워크에서 컨트롤러를 통해 DOM을 모델 데이터에 연결 할 수 있습니다.</code></pre>
</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li><p>학습 곡선</p>
<pre><code class="language-jsx">  앵귤러는 &quot;내가 너희를 위해 모든 것을 제공 하노라!&quot; 라는 정신으로 무장한 건지, 정말 소소한 것들에 대해서까지 많은 것을 제공합니다. 애초에 시작 시점에 배워야 하는 것들이 많긴 합니다.
  처음 접근을 위해서 뭔가 공부해야 할 사항이 늘어나는 것 같습니다.
  Angular CLI, Typescript, Module, Component, RxJS, Form, Router, Pipe, directive...

  초반에 접근하기 매우 어려운 프레임 워크이다.</code></pre>
</li>
<li><p>용량</p>
<pre><code class="language-jsx">  프레임워크답게, 기본적으로 앵귤러 프로젝트를 생성하면 기본 폴더 용량이 어마어마합니다. (대부분의 용량은  node_modules가 차지합니다)
  물론 빌드 후 결과물은 작습니다만, 어쨌든 처음 접근을 위해서는 꽤나 많은 자원을 필요로 합니다.</code></pre>
</li>
<li><p>업데이트 관리</p>
<pre><code class="language-jsx">  Angular는 업데이트 주기가 빠르고 업데이트에 따라 코드를 변경해야 할 수도 있습니다.</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Vue</p>
<pre><code class="language-jsx"> Vue( view 와 마찬가지로 /vjuː/ 라고 발음합니다 )는 사용자 인터페이스를 구축하기 위한 JavaScript 프레임워크입니다. 
 표준 HTML, CSS 및 JavaScript를 기반으로 구축되며, 단순한 것 부터 복잡한 것 까지 사용자 인터페이스를 효율적으로 개발할 수 있는 컴포넌트 기반 프로그래밍 모델을 제공합니다.</code></pre>
<ul>
<li><p>언어 : JavaScript</p>
</li>
<li><p>장점</p>
<ul>
<li>학습 곡선 : 매우 쉽다.</li>
<li>속도가 빠르다</li>
<li>가상DOM을 사용하여 렌더링 성능 향상 : React와 동일</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li><p>만들어진지 얼마 되지 않아서 커뮤니티가 작다.</p>
</li>
<li><p>성능 이슈</p>
<pre><code class="language-jsx">  가상 돔 기반의 성능 최적화는 대부분의 상황에서 효과적이지만, 매우 큰 규모의 애플리케이션에서는 성능에 제약이 있을 수 있다.</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Next</p>
<pre><code class="language-jsx"> Next.js는 React 기반의 웹 프레임워크로, 웹 애플리케이션 및 웹 사이트를 개발하기 위한 도구와 기능을 제공한다.
 특히 서버 사이드 렌더링 (SSR) 및 정적 사이트 생성 (SSG)과 같은 고급 기능을 지원하여 성능 최적화 및 검색 엔진 최적화 (SEO)를 향상시키는 데 도움이 된다</code></pre>
<ul>
<li><p>언어 : TypeScript</p>
</li>
<li><p>장점</p>
<ul>
<li><p>서버 사이드 렌더링(SSR) 및 정적 사이트 생성(SSG) 지원</p>
<pre><code class="language-jsx">  성능 향상과 검색 엔진 최적화(SEO)를 위한 SSR 및 SSG를 쉽게 구현할 수 있다.</code></pre>
</li>
<li><p>간편한 라우팅 : 파일 시스템 기반의 라우팅 구조로 쉽게 페이지를 생성하고 관리할 수 있습니다.</p>
</li>
<li><p>데이터 가져오기</p>
<pre><code class="language-jsx">  getServerSideProps 또는 getStaticProps와 같은 메서드를 사용하여 데이터를 가져와 페이지에 주입할 수 있다. 
  이는 서버 사이드 렌더링 및 정적 사이트 생성과 함께 사용된다.</code></pre>
</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li><p>초기 학습 곡선</p>
<pre><code class="language-jsx">  React와 함께 사용되므로 React에 익숙하지 않은 개발자에게는 초기 학습 곡선이 존재할 수 있다.</code></pre>
</li>
<li><p>복잡한 설정</p>
<pre><code class="language-jsx">  프로젝트의 규모가 커질수록 구성 및 설정이 복잡해질 수 있다.</code></pre>
</li>
<li><p>서버 요구사항</p>
<pre><code class="language-jsx">  SSR을 사용할 때 서버 리소스가 필요하므로 서버 비용이 증가할 수 있다.</code></pre>
</li>
<li><p>데이터 가져오기 복잡성</p>
<pre><code class="language-jsx">  데이터 가져오기 메서드를 사용할 때 몇 가지 복잡성이 발생할 수 있으며, 특히 초기 설정이나 오류 처리 관점에서 주의가 필요하다.</code></pre>
</li>
<li><p>프레임워크 종속성</p>
<pre><code class="language-jsx">  Next.js는 React에 의존하므로 React와 함께 업데이트 및 유지 관리되어야 한다.</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<h1 id="angular-react-vue-중-선택애야-하는-경우">Angular, React, Vue 중 선택애야 하는 경우</h1>
<p><strong>■ 앵귤러를 선택해야 하는 경우</strong></p>
<ul>
<li>기능이 풍부하고 규모가 큰 애플리케이션을 개발할 때</li>
<li>믿을 수 있고 확장 가능한 프레임워크가 필요할 때</li>
<li>채팅 앱이나 메시징 앱과 같은 실시간 애플리케이션을 개발할 때</li>
<li>장기프로젝트이며, 투자규모도 상당한 네이티브 앱이나 하이브리드 앱, 또는 웹앱을 개발할 때</li>
<li>타입스크립트(TypeScript)로 코딩해야 할 때</li>
<li>객체지향(Object-oriented)프로그래밍을 해야 할 때</li>
</ul>
<p><strong>■ 리액트를 선택해야 하는 경우</strong></p>
<ul>
<li>빠른 일정 안에 엔터프라이즈 수준의 가벼우면서도 현대적인 애플리케이션을 개발해야 할 때</li>
<li>웹사이트 개발 솔루션을 안전하게 보호할 수 있는 유연한 프레임워크가 필요할 때</li>
<li>크로스 플랫폼(cross-platform) 애플리케이션이나 싱글 페이지 애플리케이션(SPA)을 개발할 때</li>
<li>기존의 앱에서 기능성을 확장할 때</li>
<li>강력한 커뮤니티 지원과 솔루션이 필요할 때</li>
</ul>
<p><strong>■ 뷰를 선택해야 하는 경우</strong></p>
<ul>
<li>시장 진입 단계에서 필요한 프레임워크를 선택할 때</li>
<li>작고 가벼운 애플리케이션을 개발할 때</li>
<li>기존의 프로젝트에서 현대적이지만 제한된 리소스를 가진 프레임워크로 마이그레이션을 해야할 때</li>
<li>기업이 아니라 사용자 커뮤니티의 지원을 받는 프레임워크를 원할 때</li>
</ul>
<h2 id="next-와-react">Next 와 React</h2>
<h3 id="■-next"><strong>■ NEXT</strong></h3>
<ul>
<li>최고의 서버 측 렌더링 및 정적 웹 사이트 개발 솔루션을 제공한다.</li>
<li>다양한 도구와 기능으로 프로젝트를 쉽게 관리할 수 있다.</li>
<li>웹 애플리케이션을 만들고 서버 측 렌더링을 수행하는 데 사용된다.</li>
<li>React 라이브러리를 사용하여 웹 앱용 UI 및 페이지를 빌드하는 데 사용되는 <code>프레임워크이다</code>.</li>
</ul>
<h3 id="■-react"><strong>■ REACT</strong></h3>
<ul>
<li>SPA용 UI를 개발하는 데 가장 적합한 선택이다.</li>
<li>모바일 및 웹 앱 레이어와 함께 작동한다.</li>
<li>DOM을 향한 렌더링에 중점을 둔다.</li>
<li>클라이언트 측 렌더링을 제공하여 애플리케이션 성능을 향상 시킨다.</li>
<li>라이브러리로, UI 구성 요소 부분인 프레임워크의 일부분이다.</li>
</ul>
<p>⇒ <strong>Next.js는 <code>개발 프로세스를 최소화하기 위한 다양한 도구와 기능을 제공</code></strong>하는 반면 <strong>React.js는 <code>모바일 및 웹 애플리케이션의 프런트 엔드 개발을 위한 더 나은 리소스를 제공</code></strong>합니다.</p>
<h3 id="내가-선택한-프레임-워크">내가 선택한 프레임 워크</h3>
<ul>
<li>Angular
학습에 어려움이 있어 빠른 기간 내에 체득하기 어려워 순위에서 가장 후순위
또한 채팅 앱이나 메시징 앱을 개발을 하는 것이 아님.</li>
<li>Vue
학습에 있어서 귀운 모습을 보이지만, 페오펫의 애플리케이션은 점점 커져갈 것이기 때문에  작고 가벼운 애플리케이션과 맞지 않다고 생각이 듦
규모가 커질수록 가상 돔 + 양방향 데이터 바인딩에 의해 성능이 크게 저하될 수 있음.</li>
</ul>
<p>해당 사항을 통해 React와 Next 둘 중 하나로 생각이 좁혀 졌고, 이번에 Next의 새로운 버전인 14가 자세히 조사해 보니 기존 함수는  사용할 수 있게 해놨고, 추가적인 업데이트에 php 처럼 front에서 sql문을 조작할 수 있게 만들어 놔서 논란이 됨.
 =&gt; 즉 해당 sql문 조작 부분을 사용하지 않으면 기존 코드를 사용할 수 있으며, 성능도 매우 빨라진 모습을 보여줘 호평을 받고 있음.
그래서 개인적인 생각으로는 오류를 최대한 잡아줄 수 있는 TypeScript와 속도나 성능면에서 많이 개선이 된 NextJs를 쓰는 것이 좋을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[23.11.27 4달만에...]]></title>
            <link>https://velog.io/@0_right/23.11.27-4%EB%8B%AC%EB%A7%8C%EC%97%90</link>
            <guid>https://velog.io/@0_right/23.11.27-4%EB%8B%AC%EB%A7%8C%EC%97%90</guid>
            <pubDate>Mon, 27 Nov 2023 05:53:01 GMT</pubDate>
            <description><![CDATA[<h2 id="취업">취업</h2>
<p><code>취업을 하고 그동안 있었던 일</code></p>
<ul>
<li>나는 프리 A 단계에 있는 스타트업에 취업을 했다. 회사 개발 팀에는 팀장, 백앤드, 프론트(나) 로 3명의 개발자로 구성돼있다. 회사에는 총 5가지의 프로젝트가 있으며, 각각 문제가 많이 있다.<pre><code>a,b,c,d,e로 나누어서 설명하겠다.
a는 메인페이지 b는 커머스 몰 c는 어드민 페이지 d,e 는 각 b2b 페이지이다.
</code></pre></li>
</ul>
<p>우선 a ~ e 모두 코드가 정리가 안되어 있으며, 사용하지 않는 코드가 매우 많이 존재한다. 또한 오류도 많아서 4달동안 업무의 70%가 유지 보수 및 코드 파악이었다.</p>
<p>우선 d,e는 베트남에 외주를 맡겨서 코드를 짰다고 했는데, async awiat 비동기 함수 내에 setTimeOut을 사용한다던가 이해할 수 없는 코드 구조로 작성이 되어있으며, 또한 UI로는 구현 되어있지만 사용 못하는 기능이 여러 존재한다는 문제점이 있다.</p>
<p>그 다음으로 c는 코드구조가 괜찮다고 느껴졌다. 그중에 문제점이라면 어드민 페이지이다 보니, 회사의 다른 팀에서 요청한 기능을 넣어야해서 급하게 코드를 짠게 보이는 느낌이다.</p>
<p>이제 가장 큰 문제인 a,b가 남았다. 
우선 현재 b는 모든 코드가 php/html을 사용하고 있다. 해당 코드를 알지 못하다 보니, 어떤 구조로 코드가 짜여져있는지 확인할 수 없었고, 운영 팀의 많은 요구를 들어주기 어려웠다.</p>
<p>또한 a는 메인 페이지이다 보니, 여러 기능이 있고, 코드가 분리 되어있지 않아서. 한개를 수정하면 다른곳에서 에러가 터지는 현상이 자주 발생했다. 또한, 한개의 파일에만 같은 코드를 조건에 따라 3항연산자를 4개를 쓴 엄청난 비효율적인 코드가 존재한다.</p>
<p>이번에 개발팀에서 회의 결과, a,b를 통합 이전을 하기로 했고, 그러기 위해 나는 다시 리팩토링을 시작해야한다.</p>
<p>```</p>
<ul>
<li>이번 리팩토링은 실제 많은 고객들이 사용하고 있는 페이지를 만드는 것이기 때문에 철저하게 학습을 하고 리팩토리에 들어갈까 한다. </li>
<li>그러기 위해서 나는 오늘부터 책 2권을 읽으며 학습한 뒤에 코드 이사를 가기전에 미리 가장 간단한 마이페이지 부분을 리팩토링에 들어가려한다.</li>
<li>책의 목록은 (구글 엔지니어는 이렇게 일한다, 리팩토링 2판)이다. </li>
<li>최근 유지 보수만해서 나는 해당 회사에 와서 개인의 성장을 많이 느끼지 못하고 있어서 아쉬웠는데. 이번 기회를 통해 많은 성장을 이룰 수 있을거 같아 기대가 된다. 화이팅 해보자!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 23.07.10]]></title>
            <link>https://velog.io/@0_right/TIL-23.07.10</link>
            <guid>https://velog.io/@0_right/TIL-23.07.10</guid>
            <pubDate>Mon, 10 Jul 2023 10:18:30 GMT</pubDate>
            <description><![CDATA[<h3 id="최근들어-느낀-점들">최근들어 느낀 점들</h3>
<ul>
<li>요즘 나는 여러 회사에 면접과 과제 테스트를 보고 있다. 그러다 보니 자소서와, 포트폴리오 관리에만 매달려 있던 것 같다. (정작 중요한 건 안하고..)</li>
<li>물론 위에 것을 신경 쓰니 전과는 다르게 서류에서 많이 합격하는 것 같았다.</li>
<li>하지만 중요한 기본기(JS, CS) 등을 준비를 덜한 상태로 면접과 과제 테스트를 마주하니 떨어질 수 밖에 없던것 같다.</li>
<li>오늘 부터 다시 JS와 CS등 공부를 시작하려한다. (모든지 꾸준함이 중요한 법)</li>
<li>TIL은 평일엔 최대한 매일 쓰려고 노력할 것이다.</li>
</ul>
<h3 id="앞으로-할-것">앞으로 할 것</h3>
<ul>
<li>우선 이번 과제 테스트에서 useEffect useCallback을 사용하여 Data를 불러오는 것은 성공 했지만, 그 뒤에 데이터를 사용하는데 어려움을 느꼈다. 이에 대해 공부할 것이다.</li>
<li>또한 Promise async await을 제대로 알지 못한 상태로 사용하니 많이 버벅였던 것 같다.</li>
<li>redux와 같은 상태관리 라이브러리에 관심을 가져야 할 것 같다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻TIL 23.05.22]]></title>
            <link>https://velog.io/@0_right/TIL-23.05.22</link>
            <guid>https://velog.io/@0_right/TIL-23.05.22</guid>
            <pubDate>Mon, 22 May 2023 13:17:54 GMT</pubDate>
            <description><![CDATA[<h1 id="1-mui-theme-사용하기">1. Mui theme 사용하기</h1>
<h3 id="mui에서-theme이란">Mui에서 theme이란</h3>
<ul>
<li><p>Theme에는 공통으로 사용하는 스타일 내용을 <code>정의해둔 Object</code>이다. </p>
<pre><code>  palette: {
    primary: {
      main: &#39;#000000&#39;,
    },
    secondary: {
      main: &#39;#DCFC73&#39;,
    },
    thirdly: {
      main: &#39;#939393&#39;,
    },
    fourth: {
      main: &#39;#D9D9D9&#39;,
    },
  },
</code></pre></li>
<li><p>위와 같이 theme의 palette에 색을 정의를 해두고 mui component를 사용할 때 필요한 color를 palette에서 꺼내 쓰는 것이다.</p>
</li>
<li><p>또한 Typography의 스타일을 정의 할 수 있다.</p>
<pre><code>typography: {
    h1: { fontSize: &#39;2.5rem&#39;, fontWeight: &#39;bold&#39; },
    h2: { fontSize: &#39;2.00rem&#39;, fontWeight: &#39;bold&#39; },
    h3: { fontSize: &#39;1.75rem&#39;, fontWeight: &#39;bold&#39; },
    h4: { fontSize: &#39;1.63rem&#39;, fontWeight: &#39;bold&#39; },
    h5: { fontSize: &#39;1.50rem&#39;, fontWeight: &#39;bold&#39; },
    subtitle1: { fontSize: &#39;1.38rem&#39; },
    subtitle2: { fontSize: &#39;1.25rem&#39; },
    subtitle3: { fontSize: 16 },
    body1: { fontSize: &#39;1.13rem&#39; },
    body2: { fontSize: &#39;1.00rem&#39; },
 }</code></pre><pre><code>&lt;Typography
  sx={(theme) =&gt; ({
  color: theme.palette.primary.main,
  typography: [&#39;h4&#39;, &#39;h4&#39;, &#39;h5&#39;, &#39;h3&#39;],
  })}
&gt;</code></pre></li>
<li><p>theme에 Typography를 정의하고 Typography를 사용할 때 sx prop을 사용해서 Typography의 설정 값을 지정해주는 것이다.</p>
</li>
<li><p>위의 코드는 &#39;색은 theme의 primary.main(즉, #000000)을 사용하고 typography는 breakpoint에 따라 (h4, h4, h5, h3)로 그려라.&#39; 라는 뜻이다.</p>
</li>
</ul>
<h3 id="typography-highlight-표시">Typography highlight 표시</h3>
<ul>
<li>MUI typography에서는 있을 수도 있지만, 적어도 내가 찾아본 문서에서는 따로 highlight 기능이 없었다. 그래서 어떻게 하면 만들 수 있을까를 생각했고, 검색해보니 생각보다 간단했다.</li>
<li>Typography의 boxShadow를 통해 색을 집어넣고, shadow의 크기를 설정하면 된다.<pre><code>&lt;Typography
  sx={(theme) =&gt; ({
  color: theme.palette.primary.main,
  fontWeight: &#39;600&#39;,
  fontSize: [&#39;16px&#39;, &#39;18px&#39;, &#39;20px&#39;, &#39;20px&#39;],
  boxShadow: `inset 0 -15px 0 ${theme.palette.secondary.main}`,
  })}
&gt;</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.04.18]]></title>
            <link>https://velog.io/@0_right/TIL-23.04.18</link>
            <guid>https://velog.io/@0_right/TIL-23.04.18</guid>
            <pubDate>Mon, 24 Apr 2023 05:43:22 GMT</pubDate>
            <description><![CDATA[<h2 id="❗-문제점">❗ 문제점</h2>
<ul>
<li>삭제 버튼을 눌렀을 때 팝업이 나온다.</li>
<li>팝업에서 동의 버튼을 누르면 api.post를 통해 삭제를 요청한다.</li>
<li>삭제 요청이 가면 해당 리스트의 삭제 버튼이 사라지고 리스트 상태 : 삭제가 표시되어야 한다.</li>
</ul>
<p>위 3가지가 내가 현재 만들고 있는 프로세스인데, 1,2번은 잘 작동이 된다. 하지만 re-rendering이 되지 않는 문제를 가지고 있다.</p>
<h3 id="해결-방법-생각">해결 방법 생각</h3>
<ol>
<li>동의 버튼을 누르면 api.post를 보내고 location.reload()를 사용하여 새로고침한다.</li>
<li>api.get을 한번 더 실행한다.</li>
</ol>
<p>우선 데이터를 새로 받기 위해 페이지를 새로 고침하는 것은 사용자로 하여금 많은 <code>불편함</code>을 야기한다. 그래서 제외하고 2번째 방법을 선택했다.</p>
<pre><code>
// index.tsx

api.get(apply)
&lt;ApplyProcess/&gt;
applyStudys.map((applyStudy)=&gt;{
    &lt;ApplyStudy applyStudy={applyStudy} /&gt;
}
--------------------------------------------

//ApplyStudy.tsx

const ApplyStudy = () =&gt; {
    &lt;ApplyStudyList&gt;
        &lt;ApplyTitle&gt;
        &lt;/ApplyTitle
        &lt;InnerContent/&gt;
    &lt;/ApplyStudyList&gt;
}
function InnerContent(){
    다른 상태들
    &lt;show &amp;&amp; &lt;CancleFunction applyStudy = {applyStudy}/&gt;
}
function CancleFunction(){
    &lt;버튼/&gt;
    &lt;팝업/&gt;
}
</code></pre><p>현재 대략적인 나의 코드이다. 그렇다면 2번 해결책을 하기 위해서는 ApplyStudy.tsx의 function CancleFunction에 있는 팝업에서 동의 버튼을 눌렀을 때 index.tsx의 api.get을 다시 실행해줘야 한다.</p>
<p>이를 위해 나는 처음 팝업에서 동의 버튼을 눌렀을 때 canclefunction에서 api.get을 실행시켰다. 당연하게도 re-rendering은 실행되지 않았다. 왜냐하면 부모에서 내려온 props를 자식에서 다시 get한다고 해서 redering이 되는 것이 아니기 때문이다.</p>
<p>그래서 나는 생각을 해봤다. 어떻게하면 부모에서 동의 버튼을 눌렀다는 것을 인지하고 다시 렌더링할 수 있을까?</p>
<p>=&gt; 고민에 대한 답을 생각하는데 시간이 걸렸지만, 만약 ApplyStudy에 <code>refresh 함수</code>를 내려주고 해당 함수를 동의 버튼을 눌렀을 때 실행시키면 되지 않을까?라는 생각을 하였고, 해당 생각을 통해 문제를 해결했다.</p>
<p>refresh 코드는 이렇다</p>
<pre><code>  const refreshStudyStatus = async () =&gt; {
    const refreshStudy = await api.getApplyStudy();
    setApplyStudys(refreshStudy);
  };</code></pre><p>해당 함수를 통해서 applyStudy를 가져와서 setState를 통해 다시 랜더링하게 되는 것이다.
하지만 다른 문제가 발생했는데, 현재 해결이 된 부분은 MSW을 사용하고 있는 local 환경에서는 해결이 됐지만, 왜그러는지 모르겠는데 배포를 한 뒤, 다시 테스트를 진행해 봤는데 똑같이 렌더링이 다시 되지 않는 문제가 발생했다. 이 부분은 다음 주에 해결해 볼 생각이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🤔 앞으로의 계획]]></title>
            <link>https://velog.io/@0_right/%EC%95%9E%EC%9C%BC%EB%A1%9C%EC%9D%98-%EA%B3%84%ED%9A%8D</link>
            <guid>https://velog.io/@0_right/%EC%95%9E%EC%9C%BC%EB%A1%9C%EC%9D%98-%EA%B3%84%ED%9A%8D</guid>
            <pubDate>Tue, 18 Apr 2023 07:16:45 GMT</pubDate>
            <description><![CDATA[<h3 id="🥺-현재">🥺 현재</h3>
<p>지금의 나는 주니어 개발자로, 친구와 함께 학교 동생의 Start-up의 웹 Front-end를 맡아 개발중이다. 처음 이 일을 하겠다고 한 이유는, 나의 첫 프로젝트이자, 처음으로 협업을 할 수 있는 기회였기 때문이다. 이 기회를 토대로 경험을 쌓아 다른 기업에 취업을 할 생각이었다(물론 동생과도 얘기가 된 부분). </p>
<p>하지만 생각보다 해당 페이지에 애정도 갖게 되었고, 수익이 창출이 되면서 적긴 하지만 한달 생활비로 쓸 정도의 돈을 받게 되었다. 사실 그 동안은 책임감이라기 보다는 &#39;나의 공부&#39; 딱 이정도의 마음 가짐이였다. 하지만 돈을 받게 된 순간 마음이 복잡해졌다. 뭔가 받은 만큼 해야하나? 라는 부담감과 돈을 받기 시작한거 한번 끝까지 해볼까?라는 생각이 들기 시작했다. </p>
<p>2일간 고민 끝에 내린 결정은 이렇다. 지금까지 작업한 양과 진행중인 작업을 따져봤을 때, 현재 받기로한 금액보다는 더 가치가 있기 때문에, 해당 기업에서는 받은 만큼 일을 하되, 그 이상으로 내가 욕심이 나는 부분은 <code>공부</code>라고 생각하려 한다.</p>
<h3 id="😮-앞으로는">😮 앞으로는?</h3>
<p>생각한 결과에 따라 <code>취업 준비</code>를 계속 하려고 한다. 그 중에 가장 큰 이유는 새로운 회사는 어떤 식으로 작업을 하는지, 어떤 식으로 회의를 하는지, 어떤 것을 배우는지가 많이 궁금하다. 그를 위해서 나는 <code>면접 준비, 알고리즘, 포트폴리오, 블로그</code>를 꾸준히 할 생각이다.</p>
<h4 id="😋-지금-진행하고-있는-start-up은">😋 지금 진행하고 있는 Start-up은?</h4>
<p>그렇다고 지금 진행하고 있는 Start-up을 대충할 생각은 전혀 없다. 말 그대로 받은 만큼 일하되, 나는 개인적으로 내 인생에서의 첫 프로젝트인 해당 웹 페이지에 많은 애정이 있기 때문에, 욕심도 있다. 내 취업준비에는 이 Start-up에서 개발을 하는 것도 포함된다. 새로운 기술도 공부하면서 적용해볼 생각이다. 또한 여건이 된다면 내가 다른 회사에 가고 난 뒤, 해당 Start-up에 들어올 개발자에게 인수인계를 하기 위한 문서를 꾸준히 작성해 놓을 생각이다!</p>
<h4 id="📆-공부-계획">📆 공부 계획</h4>
<p>하루에 최소 7시간은 공부를 할 생각이다.</p>
<ul>
<li>2시간 start-up 개발</li>
<li>2시간 면접 공부</li>
<li>2시간 알고리즘 공부</li>
<li>1시간 포트폴리오 수정 및 velog 작성</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.04.16]]></title>
            <link>https://velog.io/@0_right/TIL-23.04.16</link>
            <guid>https://velog.io/@0_right/TIL-23.04.16</guid>
            <pubDate>Sat, 15 Apr 2023 20:14:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>오늘은 현재 작업을 진행하면서 특정 상태 또는 상황에서 component를 보이거나 안보이게 하는 방법에 대하여 공부를 했다.</p>
</blockquote>
<h4 id="간단한-원리를-이용하자">간단한 원리를 이용하자!</h4>
<pre><code>const MyApp = () =&gt; {
    return(
        {...}
    )

}</code></pre><ul>
<li>위 코드에서 ...에는 JS 함수식을 사용할 수 있다.</li>
<li>해당 원리를 이용해서 &amp;&amp;을 사용해서 두개가 모두 참일 경우에 작동이 되게 할 수 있다.<pre><code>const MyApp = () =&gt; {
  return(
      {isTrue &amp;&amp; &lt;Button/&gt; }
  )
</code></pre></li>
</ul>
<p>}</p>
<pre><code>- 이렇게 코드를 짜면 isTrue가 참일 경우 Button 컴포넌트가 나타나게 된다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[💻TIL 23.04.05]]></title>
            <link>https://velog.io/@0_right/TIL-23.04.05</link>
            <guid>https://velog.io/@0_right/TIL-23.04.05</guid>
            <pubDate>Wed, 05 Apr 2023 11:59:24 GMT</pubDate>
            <description><![CDATA[<h2 id="😏그동안-진행-상황">😏그동안 진행 상황</h2>
<ul>
<li>근 2~3주 동안 나는 Migration을 진행하였다. 처음에는 단순히 Next에서 React로 옮기는 거니까 &quot;뭐....금방 하겠지?&quot;라는 생각을 했었다. 하지만 이것은 나의 착각.... 내 생각보다 과거 나의 코드는 더 엉망진창이였다.</li>
</ul>
<h3 id="😂-어떤-문제점들이-있었나요">😂 어떤 문제점들이 있었나요?</h3>
<ol>
<li>우선 위에서 말했듯이 나의 예전 코드는 정말 생각하지 않고 &quot;구현&quot;만 될 수 있게 짜여있었다. 이는 내가 어느 부분을 수정해야하는지 찾는데만 5~10분이 걸렸는데 이게 쌓이다 보니 몇시간씩이나 걸리게 됐다.</li>
<li>다음으로는 clubstudy는 기존 여러가지의 domain을 사용했었는데, 이는 배포하는 과정에서도 불편했지만, 생각보다 학생 domain과 mainPage의 domain이 겹치는 부분이 많았다. 그래서 domain을 줄이기로 했는데 여기서 다른 문제가 발생한다.<ul>
<li>기존 mainPage는 Emotion만을 사용해서 직접 모든 component들을 styled로 수정해서 그려나갔다. 하지만 studentPage에서는 mui를 기본으로 해당 mui component를 emotion을 통해 수정했기 때문에 mainPage와 studentPage는 합치기 불가능한 상황이였다.</li>
</ul>
</li>
</ol>
<h3 id="🙄-어떻게-해결하셨나요">🙄 어떻게 해결하셨나요?</h3>
<ul>
<li>내 판단으로는 아 이건 mainPage를 뜯어서 고쳐나가는 것보다는 mainPage 코드를 참고해서 아예 <code>새로 코드를 짜는 것</code>이 낫다고 판단했다.</li>
<li>mainPage를 처음 만들었을 때는 거의 3개월이 걸렸었던 것으로 기억하는데, 이번엔 기존 코드가 있고 구조도 미리 짠 뒤에 코드를 작성하다보니 2주일? 정도의 시간 밖에 걸리지 않았다.</li>
<li>기존 mainPage 폴더 안에 새롭게 cra(create react app)을 통해서 코드를 작성했고 모두 정상적으로 작동이 됐기 때문에 해당 cra를 기존 메인 폴더로 옮겨 놨어야 했다.<pre><code>  // before
  ├── node-modules
  ├── components
  ├── page
  ├── new Create React App
  ├── style
  └── run</code></pre></li>
<li>하지만 폴더 구조를 보면  node-modules라는 것이 있는데 이 파일이 진짜 너무 커서 지우는데 하루종일 걸리는 듯한 느낌을 받았고 이게 무엇인지 알아봤다.</li>
</ul>
<h4 id="node-modules란">node-modules란</h4>
<ul>
<li>node_modules 디렉토리에는 package.json에 있는 모듈 뿐만 아니라, package.json에 있는 모듈이 의존하고 있는 모듈 전부를 포함하고 있다. 그래서 node_modules 디렉토리안에는 정말 많은 모듈들이 들어가 있다. npm으로 새로운 모듈(패키지)를 설치하게 되면, package.json과 node_modules에 추가된다.<blockquote>
<p>출처
<a href="https://cheonmro.github.io/2018/12/23/package-json/">https://cheonmro.github.io/2018/12/23/package-json/</a></p>
</blockquote>
</li>
</ul>
<p>즉 우리 프로젝트에 들어가는 모든 모듈들을 포함한 파일이다. 그래서 그렇게 용량이 컷던 것이다.
이를 해결하는 방법을 한가지 찾았는데 </p>
<pre><code>rm -rf node_modules</code></pre><p>해당 코드를 터미널에 작성하면 엄청 빠른 속도는 아니지만, 그냥 폴더를 삭제하는 것보다는 훨씬 빠르게 삭제된다.</p>
<h3 id="끝">끝!</h3>
<p>이렇게해서 나의 첫 MIGRATION은 끝을 마쳤다. 파일 구조도 <a href="https://velog.io/@0_right/TIL-23.03.17">기존에 작성</a>한대로 style까지 분리를 마쳤다.</p>
<h3 id="💡-앞으로의-계획">💡 앞으로의 계획</h3>
<ul>
<li>우선 새로운 요구사항이 들어왔고 해당 부분을 먼저 개발할 것 같다. 그 다음으로는 드디어 사용 해보고 싶었던 상태관리 라이브러리 &quot;redux&quot;를 공부해 볼까 한다! 화이팅~</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.03.17]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.17</link>
            <guid>https://velog.io/@0_right/TIL-23.03.17</guid>
            <pubDate>Thu, 16 Mar 2023 16:12:52 GMT</pubDate>
            <description><![CDATA[<h2 id="refactoring에서-생각해-봐야할-항목">Refactoring에서 생각해 봐야할 항목</h2>
<p>이번에 refactoring을 진행하기 전에 이번처럼 큰 공사(refactoring)을 하지 않기 위해 기초적인 것을 공부하고 있다. 공부를 하다보니 어느 글에서 <code>module의 특성을 고려하여 directory structre를 작성하라</code>라는 문구를 봤다. 나는 그동안 알지도 못하는 module을 당연한듯이 쓰다보니 이 말 뜻을 이해하지 못했다. 그래서 모듈에 대해 공부해보고 <a href="https://velog.io/@0_right/TIL-23.03.16">지난글</a>에서 작성한 디렉토리 구조를 다시 작성해보려 한다.</p>
<h3 id="❔-모듈이란">❔ 모듈이란</h3>
<ul>
<li>애플리케이션을 구성하는 개별적 요소로서 <code>재사용 가능한 코드 조각</code>을 말한다. 일반적으로 모듈은 기능을 기준으로 파일 단위로 분리한다. 이때 모듈이 성립하려면 모듈은 자신만의 <code>파일 스코프</code>를 가질 수 있어야한다.
출처 : <a href="http://www.yes24.com/Product/Goods/92742567">JavaScript Deep Dive 48장</a></li>
<li>즉, 모듈은 개별적 존재로서 애플리케이션과 분리되어 존재한다. 하지만 완전이 분리되어 개별적으로 존재하는 모듈은 재사용이 불가능하므로 존재의 의미가 없다고 할 수 있다. 따라서 <code>모듈은 공개가 필요한 자산에 한정하여 명시적으로 선택적 공개가 가능하다. 이를 export라 한다.</code> export된 모듈의 자산은 다른 모듈에서 재사용할 수 있는데, 이때 <code>공개된 모듈을 재사용할 때 자신의 스코프 내로 불러들여 사용하는 것을 import라 한다.</code></li>
<li>따라서 모듈은 기능별로 분리되어 개별적인 파일로 작성되는데, 코드의 단위를 명확히 분리하여 애플리케이션을 구성할 수 있고, 재사용성이 좋아서 개발 효율성과 유지보수성을 높일 수 있다.</li>
</ul>
<h3 id="directory-sturcture-재설계">Directory Sturcture 재설계</h3>
<pre><code>    // before
    ├── components
    │   ├── Header.tsx
    │   ├── Footer.tsx
    │   └── Tag.tsx
    ├── page
    │   ├── mainPage
    │   │   └── index.tsx
    │   └── detailStudyPage
    │       ├── index.tsx
    │       ├── TabStudyIntroduce.tsx
    |       └── TabBookIntroduce.tsx
    ├── style
    │   ├── components
    │   │   ├── HeaderStyled.tsx
    │   │   ├── FooterStyled.tsx
    │   │   └── TagStyled.tsx
    │   └── page
    │       ├── mainPage
    │       │   └── MainPageStyled.tsx
    │       └── detailStudyPage
    │           ├── DetailStudyPageStyled.tsx
    │           ├── TabStudyIntroduceStyled.tsx
    |           └── TabBookIntroduceStyled.tsx
    └── run</code></pre><ul>
<li><p>기존에 구상했던 부분에서 모듈의 특성을 고려하지 않은 부분은 style과 component의 분리다. 모듈의 특성상 개발의 효율성과 유지보수성을 높일 수 있다는 것인데, 자주 사용하는 모듈끼리 함께 있어야 관리하기 용이할 것 같다는 생각이 들었다. 해당 생각을 바탕으로 다시 구상해봤을때의 결과이다 </p>
<pre><code>// after
├── components
│   ├── Header.tsx
│   ├── HeaderStyled.tsx
│   └── Footer.tsx
│   ├── FooterStyled.tsx
│   ├── Tag.tsx
│   └── TagStyled.tsx
├── page
│   ├── mainPage
│   │   └── index.tsx
│   │   └── MainPageStyled.tsx
│   └── detailStudyPage
│       ├── index.tsx
│       ├── TabStudyIntroduce.tsx
|       ├── TabBookIntroduce.tsx
│       ├── DetailStudyPageStyled.tsx
│       ├── TabStudyIntroduceStyled.tsx
|       └── TabBookIntroduceStyled.tsx
├── style
└── run</code></pre></li>
<li><p>style에는 공통으로 사용되는 부분에 대해서 사용하려고 한다. 하지만 아직까지 공통으로 사용되는 스타일에 대해서 생각해본 것이 없으므로 추후에 넣어볼 예정이다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.03.16]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.16</link>
            <guid>https://velog.io/@0_right/TIL-23.03.16</guid>
            <pubDate>Thu, 16 Mar 2023 12:57:34 GMT</pubDate>
            <description><![CDATA[<h2 id="💪-mainpage-refactoring">💪 MainPage Refactoring</h2>
<h4 id="지난-게시글에서-말했듯이-우리는-nextjs에서-reactjs로-migration을-진행하기로-했다">지난 게시글에서 말했듯이 우리는 NextJs에서 ReactJs로 migration을 진행하기로 했다.</h4>
<p>처음으로 진행해보는 migration이라서 어떻게 시작할지 막막해서 계획을 세워보기로 했다.</p>
<h3 id="📄-현재-처한-상황">📄 현재 처한 상황</h3>
<ol>
<li><p>현재 우리 페이지는 auth.xxx.com, learn.xxx.com, main.xxx.com, admin.xxx.com 4개로 이뤄져있다.</p>
</li>
<li><p>같은 NavBar를 사용하는 learn page와 main page를 합치려고 한다.</p>
</li>
<li><p>하지만 현재 learn page는 MUI를 사용할 수 있는 세팅이지만 main page는 초기에 MUI를 사용하기로 하지 않아서 theme.ts가 존재하기 때문에 MUI를 사용할 수 없는 상태이다.</p>
</li>
<li><p>이번에 팀원과 code Review를 하며 깨달은 것이 있는데, 해당 부분이 main page의 코드를 작성할 때 아예 적용되지 않았던 것 같아서 적용하려한다</p>
<ul>
<li><p>&quot;함수 하나에 하나의 동작이 이뤄질 수 있도록 하는게 좋을 것 같아요&quot; 라는 review가 있었다.</p>
</li>
<li><p>해당 review를 보고 간단하게 refactoring을 진행해 봤는데 생각보다 아주 만족스러웠다.</p>
</li>
<li><p>before</p>
<pre><code> const Detail_Study = () =&gt; {
    const [curTapId, setCurTapId] = useState(0);
    const handleClickTap = (id: number) =&gt; {
      if (id === 1 || id === 0) setCurTapId(id);
    };
 return (
   &lt;&gt;
     &lt;Layout&gt;
       &lt;DetailHeadContainer&gt;
         &lt;StudyImg /&gt;
         &lt;HeadRightBox&gt;
           &lt;SeperateHeartBtn&gt;
             &lt;StudyName&gt;...&lt;/StudyName&gt;
             &lt;HeartBtn /&gt;
           &lt;/SeperateHeartBtn&gt;
           &lt;TeacherName&gt;...&lt;/TeacherName&gt;
           &lt;StudyTag study_tag={study_detail_tag} /&gt;
           &lt;SummaryStudy&gt;...&lt;/SummaryStudy&gt;
           &lt;StudyDeadLine&gt;...&lt;/StudyDeadLine&gt;

           &lt;Link href=&quot;/apply_math&quot;&gt;
             &lt;HeadBottomBtn disabled&gt;...&lt;/HeadBottomBtn&gt;
           &lt;/Link&gt;
           &lt;div
             style={{
               display: &#39;flex&#39;,
               justifyContent: &#39;flex-end&#39;,
             }}
           &gt;
             &lt;a
               href=&quot;http://pf.kakao.com/_yKHxnxj/chat&quot;
               target=&quot;_blank&quot;
               rel=&quot;noreferrer&quot;
             &gt;
               &lt;div style={{ display: &#39;flex&#39;, alignItems: &#39;center&#39; }}&gt;
                 &lt;KakaotalkContent&gt;...&lt;/KakaotalkContent&gt;
                 &lt;Image/&gt;
               &lt;/div&gt;
             &lt;/a&gt;
           &lt;/div&gt;
         &lt;/HeadRightBox&gt;
       &lt;/DetailHeadContainer&gt;
       &lt;TabContainer&gt;
         &lt;TabTitleContainer&gt;
           {TAB_INFO.map((item) =&gt; {
             return (
               &lt;TabTitleBox
                 active={curTapId === item.id}
                 first_tab={item.id === 0}
                 key={item.id}
                 onClick={() =&gt; handleClickTap(item.id)}
               &gt;
                 {item.title}
               &lt;/TabTitleBox&gt;
             );
           })}
         &lt;/TabTitleContainer&gt;
         &lt;TapContentsContainer&gt;
           {TAB_INFO.map((item) =&gt; {
             if (curTapId === item.id) {
               return item.contents;
             }
           })}
         &lt;/TapContentsContainer&gt;
       &lt;/TabContainer&gt;
     &lt;/Layout&gt;
   &lt;/&gt;
 );</code></pre></li>
<li><p>after</p>
<pre><code>const Detail_Study = ({ study }: DetailProps) =&gt; {
  return (
    &lt;Layout&gt;
      &lt;DetailHeadContainer&gt;
        &lt;StudyImg imageSrc={study.img} /&gt;
        &lt;Head study={study} /&gt;
      &lt;/DetailHeadContainer&gt;
      &lt;DetailStudyTab study={study} /&gt;
    &lt;/Layout&gt;
  );
};
function Head({ study }: DetailProps) {
  return (
    &lt;HeadRightBox&gt;...&lt;/HeadRightBox&gt;
  );
}
function DetailStudyTab({ study }: DetailProps) {
  ...
  return (
    &lt;TabContainer&gt;...&lt;/TabContainer&gt;
  );
}</code></pre><p> before 코드는 Detail_Study component에 모든 로직이 들어가 있다. 하지만 Detail_Study 안에 있는 로직을 나눠보면 <code>Head와 Tab</code>으로 나눌 수 있었다. 그래서 Head와 DetailStudyTab을 따로 함수로 만든 뒤 Detail_Study component에서 분리시켰다. </p>
<p> 이렇게 했을 때, 다른 개발자가 해당 component를 봤을때 어떤 기능을 하는지 확실하게 알 수 있을 것 같았다. 또한 detail_study에서 수정사항이 발생했을 때, Head를 고쳐야하면 Head 함수에 가고, Tab을 수정해야하면 DetailStudyTab에 가서 수정하면 되기 때문에 refactoring적 면에서도 매우 좋을 것 같았다.</p>
<p> 또한 component와 함수의 구분을 위해서 component는 arrow function으로 작성했고, 함수는 일반 function을 통해 정의를 내렸다.</p>
</li>
</ul>
</li>
</ol>
<h2 id="🗓️-계획">🗓️ 계획</h2>
<ol>
<li>위의 완료된 예시를 기준으로 함수 하나에 기능 하나를 만들 것이다.</li>
<li>현재 모든 component에는 기능뿐만 아니라 style 또한 함께 있는데, 이를 분리 시킬예정이다. 또한 공동 컴포넌트와 한 페이지에서만 사용하는 컴포넌트 또한 분리할 예정이다.<ul>
<li>예시<pre><code>// before
├── components
│   ├── Header.tsx
│   ├── Footer.tsx
│   ├── TabStudyIntroduce.tsx
│   ├── TabBookIntroduce.tsx
│   └── Tag.tsx
├── page
│   ├── mainPage.tsx
│   └── detailStudyPage.tsx
└── run

</code></pre></li>
</ul>
</li>
</ol>
<pre><code>// after
├── components
│   ├── Header.tsx
│   ├── Footer.tsx
│   └── Tag.tsx
├── page
│   ├── mainPage
│   │   └── index.tsx
│   └── detailStudyPage
│       ├── index.tsx
│       ├── TabStudyIntroduce.tsx
|       └── TabBookIntroduce.tsx
├── style
│   ├── components
│   │   ├── HeaderStyled.tsx
│   │   ├── FooterStyled.tsx
│   │   └── TagStyled.tsx
│   └── page
│       ├── mainPage
│       │   └── MainPageStyled.tsx
│       └── detailStudyPage
│           ├── DetailStudyPageStyled.tsx
│           ├── TabStudyIntroduceStyled.tsx
|           └── TabBookIntroduceStyled.tsx
└── run</code></pre><p>   ```</p>
<h3 id="느낀점">느낀점</h3>
<ul>
<li>음... 기존 learn page를 제작하면서 Main page도 learn page 처럼 만들어야하는데...해야하는데...라고 생각만하고 실천하기 두려웠었다...(너무 양이 많아서..) 하지만 어떻게 보면 지금이 고쳐야할 분량이 적을 때가 아닌가라고 생각했고. 이번 기회에 싹다 고치고 미래를 기약하자는 마음으로 Refactoring을 시작하려한다. </li>
<li>나에게 나는 데드라인을 주고 빡세게 해보려한다. 다음주까지 마무리 해보도록 할 것이다! 화이팅ㅎ..</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.03.13]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.13</link>
            <guid>https://velog.io/@0_right/TIL-23.03.13</guid>
            <pubDate>Thu, 16 Mar 2023 11:15:35 GMT</pubDate>
            <description><![CDATA[<h1 id="❗️문제">❗️문제</h1>
<ul>
<li><p>우리는 로그인 기능을 JWT를 이용해 구현했다. </p>
<blockquote>
<p>JWT(JSON WEB TOKEN)란 웹에서 사용되는 JSON 형식의 토큰에 대한 표준 규격으로, 주로 사용자의 인증 또는 인가 정보를 서버와 클라이언트간에 안전하게 주고 받기 위해 사용된다.</p>
</blockquote>
</li>
<li><p>로그인 인증 방식에서 localhost와 문제가 발생했다.</p>
<p> auth 페이지에서 알맞는 이메일과 비밀번호를 전송한다면, JWT를 cookie에 담아서 보내는 형식으로 설정했다. </p>
<ul>
<li>&#39;api.xxx.xxx/xxx&#39;에 데이터를 요청했을 때 해당 페이지에 JWT가 와있다면 데이터를 보여주고 없다면 401 ERROR를 출력하게 설정했다. </li>
<li>이때, cookie의 세팅에 <code>Same-site:none, Secure:true</code>로 설정함으로써 http에서는 쿠키를 가져올 수 없게 했다. </li>
</ul>
<p>하지만 localhost:3000/은 https가 아닌 http 사이트로 해당 쿠키를 가져오지 못하기 때문에 인증정보를 받지 못해서 local 환경에서 api를 요청하면 <code>401 ERROR</code>가 발생했다.</p>
<h2 id="🔍-해결-방안">🔍 해결 방안</h2>
<ul>
<li><p>MSW(Mock Service Worker) 도입</p>
<blockquote>
<p>MSW란, API Mocking 라이브러리로, 서버향의 네트워크 요청을 가로채서 모의 응답(Mocked response)을 보내주는 역할을 합니다. 따라서, Mock Service Worker(MSW) 라이브러리를 통하면, Mock 서버를 구축하지 않아도 API를 네트워크 수준에서 Mocking 할 수 있습니다. 
참조 : <a href='https://tech.kakao.com/2021/09/29/mocking-fe/'>Mocking으로 생산성까지 챙기는 FE 개발</a></p>
</blockquote>
<ul>
<li>즉 정리하자면, 기존의 API서버에 요청은 보내지만, local 서버에서는 지정해둔 Mock Data를 브라우저에서 API 요청을 가로챈 뒤 보내주는 것이다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="😩-여기서-문제가-발생한다">😩 여기서 문제가 발생한다.</h3>
<ul>
<li><p>지난 게시물에서 우리는 SEO를 위해서 NEXT.JS의 SSG 랜더링 방식을 선택했다. 하지만 MSW를 도입해서 작업을 하는데 MSW가 API요청을 가로채기 전에 pre-rendering에 의해 이미 데이터를 요청 받아 출력했기 때문에 MSW가 작동하지 않았던 것이다.</p>
</li>
<li><p>앞으로 Back-end와 Front-end에서 작업속도를 올리기 위해서는 MSW를 계속 사용하기로 약속된 상태에서 이러한 문제를 직면해서 어떻게 해야할지 팀원과 이야기를 나눴다.</p>
</li>
<li><p>그 결과 우리는 그동안 작업했던 Next.Js를 포기하고 React.Js로 migration한 뒤 CSR 방식을 사용하기로 했다.</p>
</li>
</ul>
<h3 id="🙁-migration-했을-때-문제점은-없을까">🙁 Migration 했을 때 문제점은 없을까?</h3>
<ul>
<li><p>Next.Js에서 React.Js로 옮기기로 했을 때 가장 신경쓰였던 부분이 있었다. 우리는 <code>왜? Next를 선택했지?</code> 해당 질문의 답은 전 게시물에 있다.</p>
<blockquote>
<p>스터디니까 SEO가 꼭 필요하지 않나요? 그러면 저희 SSR이나 SSG를 사용해보는게 어떨까요?!</p>
</blockquote>
</li>
<li><p>맞다. 우리는 SEO에 도움이 되는 SSR 또는 SSG를 선택했었다. 하지만 CSR을 선택하면 SEO를 포기해야하나...라고 생각했고, 해당 부분에 대해서 검색을 했다.</p>
</li>
<li><p>검색 결과 우리는 해답을 찾을 수 있었는데, AWS의 S3를 이용해 배포를 하고, Cloud Front의 Ramda@Edge를 이용하면 CSR에서 부족한 SEO 최적화를 도와준다는 글을 읽었다. 해당 부분은 추후에 공부를 한 뒤에 남길 예정이다.</p>
</li>
</ul>
<h1 id="🥲-next-안녕">🥲 Next 안녕...</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.03.10]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.04</link>
            <guid>https://velog.io/@0_right/TIL-23.03.04</guid>
            <pubDate>Sat, 11 Mar 2023 06:31:12 GMT</pubDate>
            <description><![CDATA[<h4 id="🫠-업로드가-느렸던-이유">🫠 업로드가 느렸던 이유...</h4>
<ol>
<li>기존 ClubStudy 페이지는 하드코딩으로 작성되어있었다..(작업 초반 나의 실력 미숙과 기한이 짧았어서)</li>
<li>그래서 해당부분을 API를 받아와서 적용하려하다 보니 발생하는 오류가 있었다.</li>
<li>하지만 오류가 하나를 해결하니 다른 오류가 계속 발생했고, 천천히 처음부터 돌아가보자 라는 생각이 들었다.</li>
<li>한부분당 하나씩 업로드를 했어야했는데...나를 과신해서 하루만에 다 해결할 줄 알았다..</li>
<li>이제 어떤 문제가 있었고, 어떻게 해결했는지 확인해보자.<h1 id="✅-문제">✅ 문제</h1>
</li>
</ol>
<h3 id="1-csr-vs-ssg-vs-ssr">1. CSR vs SSG vs SSR</h3>
<ul>
<li>CSR은 JS파일을 전부 로드해야, 페이지 정보를 구성할 수 있으므로 SEO에 취약하다. 하지만 해당 웹사이트는 마케팅을 위해 SEO가 필요한 상황이기 때문에 CSR은 제외했다.</li>
<li>SSG와 SSR 중에 선택을 해야했다. SSR의 장점으로는 더 많은 <code>실시간</code> 데이터를 가져와 응답을 하는 것이다. 하지만 페이지 특성상 실시간으로 바뀌는 데이터가 빈번하지 않기 때문에 속도가 더 빠른 SSG를 선택하기로 했다.</li>
</ul>
<h3 id="2-api연동">2. API연동</h3>
<ul>
<li><p>Next JS에서 SSG 방식으로 API 연동하는 방법에는 getStaticProps가 있다.</p>
<pre><code>export const getStaticProps: GetStaticProps = async (context) =&gt; {
const res = await fetch(&#39;https://.../posts&#39;)
const posts = await res.json()

// 데이터가 없으면 notFound를 보낸다 
if (!data) {
  return {
    notFound: true,
  }
}

return {
  props: {
    posts,
  },
}
}</code></pre></li>
<li><p>메인페이지에서는 문제가 발생하지 않았지만, detail_study에서 해당 문제가 발생했다.
<img src="https://velog.velcdn.com/images/0_right/post/ea8f02ba-7b37-47ae-a5bc-cb69c1b69b43/image.png" alt=""></p>
</li>
</ul>
<h2 id="🔍-원인-파악">🔍 원인 파악</h2>
<h3 id="1-detail_study는-어떻게-이뤄져있나">1. detail_study는 어떻게 이뤄져있나.</h3>
<ul>
<li><p>메인페이지에서 스터디 카드를 누르면 해당 스터디의 상세페이지로 이동하게 해야했다. 이때 생각한 방법으로는 두가지가 있다.</p>
<ol>
<li>router.query를 이용하여 스터디 카드를 클릭했을 때, 페이지를 이동하면서 studyId를 함께 보내서 API에 studyId를 보내 해당 스터디 데이터를 받아오는 방법</li>
<li>Next JS의 dynamic routing을 이용해서 동적으로 studyId에 따라 페이지를 이동하도록 (ex : studyId가 1일 경우 clubstudy.net/detail_study/1) 하는 방법이 있다.</li>
</ol>
</li>
<li><p>해당 보기들 중 한번 구성을 하면 관리자의 개입이 없는 2번을 택해서 코드를 작성했다.</p>
<pre><code>&lt;StudyCardBox
  onClick={() =&gt; {
      const path = `/detail_study/${Props.id}`;
      router.push({
          pathname: path,
      });
  }}
  maxWidth=&quot;xs&quot;
&gt;</code></pre></li>
</ul>
<h3 id="2-getstaticpaths란">2. getStaticPaths란?</h3>
<ul>
<li>If a page has dynamic routes and uses getStaticProps it needs to define a list of paths that have to be rendered to HTML at build time.
<a href="https://nextjs.org/docs/basic-features/data-fetching/overview#getstaticprops-static-generation">공식문서</a></li>
<li>즉, 동적라우팅 + getStaticProps를 사용하고 싶을 때 getStaticPaths로 경로를 지정해놔야 한다.</li>
<li>prerendering하는 과정에서 경로가 외부에 의존하게 됐을때, getStaticProps만으로는 할 수 가 없다. 왜냐하면 <code>/detail_study/${Props.id}</code>에서 id에 어떤 값이 있는지 알 수 없고, 지금 알고 있더라도 추가되면 달라지기 때문이다.</li>
<li>getStaticPaths는 해당 문제를 해결하기 위해 빌드시에 호출되며 id에는 어떤 값들이 있는지 미리 파악해서 getStaticProps에 알려주는 역할을 한다.</li>
</ul>
<h4 id="시도">시도</h4>
<pre><code>export const getStaticPaths: GetStaticPaths = async () =&gt; {
  // posts를 받기 위해 fetch
  const res = await fetch(`https://api-/`);
  const posts = await res.json();
  // pre-render할 Path를 얻음 (posts를 통해서)
  const paths = posts.map((study: StudyInfoType) =&gt; ({
    params: { post: study.studyId.toString() },
  }));
  return { paths, fallback: false };
};

// 빌드될 때 실행
export const getStaticProps: GetStaticProps = async (context) =&gt; {
  // params는 post `id`를 포함하고 있다
  const { id } = context.params as IParams;
  const res = await axios.get(
    `http://api-/{id}`,
  );
  const data = res.data;
  // 해당 페이지에 props로 보냄
  return { props: { study: data } };
};</code></pre><p><img src="https://velog.velcdn.com/images/0_right/post/b6908f5e-fdc6-4af9-b2fb-cbd7697b27c2/image.png" alt=""></p>
<ul>
<li>하지만 해당 오류가 발생했다. 진짜 많이 찾아보고 드디어 해결법을 찾은줄 알고 기뻤었는데 다른 오류가 뜬다.</li>
<li>그렇다는 것은 Path를 통해 가져왔다는 것 같은데 parameter에서 오류가 발생한 것 같아 다시 확인을했다.</li>
<li>정말 간단한 문제로 path에서 보내는 params에는 post가 아닌 StaticProps의 것 과 같게 만들어야 했다.</li>
</ul>
<h2 id="해결">해결</h2>
<pre><code>export const getStaticPaths: GetStaticPaths = async () =&gt; {
  // posts를 받기 위해 fetch
  const res = await fetch(`https://api-/`);
  const posts = await res.json();
  // pre-render할 Path를 얻음 (posts를 통해서)
  const paths = posts.map((study: StudyInfoType) =&gt; ({
    params: { id: study.studyId.toString() },
  }));
  return { paths, fallback: false };
};</code></pre><h3 id="느낀점">느낀점</h3>
<ol>
<li>페이지 렌더링하는 방식부터 API 연동, Dynamic Routing, StaticPaths, StaticProps까지 한번에 정말 많은 공부를 한 것 같았다.</li>
<li>처음으로 하는 것들이 많아서 개발 설계부터 하지 않고, 맨바닥에 헤딩으로 시작하다보니 막히는 부분이 많았다. 하지만 이번 경험을 통해서 어떻게 설계를 할지 알게 되었고, 공부하는 방법에 많은 도움이 된 것 같았다.</li>
<li>차근차근 하나씩 풀어나가는 과정이 아직까지 나는 너무 재밌다. 앞으로도 재밌길 바라며 오늘 기록 끝!</li>
</ol>
<h4 id="📄-참조">📄 참조</h4>
<blockquote>
<p><a href="https://mui.com">https://mui.com</a> 
<a href="https://agilejung.tistory.com/entry/MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">https://agilejung.tistory.com/entry/MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</a>
<a href="https://ajdkfl6445.gitbook.io/study/web/csr-vs-ssr-vs-ssg">https://ajdkfl6445.gitbook.io/study/web/csr-vs-ssr-vs-ssg</a>
<a href="https://han-py.tistory.com/489">https://han-py.tistory.com/489</a>
<a href="https://velog.io/@devstone/Next.js-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-feat.-initialProps-webpack-storybook#-getstaticpaths-static-generation">https://velog.io/@devstone/Next.js-100-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0-feat.-initialProps-webpack-storybook#-getstaticpaths-static-generation</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 💻 TIL  23.03.07]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.07</link>
            <guid>https://velog.io/@0_right/TIL-23.03.07</guid>
            <pubDate>Thu, 09 Mar 2023 05:37:32 GMT</pubDate>
            <description><![CDATA[<h3 id="🤷-면접-대비-공부를-이어서-하려-한다">🤷 면접 대비 공부를 이어서 하려 한다.</h3>
<h3 id="1-this">1. This</h3>
<ul>
<li>JS에서 모든 함수는 실행될 때마다 함수 내부에 this라는 객체가 추가되는데, 해당 함수 호출 방식에 따라 바인딩 되는 객체가 달라지는 특징이 있다.</li>
</ul>
<h4 id="함수-호출-방식">함수 호출 방식</h4>
<ol>
<li>함수 호출</li>
<li>메소드 호출</li>
<li>생성자 함수 호출</li>
<li>apply/call/bind 호출<pre><code>var foo = function () {
console.dir(this);
};
</code></pre></li>
</ol>
<p>// 1. 함수 호출
foo(); // window
// window.foo();</p>
<p>// 2. 메소드 호출
var obj = { foo: foo };
obj.foo(); // obj</p>
<p>// 3. 생성자 함수 호출
var instance = new foo(); // instance</p>
<p>// 4. apply/call/bind 호출
var bar = { name: &#39;bar&#39; };
foo.call(bar);   // bar
foo.apply(bar);  // bar
foo.bind(bar)(); // bar</p>
<pre><code>#### 1. 함수 호출
- 전역 객체는 모든 객체의 최상위 객체를 의미하며 브라우저 상에서는 window, terminal 상에서는 global이다.
- this는 기본적으로 전역객체에 바인딩 되는데, 함수안에 있는 내부함수의 경우에도 this는 외부함수가 아닌 전역객체에 바인딩된다.</code></pre><p>var foo = function(){
    var boo = function(){
        console.dir(this);
    }
    boo() // window
}
foo();</p>
<pre><code>
#### 2. 메소드 호출
- 함수가 객체의 value이면 메소드로서 호출되는데, 이때 함수 내부의 this는 객체에 바인딩 된다.</code></pre><p>var object1 = {
    name: &quot;Kim&quot;,
    sayName: function(){
        console.log(this.name);
    }
}
var object2 = {
    name: &quot;Pee&quot;
}</p>
<p>object2.sayName = object1.sayName;</p>
<p>object1.sayName(); // Kim
object2.sayName(); // Pee</p>
<pre><code>
#### 3. 생성자 함수 호출
- JS의 생성자는 일반 함수에 new 연산자를 붙여 호출하면 생성자 함수처럼 동작한다.</code></pre><p>function Person(name) {
  // 생성자 함수 코드 실행 전 -------- 1
  this.name = name;  // --------- 2
  // 생성된 함수 반환 -------------- 3
}</p>
<p>var me = new Person(&#39;Lee&#39;);
console.log(me.name); // Lee</p>
<pre><code>
#### 4. apply/call/bind 호출
- JS엔진은 암묵적으로 this를 1~3번의 기준으로 바인딩한다. 하지만 그 이외에도 직접 바인딩하는 방법도 존재하는데 apply와 call이 그러하다. 
- 그러나 명시적인 바인딩이라고 하더라도 apply와 call은 콜백함수가 실행되는 시점에 global context로 바인딩이된다. 이때 apply와 call은 실행한 결과 값을 반환하기 때문에 영구적으로 this를 가리키도록 할 수 없는 단점이 있다.

- 반면에 bind() 메서드는 this가 bind에 제공된 값으로 설정된 함수를 생성하며, 해당 함수의 인자값의 순서 또한 영구적으로 지정할 수 있다.</code></pre><p>var healthObj = {
    name : &quot;달리기&quot;,
    lastTime : &quot;PM10:12&quot;,
    showHealth : function() {
        setTimeout(function(){
            console.log(this.name + &quot;님, 오늘은 &quot; + this.lastTime + &quot;에 운동을 하셨네요&quot;);
        }, 500);
    }
}</p>
<p>healthObj.showHealth();</p>
<pre><code>해당 코드의 결과값을 언뜻 보면 &quot;달리기님 오늘은 PM10:12에 운동을 하셨네요&quot;라고 생각할 수 있지만, 해당 결과 값은 &quot;undefined님, 오늘은 undefined에 운동을 하셨네요&quot;이다.
왜냐하면 setTimeout은 비동기 함수 이기 때문에, 해당 함수가 실행될 때는 이미 showHealth가 반환된 상태이기 때문이다.</code></pre><p>var healthObj = {
    name : &quot;달리기&quot;,
    lastTime : &quot;PM10:12&quot;,
    showHealth : function() {
        setTimeout(runFunction, 500);
    }
}
var runFunction = function(){
    console.log(this.name + &quot;님, 오늘은 &quot; + this.lastTime + &quot;에 운동을 하셨네요&quot;);
}.bind(healthObj);</p>
<p>healthObj.showHealth();</p>
<pre><code>위와 같이 runFunction에 healthObj에 bind를 하게 되면, this를 영구적으로 바인드하게 된다. 

### ❤️ 도움받은 곳 
&gt; 
https://poiemaweb.com/js-this
https://enai.tistory.com/14</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.03.06]]></title>
            <link>https://velog.io/@0_right/TIL-23.03.06</link>
            <guid>https://velog.io/@0_right/TIL-23.03.06</guid>
            <pubDate>Mon, 06 Mar 2023 15:29:55 GMT</pubDate>
            <description><![CDATA[<h2 id="🤷-면접을-준비하며-공부한-내용을-끄적거려-볼까-한다">🤷 면접을 준비하며 공부한 내용을 끄적거려 볼까 한다.</h2>
<h3 id="1-호이스팅">1. 호이스팅</h3>
<ul>
<li>호이스팅이란 실제 코드가 실행되는 런타임 이전에 변수의 선언 단계가 코드의 맨 위로 올려진 것처럼 동작하는 자바스크립트의 특징이다.</li>
</ul>
<h4 id="호이스팅의-대상">호이스팅의 대상</h4>
<ul>
<li><p>자바스크립트에서는 let, const를 포함한 <code>모든 선언</code>을 호이스팅합니다.</p>
</li>
<li><p>변수는 3가지 단계를 거처 생성됩니다.</p>
<ul>
<li><p>선언 단계 : 변수를 객체에 등록</p>
</li>
<li><p>초기화 단계 : 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보. 이때 변수는 <code>undefined</code>로 초기화</p>
</li>
<li><p>할당 단계 : <code>undefined</code>로 초기화된 변수에 실제 값을 할당.</p>
<pre><code>해당 부분에서 var와 es6에서 도입된 let,const와의 차이점이 생긴다.
var는 선언 단계와 초기화 단계가 한번에 이뤄진다.

console.log(a) // undefined
var a = 12;
console.log(a) // 12

하지만 const와 let의 경우 선언 단계와 초기화 단계가 분리되어 이루어지기 때문에, 
스코프에 변수를 등록(선언 단계)하지만 초기화 단계는 변수 선언문에 도달했을 때 실행 되기 때문에 
초기화 이전에 변수에 접근하면 참조 에러(ReferenceError)가 발생한다.

</code></pre></li>
</ul>
</li>
</ul>
<pre><code>   ❔ 그렇다면 어떤 이유로 es6에 추가된 const,let은 선언, 초기화 단계를 구분했을까?
    &gt;  var는 중복 선언이 가능하기 때문이다. 해당 부분이 왜 문제가 되는지는 코드를 봐보도록 하자

     ```
     var PersonName = &#39;김아무개&#39;;
     console.log(`그의 이름은 ${PersonName}입니다.`); //김아무개
     var PersonName = &#39;김진짜진짜&#39;;
     console.log(`그의 이름은 ${PersonName}입니다.`); //김진짜진짜
     ```
     위와 같이 짧은 코드만 보더라도 내가 &quot;김아무개&quot;에 대한 정보를 가진 변수를 사용하고 싶어도 중복된 변수명으로 &quot;김진짜진짜&quot;가 다시 선언되었기 때문에 &quot;김아무개&quot;에 대한 정보를 다시 가져올 수 없게된다. 만약 수십에서 수백줄이 되는 코드에서 해당 문제가 발생하면 해결하기 위해 꽤나 오랜 시간이 걸릴 수 있다.
     하지만 let,const를 사용하면 같은 변수명을 중복해서 사용할 수 없기 때문에 해당 변수 선언을 권장하는 것이다.

### 2. 스코프
- 변수 이름, 함수 이름과 같이 `식별자가 참조할 수 있는 유효 범위`를 뜻한다.

#### 종류
   - 함수 레벨 스코프
      - 함수에 의해서만 스코프가 형성됨
      - var 키워드로 선언된 변수
   - 블록 레벨 스코프
      - 코드 블록 단위의 스코프가 형성됨
      - let, const 키워드로 선언된 변수

변수를 참조할 때 JS엔진은 자신의 스코프에 변수가 없으면 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다. 이를 `스코프 체인`이라고 한다.

예를 들어보자</code></pre><p>var x = 1;</p>
<p>function foo() {
  var x = 10;
  bar();
}</p>
<p>function bar() {
  console.log(x);
}</p>
<p>foo(); // ?
bar(); // ?</p>
<p>```</p>
<p>해당 코드를 보았을 때 JS가 동적 스코프를 따르는지 렉시컬 스코프를 따르는지 잘 모른다면 결과 값을 동적 스코프를 따르는 10, 1로 예상했을 것이다. 하지만 JS는 렉시컬 스코프를 따르기 때문에 결과 값은 1,1이 나온다. 이때 렉시컬 스코프란 무엇일까?</p>
<p>렉시컬 스코프는 정적 스코프로 상위 스코프가 동적으로 변하지 않고 함수 정의가 평가 되는 시점에 상위 스코프가 정적으로 결정된다. 즉, JS의 상위 스코프는 어디서 호출했는지가 아닌 어디서 <code>정의</code>했는지에 따라 결정된다. 즉 bar는 전역 스코프를 기억하고 있다가 x를 전역에서 찾게 되기 때문에 결과 값이 1,1이 된다.</p>
<h2 id="to-be-continued">To be continued...</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 23.02.22]]></title>
            <link>https://velog.io/@0_right/TIL-23.02.22-ajvjl5g4</link>
            <guid>https://velog.io/@0_right/TIL-23.02.22-ajvjl5g4</guid>
            <pubDate>Wed, 22 Feb 2023 10:37:43 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-문제">✅ 문제</h1>
<ul>
<li>작년 말에 참여했던 KB IT&#39;s Your Life에서 만들었던 감성숙소 추천 웹 사이트를 리팩토링 계획을 세우고 진행하려 한다.</li>
<li>리팩토링에서 해야할 과제<ol>
<li>코드 개선<ul>
<li>1달동안 프로젝트를 하나 진행해야하는데 프론트를 혼자 맡게 되어서 급하게 코드를 짜다보니 컴포넌트 재사용성도 떨어지고, 지저분하다고 느껴졌기 때문에</li>
<li>MUI를 써서 코드를 간소화할 예정</li>
<li>반응형 웹페이지로 만들기</li>
</ul>
</li>
<li>로그인 기능 구현<ul>
<li>프로젝트를 하던중에 상태관리까지 공부하기에 시간이 매우 촉박했어서, 눈가리고 아웅식으로 로그인을 구현했다 (로그인을 누르면 로그인 된 홈페이지로 이동되도록...ㅎ)</li>
<li>redux toolkit 또는 react queary를 공부해서 적용할 예정이다.</li>
</ul>
</li>
<li>배포<ul>
<li>배포까지 해야 완벽한 프로젝트를 해냈다고 생각하기 때문이다.</li>
</ul>
</li>
</ol>
</li>
</ul>
<h1 id="🤷-새로-만들기-vs-리팩토링">🤷 새로 만들기 vs 리팩토링</h1>
<ul>
<li>현재 코드가 너무 복잡하고 방대해서 리팩토링을 하는게 나은 것인지, 만들어 놓은 hook을 가져와서 처음부터 다시 시작해야하는지를 고민했다.</li>
<li>물론 새롭게 시작하는 것이 더 빠를 것 같다고 느꼈다. 하지만 나중에 현업에 갔을 때, 매우 불친절한 코드를 리팩토링을 해야할 수 있다는 생각을 했고, 힘들겠지만 나의 코드를 하나하나 뜯어 보면서 리팩토링을 하려고 한다.</li>
</ul>
<h1 id="🥳-오늘의-리팩토링-페이지">🥳 오늘의 리팩토링 페이지</h1>
<h4 id="landingpage">LandingPage</h4>
<ul>
<li>Before &amp; After!</li>
</ul>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/0_right/post/3ef36a20-36dc-452e-928f-7114f692f120/image.png" alt="before"></th>
<th><img src="https://velog.velcdn.com/images/0_right/post/9ceb96fa-9893-4be3-b61a-fb23998b72c3/image.png" alt=""></th>
</tr>
</thead>
</table>
<ul>
<li>사진에서 보여주듯이 Before(왼쪽)은 아이폰 화면으로 봤을 때 40%가량이 잘리는 것을 확인 할 수 있다. 하지만 After(오른쪽)에서는 아이폰 화면으로 봤을 때도 정상적으로 나오는 것을 확인할 수 있다.</li>
<li>해당 부분은 전체 컴포넌트를 MUI Container를 통해 감싸서 크기를 고정시켰고, 기존 px로 margin 및 width height이 설정 되어있었는데 vw를 이용해서 자연스럽게 변경되게 설정하였다.</li>
<li>글자는 MUI Typography를 emtion style로 customizing하여서 media query를 이용하여 글자크기를 수정하였다.</li>
</ul>
<h3 id="느낀점">느낀점</h3>
<ul>
<li>리팩토링을 하기전에 코드를 보고 꽤 걸리겠다고 생각했지만... 생각보다 더 걸렸던 것 같았다.</li>
<li>media query를 이용하기 위해서 emotion으로 mui를 customize를 이용하니 편했던 것 같다.</li>
<li>다른 사람을 위해 또는 미래의 나를 위해.... 함수명과 코드에 신경을 쓰자..!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 2023.02.18]]></title>
            <link>https://velog.io/@0_right/TIL-2023.02.18</link>
            <guid>https://velog.io/@0_right/TIL-2023.02.18</guid>
            <pubDate>Sat, 18 Feb 2023 18:54:22 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-문제">✅ 문제</h1>
<ul>
<li>Next Js로 개발하던 중 mui를 사용하자 오류가 발생함</li>
<li>처음 렌더시에만 오류가 뜨고 화면에 UI가 나타난 뒤에는 문제없이 작동함</li>
</ul>
<h2 id="🔍-원인-파악">🔍 원인 파악</h2>
<p><img src="https://velog.velcdn.com/images/0_right/post/615cfe5e-7f3d-441c-907c-0831266ea79c/image.png" alt=""></p>
<ul>
<li>크롬의 성능 테스트를 통해 알아 봤을 때 mui의 CSS적인 부분에서 오래 걸린다고 생각했다.</li>
</ul>
<h3 id="❗️-문제가-되는-코드">❗️ 문제가 되는 코드</h3>
<h4 id="livestudytsx">LiveStudy.tsx</h4>
<pre><code>&lt;Button
    disabled
    sx={{
    &#39;&amp;.Mui-disabled&#39;: {
    background: &#39;#d9d9d9&#39;,
    color: &#39;white&#39;,
    },
    backgroundColor: &#39;black&#39;,
    color: &#39;white&#39;,
    }}
&gt;
    실시간 수업 바로가기
&lt;/Button&gt;</code></pre><ul>
<li>해당 코드와 같이 MUI를 커스터마이징 하는 부분에서 sx를 통해 계속 css를 수정을 반복하게 되다보니 성능이 저하됐다고 생각했다.</li>
</ul>
<h2 id="👍-해결-방안">👍 해결 방안</h2>
<ul>
<li>Emotion/styled를 통해 MUI를 컴포넌트화 함으로 style을 한번에 처리하면 될것 같다고 생각했다.<pre><code>const LiveButton = styled(Button)`
&amp;.Mui-disabled {
  background-color: #d9d9d9;
  color: white;
}
background-color: black;
color: white;
width: 38.75vw;
`;
</code></pre></li>
</ul>
<p>```</p>
<h3 id="느낀점">느낀점</h3>
<p><img src="https://velog.velcdn.com/images/0_right/post/e0d58586-73a0-46b1-ab29-cfebbacb65c0/image.png" alt="">
<img src="https://velog.velcdn.com/images/0_right/post/fb7137a5-68b2-4d86-87d3-b4707f12466b/image.png" alt=""></p>
<ul>
<li>해당 사진들을 봤을 때 스크립트 평가의 길이가 현저히 줄어든 것을 볼 수 있다.</li>
<li>물론 시간이 줄어들긴 했지만 여전히 줄일 수 있다고 생각이 들었고, 다음번엔 webpack chunk 분리를 통해서 성능을 향상시켜볼 생각이다.</li>
</ul>
<h4 id="📄-참조">📄 참조</h4>
<blockquote>
<p><a href="https://mui.com">https://mui.com</a> 
<a href="https://agilejung.tistory.com/entry/MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">https://agilejung.tistory.com/entry/MUI%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 2023.02.16]]></title>
            <link>https://velog.io/@0_right/TIL-2023.02.16</link>
            <guid>https://velog.io/@0_right/TIL-2023.02.16</guid>
            <pubDate>Sat, 18 Feb 2023 10:51:22 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-문제-1">✅ 문제 1</h1>
<p><img src="https://velog.velcdn.com/images/0_right/post/a46f1492-ab6d-43ae-b6a2-34aaf5300abf/image.png" alt=""></p>
<ul>
<li>내 사이트에서 타사 쿠키(유튜브 쿠키)를 사용하기 때문에 발생한 보안 이슈이다.<h1 id="✅-문제-2">✅ 문제 2</h1>
<img src="https://velog.velcdn.com/images/0_right/post/54ea312b-f8fe-4d30-a50f-ab437f5d9df0/image.png" alt=""></li>
</ul>
<ul>
<li>react-youtube를 사용했을 때 오류가 발생</li>
<li></li>
</ul>
<h2 id="🤷-samesite란">🤷 SameSite란?</h2>
<ul>
<li>사용하려는 쿠키가 타사의 것인지 확인하고, 그것을 사용해도 될 지 체크하는 것이다.</li>
<li>SameSite에는 3가지 값이 있다.<ul>
<li>Strict : 같은 사이트에서만!</li>
<li>Lax : 허용한 사이트에서만 (디폴트값)</li>
<li>None : 모든 사이트에서</li>
</ul>
</li>
</ul>
<h2 id="🔍-원인-파악">🔍 원인 파악</h2>
<h3 id="❔-문제-1">❔ 문제 1</h3>
<ul>
<li>기존에는 Cookie의 SameSite defalut 값이 None으로 설정 되어 있었지만 최근에 Lax로 변경되면서 생긴 오류로 추정된다.</li>
</ul>
<h3 id="❔-문제-2">❔ 문제 2</h3>
<ul>
<li><p>youtube 영상을 제어할 때 postMessage를 이용하여 제어할 수 있는데 보안상의 문제로 타겟 origin을 정확하게 입력하지 않으면 이벤트가 실행되지 않도록 막아서 생긴 문제 같다.</p>
<h3 id="❗️-문제가-되는-코드">❗️ 문제가 되는 코드</h3>
<h4 id="studylisttsx">StudyList.tsx</h4>
  <iframe
         className="youtubeBox"
         src={info.link}
         title="YouTube video player"
         allow="accelerometer; 
         autoplay; 
         clipboard-write; 
         encrypted-media; 
         gyroscope; 
         picture-in-picture"
  ></iframe>

</li>
</ul>
<h2 id="👍-해결-방안">👍 해결 방안</h2>
<ol>
<li>먼저 문제 2번에 대한 해결을 먼저 해야한다고 생각해서, origin을 직접 줬었지만, 해당 오류가 무한으로 발생하던 것에서 8번에 오류로 줄어들었지 근본적인 해결이 되지않았다.</li>
<li>그래서 iframe 태그를 사용하여 직접 구현하였더니 해당 오류가 해결되었다.</li>
<li>1번 문제도 같이 해결될 줄 알았으나 해결되지 않았고, document.tsx에서 <pre><code> document.cookie = &quot;crossCookie=bar; SameSite=None; Secure&quot;</code></pre> 을 통해 쿠키설정을 바꿔보려 시도했으나 NextJs에서 document를 불러오는 방식이 달라서 해당 부분을 수정하지 못했다.<h3 id="느낀점">느낀점</h3>
</li>
</ol>
<ul>
<li>나름 오랜시간 고민하고 알아보았지만 근본적으로 해결하지 못한것 같다. cookie에 대해 공부를 해보며 NextJs에서 cookie설정 하는 방법을 다시 공부해보고 수정하려 한다.</li>
<li>또한 react-youtbe에서 영상의 동작을 조절하는 방법에대해 공부해야할 것 같다.</li>
</ul>
<h4 id="📄-참조">📄 참조</h4>
<blockquote>
<p><a href="https://kenchoi.tistory.com/13">https://kenchoi.tistory.com/13</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 2023.02.15]]></title>
            <link>https://velog.io/@0_right/TIL-2023.02.15</link>
            <guid>https://velog.io/@0_right/TIL-2023.02.15</guid>
            <pubDate>Wed, 15 Feb 2023 11:05:34 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-문제">✅ 문제</h1>
<p><img src="https://velog.velcdn.com/images/0_right/post/f3e46fc6-e9af-42a6-b2f2-60dbeabd25f0/image.png" alt=""></p>
<ul>
<li>Next Js로 개발하던 중 mui를 사용하자 오류가 발생함</li>
<li>처음 렌더시에만 오류가 뜨고 화면에 UI가 나타난 뒤에는 문제없이 작동함</li>
</ul>
<h2 id="🤷-hydration이란">🤷 Hydration이란?</h2>
<blockquote>
<p>Hydration은 수분 공급이라는 뜻을 가진 영어 단어이다. 하지만 개발 언어의 Hydration은 어떻게 다른지 알아보자.</p>
</blockquote>
<ul>
<li>Next Js는 SSR(Server Side Rendering)과 CSR(Client Side Rendering)을 병행해서 사용합니다.</li>
<li>여기서 SSR의 치명적인 단점이 발생합니다. 그 단점으로는 SSR은 HTML을 그려줄 수는 있어도 실제로 브라우저가 렌더링 한 것이 아니기 때문에 Javascript의 코드를 DOMElement와 매칭시켜서 <code>동적인 페이지를 구현하지는 못한다</code>는 것입니다.</li>
<li>SSR로 인해 렌더링 된 HTML 페이지는 뼈대만 존재하는 <code>바싹 마른 형태</code>로 존재하게 됩니다.</li>
<li>이때 <code>수분 공급</code>을 해주는 것을 Hydration이라고 합니다.<pre><code>Hydrate는 DOM tree에 해당되는 DOM 요소를 찾아 자바스크립트 속성(이벤트 리스너 등)들을 부착하는 일을 말합니다.</code></pre></li>
</ul>
<h3 id="장점">장점</h3>
<ol>
<li><p>초기 로딩속도 감소</p>
<ul>
<li>Pre-Renderingn된 Document는 자바스크립트 요소가 빠진 가벼운 상태이기 때문에 클라이언트 측에서 빠르게 로딩이 가능한 장점이 있습니다.</li>
</ul>
</li>
<li><p>검색엔진 최적화</p>
</li>
</ol>
<h2 id="🔍-원인-파악">🔍 원인 파악</h2>
<ul>
<li>ssr에서 처음에 내려주는 UI(pre-render)와 브라우저에서 첫 번째로 렌더되는 UI 트리간에 차이가 있기 때문에 난 문제다.</li>
<li>첫 번째 렌더는 React의 특징인 Hydration이라고 불린다.</li>
<li>즉, React 트리가 DOM과 동기화되지 않아 발생하게 되는 문제다.</li>
</ul>
<h3 id="❗️-문제가-되는-코드">❗️ 문제가 되는 코드</h3>
<h4 id="studypagetsx">studyPage.tsx</h4>
<pre><code>&lt;Box
          sx={{
            width: &#39;100vw&#39;,
            borderBottom: &#39;1px solid black&#39;,
            display: &#39;flex&#39;,
            justifyContent: &#39;center&#39;,
            alignItems: &#39;center&#39;,
          }}
        &gt;
          &lt;Tabs
            value={value}
            onChange={handleChange}
            textColor=&quot;primary&quot;
            indicatorColor=&quot;none&quot;
            sx={{
              &#39;&amp; button:active&#39;: { backgroundColor: &#39;black&#39; },
              &#39;&amp; button.Mui-selected&#39;: {
                backgroundColor: &#39;black&#39;,
                color: &#39;#dcfc73&#39;,
                border: &#39;1px solid white&#39;,
              },
              width: &#39;59.16vw&#39;,
            }}
          &gt;
            &lt;Tab
              value={0}
              label=&quot;강의 목록&quot;
              sx={{
                width: &#39;100%&#39;,
                maxWidth: &#39;50%&#39;,
                borderLeft: &#39;1px solid black&#39;,
              }}
            /&gt;
            &lt;Tab
              value={1}
              label=&quot;실시간 수업&quot;
              sx={{
                width: &#39;100%&#39;,
                maxWidth: &#39;50%&#39;,
                borderRight: &#39;1px solid black&#39;,
              }}
            /&gt;
          &lt;/Tabs&gt;
        &lt;/Box&gt;
        &lt;Box sx={{ padding: 2, width: &#39;59.16vw&#39; }}&gt;
          {value === 0 &amp;&amp; (
            &lt;Typography&gt;
              &lt;StudyList studyList={studyData.lecture} /&gt;
            &lt;/Typography&gt;
          )}
          {value === 1 &amp;&amp; &lt;Typography&gt;The second tab&lt;/Typography&gt;}
        &lt;/Box&gt;</code></pre><h4 id="studylisttsx">StudyList.tsx</h4>
<pre><code>const StudyList = (studyList: StudyListType) =&gt; {
  const list = studyList.studyList;

  return (
    &lt;&gt;
      {Object.entries(list).map(([week, data]) =&gt; (
        &lt;div key={week}&gt;
          &lt;div key={week}&gt;{week}&lt;/div&gt;
          {Object.entries(data).map(([lecture, info]) =&gt; (
            &lt;div key={lecture}&gt;
              &lt;Accordion&gt;
                &lt;AccordionSummary
                  expandIcon={&lt;ArrowDropDownIcon /&gt;}
                  aria-controls=&quot;panel1a-content&quot;
                  id=&quot;panel1a-header&quot;
                &gt;
                  &lt;Typography&gt;
                    {lecture} {info.title}
                  &lt;/Typography&gt;
                &lt;/AccordionSummary&gt;
                &lt;AccordionDetails&gt;유튜부 영상&lt;/AccordionDetails&gt;
              &lt;/Accordion&gt;
            &lt;/div&gt;
          ))}
        &lt;/div&gt;
      ))}
    &lt;/&gt;
  );
};</code></pre><ol>
<li>MUI Box, Tabs, Tab을 통해 studyList.tsx에 Tab기능을 구현했고, 밑에 Box를 만들어 Tab을 클릭 했을때 나와야하는 컴포넌트를 불러오게 설정했다.<pre><code>     &lt;Box sx={{ padding: 2, width: &#39;59.16vw&#39; }}&gt;
       {value === 0 &amp;&amp; (
         &lt;Typography&gt;
           &lt;StudyList studyList={studyData.lecture} /&gt;
         &lt;/Typography&gt;
       )}
       {value === 1 &amp;&amp; &lt;Typography&gt;The second tab&lt;/Typography&gt;}
     &lt;/Box&gt;</code></pre><ol start="2">
<li>StudyList를 불러오는 과정에서 Hydration error가 발생함을 찾아냈고, 처음에는 StudyList 자체가 오류인가 싶어서 StudyList 컴포넌트를 독립적으로 출력해봤는데 문제가 없었고, 해당 코드에 문제가 있다고 생각했다.</li>
</ol>
</li>
</ol>
<h2 id="👍-해결-방안">👍 해결 방안</h2>
<ol>
<li>사실 문제는 생각보다 간단했다. MUI의 코드대로 tab요소를 출력하는 방법을 이해하지 않고 그대로 쓰려고 했기때문에 발생한 결과였다. <pre><code> &lt;Typography&gt;
       &lt;StudyList studyList={studyData.lecture} /&gt;
 &lt;/Typography&gt;</code></pre></li>
<li>해당 부분은 요소의 순서에 맞지 않은 방법이다. 왜냐하면 해당 코드는 결국 <code>&lt;p&gt;태그 안에 &lt;div&gt; 태그</code>가 있는 형태였기 때문이였다.</li>
</ol>
<h3 id="느낀점">느낀점</h3>
<ul>
<li>사실 처음에 오류가 너무 많이 뜨고, hydration에 대한 이해가 전혀 없었기 때문에 어려운 문제일거라고 겁을 먹어 스스로 문제에 대한 접근을 어렵게 했던 것 같다.</li>
<li>문제의 뿌리인 hydration에 대해 정리를 하다보니 ui를 그리는 과정에서 문제가 발생했다는 것을 알게 되었고, 코드를 봤을 때 <p>태그 안에 <div>태그가 있다는 것을 깨닫고 참 간단한 문제였다고 생각했다.</li>
<li>mui를 쓰더라도 해당 코드가 어떻게 작동하는지 정확히 파악해야겠다는 생각이 든 하루였다!</li>
</ul>
<h4 id="📄-참조">📄 참조</h4>
<blockquote>
<p><a href="https://www.univdev.page/posts/nextjs-hydration/">https://www.univdev.page/posts/nextjs-hydration/</a>
<a href="https://velog.io/@jhplus13/NextJS-React-Hydration-Error-%ED%95%B4%EA%B2%B0%EA%B8%B0">https://velog.io/@jhplus13/NextJS-React-Hydration-Error-%ED%95%B4%EA%B2%B0%EA%B8%B0</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[💻 TIL 2023.02.08]]></title>
            <link>https://velog.io/@0_right/TIL-2023.02.08</link>
            <guid>https://velog.io/@0_right/TIL-2023.02.08</guid>
            <pubDate>Wed, 08 Feb 2023 11:10:49 GMT</pubDate>
            <description><![CDATA[<h1 id="1-뒤에-있는-큰-수-찾기level-2">1. 뒤에 있는 큰 수 찾기(level 2)</h1>
<h3 id="--문제">- 문제</h3>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/154539">https://school.programmers.co.kr/learn/courses/30/lessons/154539</a></p>
</blockquote>
<h3 id="--코드-작성-전-생각">- 코드 작성 전 생각</h3>
<ol>
<li>단순히 while 문을 돌면서 numList, firstNumber를 만들고 numList.map을 통해 firstNumber보다 크면 멈추고 numberList를 pop하자는 생각이였다.</li>
</ol>
<ul>
<li><p>해당 생각은 틀렸다</p>
<ul>
<li><p>첫번째 
javaScript의 es6 함수 (즉, 고차함수 map, filter ...)는 break가 작동하지 않는다. 그 이유는 공식문서에서 찾았다.</p>
<blockquote>
</blockquote>
<p>Description
map calls a provided callback function once for each element in an array,       in order, and constructs a new array from the results. callback is invoked      only for indexes of the array which have assigned values (including             undefined).
요약하자면 주어진 input array의 길이만큼 iterator를 돌리면서 그때마다 callback 함수를 돌린다. 즉, callback을 호출한 순간 Loop의 역할은 끝나고 Loop의 중간에 break를 걸 수 없게 되는 것이다.</p>
</li>
<li><p>두번째 
고차함수를 사용하지 않고 for문을 이용하여 코드를 작성했다. 하지만 문제의 numbers의 크기를 고려하지 않고 생각 없이 코드를 짰기 때문에 시간 복잡도가 1,000,000,000,000으로 너무 커져 시간초과가 발생했다.</p>
<pre><code>const solution = (numbers) =&gt; {
let answer = [];
while(numbers.length &gt; 0){
   const firstNum = numbers[0];
   const numList = numbers.slice(1);
   let isBiggest = true;

   for(let i = 0; i &lt; numList.length; i++){
       console.log(firstNum, numList[i])
       if(numList[i] &gt; firstNum){
           answer.push(numList[i]);
           isBiggest = false;
           numbers = numList;
       }
   }
   if(isBiggest === true) {
       answer.push(-1);
       numbers = numList;
   }

}
return answer;
}</code></pre></li>
</ul>
</li>
</ul>
<h3 id="--구현-중-추가-된-항목">- 구현 중 추가 된 항목</h3>
<ol>
<li>for문을 먼저 사용하여 안에서 while문의 조건을 달아보자고 생각했다.<ul>
<li>stack 에는 numbers의 원소의 인덱스들이 들어간다.</li>
<li>while 문에서는 stack의 마지막 인덱스의 value와 numbers[i] 값과 비교하여 pop해줌으로써 뒤큰수가 없는 인덱스가 남도록한다.</li>
<li>마지막으로 stack 에 남아있는 인덱스들은 뒤큰수가 없는 원소들이므로 해당 인덱스자리에는 -1로 채워 넣음으로 최종적으로는 answer 배열을 반환한다.</li>
</ul>
</li>
</ol>
<h3 id="--코드">- 코드</h3>
<pre><code>const solution = (numbers) =&gt; {
    let answer = new Array(numbers.length).fill(0);
    let stack = []
    for(let i = 0; i &lt; numbers.length; i++){
            while (stack.length &gt; 0 &amp;&amp; numbers[stack[stack.length-1]] &lt; numbers[i]){
                answer[stack.pop()] = numbers[i]
            }
            stack.push(i)

    }
    while (stack.length &gt; 0){
            answer[stack.pop()] = -1
    }

    return answer;
}</code></pre><h1 id="2-시소-짝꿍level-2">2. 시소 짝꿍(level 2)</h1>
<h3 id="--문제-1">- 문제</h3>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/152996">https://school.programmers.co.kr/learn/courses/30/lessons/152996</a></p>
</blockquote>
<h3 id="--코드-작성-전-생각-1">- 코드 작성 전 생각</h3>
<ol>
<li>위치에 따른 경우의 수는 4가지만 존재 한다 (1,1) (2,3) (2,4) (3,4) 거리에 따른 경우</li>
<li>거리에 따른 비율을 가지고 있는 변수 ratio에 [1,3/2,2,4/3]을 생성한다.</li>
<li>weights를 정렬시켜 큰수부터 store에 개수를 넣어가면서 저장한다.<h3 id="--구현-중-추가-된-항목-1">- 구현 중 추가 된 항목</h3>
</li>
<li>store[현재무게]에 값이 없으면 1을 넣어주고 있다면 +1 을 해주는 식으로 진행해야한다.<h3 id="--코드-예시-50100200100-기준">- 코드 예시 [50,100,200,100] 기준</h3>
<ol>
<li>weights = [200,100,100,50]</li>
<li>w = 200 store = { 200 : 1} </li>
<li>w = 100 해당 함수에 의해 store[200]에 값이 존재 하기 때문에 answer += store[200] 이된다.<pre><code>cal.forEach((i)=&gt;{
      if( s = w * i, store[s] ){ //해당 비율을 곱한 값이 store에 존재할 경우
        answer += store[s];
      }
  });</code></pre></li>
</ol>
</li>
<li>해당 로직을 반복하며 총 5의 값이 나오게 된다.</li>
</ol>
<h3 id="--코드-1">- 코드</h3>
<pre><code>const solution = (weights) =&gt; {
  let answer = 0;
  const store = {};
  const ratio = [1, 3 / 2, 2, 4 / 3];

  weights
    .sort((a, b) =&gt; b - a)
    .forEach((w) =&gt; {
      let s;
      ratio.forEach((i) =&gt; {
        if (((s = w * i), store[s])) {
          answer += store[s];
        }
      });
      if (!store[w]) store[w] = 1;
      else store[w]++;
    });
  return answer;
};
</code></pre><h1 id="3-숫자-타자-대회level-3">3. 숫자 타자 대회(level 3)</h1>
<h3 id="--문제-2">- 문제</h3>
<blockquote>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/136797">https://school.programmers.co.kr/learn/courses/30/lessons/136797</a></p>
</blockquote>
<h3 id="--코드-작성-전-생각-2">- 코드 작성 전 생각</h3>
<ol>
<li>먼저 문자열에서 110을 모두 찾아서 제거한다. </li>
<li>문자열을 처음부터 끝까지 돌면서, stack의 길이가 2보다 작다면, 그냥 stack에 해당 글자를 push. 아니라면 stack을 2번 pop해서 110을 이루는 지확인하고, 110이라면 tmp에 110을 더하고, 아니라면 다시 stack에 돌려놓는다.</li>
<li>반복이 끝나면 남은 문자열 tmp를 return한다.</li>
<li>return한 문자열이 비었다면 str을 그대로 push한다.</li>
<li>그렇지 않다면 마지막 0의 뒤에 저장한 110들을 넣어준다 =&gt; 이유는 모든 110을 빼냈기 때문에 남은 stack에는 11이 두개 이상 나올 수 없기 때문이다.</li>
</ol>
<p>=&gt; 예를 들어 [&quot;0111101100011110&quot;]의 경우 나와야하는 값은 [&quot;0011011011011011&quot;]이다.</p>
<h3 id="--구현-중-추가-된-항목-2">- 구현 중 추가 된 항목</h3>
<ol>
<li>마지막 0의 위치를 찾는데 js의 lastIndexOf를 사용하면 바로 찾을 수 있었다.</li>
<li>정규표현식을 이용해 풀 수 있을 것 같다는 생각이 들었다. 금요일에 시도해 볼 예정</li>
</ol>
<h3 id="--코드-2">- 코드</h3>
<pre><code>const answer = [];
const solution = (s) =&gt; {
  for (let t = 0; t &lt; s.length; t++) {
    let str = s[t];
    let stack = [];
    let target = findTarget(str, stack);
    if (target == &quot;&quot;) answer.push(str);
    else {
      const tmpStr = stack.join(&quot;&quot;);
      const idx = tmpStr.lastIndexOf(&quot;0&quot;) + 1;
      answer.push(tmpStr.substring(0, idx) + target + tmpStr.substring(idx));
    }
  }
  return answer;
};
const findTarget = (str, stack) =&gt; {
  let target = &quot;&quot;;
  for (let i = 0; i &lt; str.length; i++) {
    const c = str.charAt(i);
    if (stack.length &gt;= 2) {
      const b = stack.pop();
      const a = stack.pop();
      if (a == &quot;1&quot; &amp;&amp; b == &quot;1&quot; &amp;&amp; c == &quot;0&quot;) {
        target += &quot;110&quot;;
        continue;
      }
      stack.push(a);
      stack.push(b);
    }
    stack.push(c);
  }
  return target;
};
</code></pre>]]></description>
        </item>
    </channel>
</rss>