<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Lr_jeong.log</title>
        <link>https://velog.io/</link>
        <description>끊임없이 노력하는 프론트엔드 개발자 (⸝⸝⍢⸝⸝) ෆ</description>
        <lastBuildDate>Thu, 23 Mar 2023 05:45:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Lr_jeong.log</title>
            <url>https://velog.velcdn.com/images/na_jeong/profile/20bcfc5e-10a4-4193-a04d-b6101fed9cb1/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Lr_jeong.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/na_jeong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Nuxt.js]Nuxt의 비동기 데이터 호출 방법]]></title>
            <link>https://velog.io/@na_jeong/Nuxt.jsNuxt%EC%9D%98-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%98%B8%EC%B6%9C-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@na_jeong/Nuxt.jsNuxt%EC%9D%98-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%98%B8%EC%B6%9C-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 23 Mar 2023 05:45:52 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Nuxt는 서버 사이드 렌더링 프레임워크이기 때문에 뷰 싱글 페이지 애플리케이션과 REST API를 호출하는 방식을 다르게 접근해야 한다.</p>
</blockquote>
<h2 id="🤔nuxt의-rest-api-호출-방식">🤔Nuxt의 REST API 호출 방식</h2>
<ul>
<li>asyncData</li>
<li>fetch</li>
</ul>
<h3 id="💡asyncdata">💡asyncData</h3>
<p>asyncData는 페이지 컴포넌트에만 제공되는 속성이다.
asyncData로 아래와 같이 서버 데이터를 호출할 수 있다.</p>
<pre><code>&lt;!-- pages/user.vue --&gt;
&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;{{ user }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import axios from &#39;axios&#39;;

export default {
  // params의 id가 1이라고 가정
  async asyncData({ params, $http }) {
    const response = await axios.get(`/users/${params.id}`);
    const user = response.data;
    return { user }
  }
}
&lt;/script&gt;</code></pre><p>위 코드는 /user 로 접근할 때 user.vue 컴포넌트를 화면에 그리기 전에 데이터를 요청하는 코드이다.
데이터를 다 받아와야지만 <template></template> 영역의 코드를 화면에 표시한다.
마치 싱글 페이지 애플리케이션의 뷰 라우터에서 네비게이션 가드에서 데이터를 호출하고 받아왔을 때 페이지를 진입하는 것과 같다.</p>
<h4 id="✅asyncdata의-파라미터">✅asyncData의 파라미터</h4>
<p>asyncData 속성의 파라미터는 context 속성이다.
context 속성은 nuxt 프레임워크 전반에 걸쳐 공용으로 사용되는 속성으로써 플러그인, 미들웨어 등의 속성에서도 접근할 수 있다. 컨텍스트에는 스토어, 라우터 관련 정보뿐만 아니라 서버 사이드에서 요청, 응답 관련된 속성도 접근할 수 있다.</p>
<h3 id="💡fetch">💡fetch</h3>
<p>fetch는 페이지 컴포넌트 뿐만 아니라 일반 뷰 컴포넌트에서도 사용할 수 있는 데이터 호출 속성이다.
fetch는 다음 2가지 상황에서 호출된다.</p>
<ul>
<li>서버 사이드 렌더링을 위해 서버에서 화면을 구성할 때 컴포넌트가 생성되고 나서 실행</li>
<li>브라우저에서 URL 주소를 변경해서 페이지를 이동할 때</li>
</ul>
<p>아래에는 예제 코드</p>
<pre><code>&lt;!-- components/UserProfile.vue --&gt;
&lt;template&gt;
  &lt;div&gt;{{ user }}&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import axios from &#39;axios&#39;;

export default {
  data() {
    return {
      user: {},
    }
  },
  async fetch() {
    const res = await axios.get(&#39;https://jsonplaceholder.typicode.com/users/1&#39;);
    this.user = res.data;
  },
}
&lt;/script&gt;
</code></pre><p>fetch를 사용하면 컴포넌트가 화면에 먼저 뿌려지고 나서 fetch 호출이 실행된다.
따라서 페이지를 이동하고 나면 데이터를 받아오는 동안 빈 페이지가 보이고 잠시 후에 받아온 데이터가 화면에 그려지게 된다.</p>
<h4 id="✅fetch-특징">✅fetch 특징</h4>
<p>• 페이지 컴포넌트 뿐만 아니라 일반 컴포넌트에서도 사용이 가능하다.
• fetch의 return 값은 Promise 이다.
• fetch는 asyncData와 다르게 아래와 같은 속성들을 제공한다.</p>
<ul>
<li><span style='color:orange'>$fetchState</span> : 데이터 호출 상태를 나타내는 속성이며 인스턴스로 접근할 수 있따. 호출 상태에 따라 pending, error, timestamp를 제공한다.</li>
<li><span style='color:orange'>$fetch</span> : fetch 로직을 다시 실행시킬 수 있는 함수이다.</li>
<li><span style='color:orange'>fetchOnServer</span> : 서버 사이드 렌더링 시에 서버에서 fetch를 실행할지 말지 결정하는 속성이다. 기본값은 true</li>
<li><span style='color:orange'>fetchDelay</span> : 실행 시간을 설정한다. 기본값은 200</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Nuxt.js]Nuxt.js 시작하기]]></title>
            <link>https://velog.io/@na_jeong/Nuxt.jsNuxt.js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@na_jeong/Nuxt.jsNuxt.js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 21 Mar 2023 08:20:22 GMT</pubDate>
            <description><![CDATA[<h2 id="🧐nuxtjs-시작하기">🧐Nuxt.js 시작하기</h2>
<p>프로젝트를 구성하기 위해서는 아래의 명령어를 입력하면 된다.</p>
<pre><code>npm init nuxt-app 프로젝트명</code></pre><p>명령어를 입력하면 설정을 할 수 있다.
<img src="https://velog.velcdn.com/images/na_jeong/post/b062f1f8-7244-4e24-93c8-92e61f3e24ee/image.png" alt=""></p>
<p>자신의 환경에 맞게 설정한 후 enter를 누르면 프로그램 생성 완료!
프로젝트가 생성되고 나면,
<img src="https://velog.velcdn.com/images/na_jeong/post/a23eeb5b-a92b-4c03-be6d-15f98ea388d6/image.png" alt=""></p>
<p>어디로 이동해서 어떻게 실행하는지 알려준다.</p>
<h2 id="🧐nuxtjs-디렉토리-구조">🧐Nuxt.js 디렉토리 구조</h2>
<blockquote>
<p>.nuxt directory는 이른바 빌드 디렉토리 라고 한다!
.nuxt directory는 기본적으로 동적으로 생성되고 숨겨진다. nuxt dev 또는 nuxt build를 실행할 때 자동으로 생성되므로 .gitignore를 통해 무시해야한다.</p>
</blockquote>
<p><span style='backgroundColor: lightgray'>assets</span> </p>
<ul>
<li>css, image, font와 같은 리소스들을 포함</li>
<li>nuxt.config에서 css 속성을 사용하여 스타일을 추가할 수 있음<pre><code>export default {
css: [
  // Load a Node.js module directly (here it&#39;s a Sass file)
  &#39;bulma&#39;,
  // CSS file in the project
  &#39;~/assets/css/main.css&#39;,
  // SCSS file in the project
  &#39;~/assets/css/main.scss&#39;
]
}</code></pre></li>
</ul>
<p><span style='backgroundColor: lightgray'>components</span></p>
<ul>
<li>애플리케이션에서 사용될 컴포넌트들을 포함</li>
<li>해당 경로에 위치된 컴포넌트들은 Nuxt.js의 비동기 데이터 함수인 asyncData 또는 fetch를 사용할 수 없음</li>
</ul>
<p><span style='backgroundColor: lightgray'>layouts</span></p>
<ul>
<li>애플리케이션 전체에 대한 레이아웃을 포함</li>
<li>기본으로 default.vue가 생성되어 있다.</li>
<li>해당 디렉터리는 이름을 변경할 수 없다.</li>
</ul>
<p><span style='backgroundColor: lightgray'>middleware</span></p>
<ul>
<li>애플리케이션에서 사용될 middleware를 포함</li>
<li>middleware는 페이지 또는 레이아웃이 렌더링되기 전에 실행된다.</li>
<li>middleware를 페이지나 레이아웃에 바인딩하였다면 해당 페이지나 레이아웃이 실행되기 전에 매번 실행됨</li>
</ul>
<p><span style='backgroundColor: lightgray'>node_modules</span></p>
<ul>
<li>Nuxt Module은 Nuxt 프레임워크의 핵심 기능을 확장하고 통합 및 추가를 할 수 있다.</li>
<li>사용자가 직접 모듈을 작성할 수 있다.</li>
</ul>
<p><span style='backgroundColor: lightgray'>pages</span></p>
<ul>
<li>실제 어플리케이션의 페이지 구성을 포함</li>
<li>이 디렉토리의 구조에 따라 router가 자동으로 생성된다.</li>
<li>해당 디렉토리는 이름을 변경할 수 없다.</li>
</ul>
<p><span style='backgroundColor: lightgray'>plugins</span></p>
<ul>
<li>애플리케이션에 바인딩될 외부 혹은 내부 plugins를 포함</li>
<li>애플리케이션이 인스턴스화 되기 전에 실행하며 전역적으로 구성 요소를 등록하고 함수 또는 상수를 삽입할 수 있다.</li>
</ul>
<p><span style='backgroundColor: lightgray'>static</span></p>
<ul>
<li>정적 파일을 포함</li>
<li>구성에 따라 html, javascript 파일도 포함시킬 수 있다.</li>
<li>해당 디렉토리는 이름을 변경할 수 없다.</li>
</ul>
<p><span style='backgroundColor: lightgray'>store</span></p>
<ul>
<li>애플리케이션에서 사용된 vuex store 파일들을 포함</li>
<li>기본적으로 비활성화 상태이고 store 디렉토리에 index.js 파일을 작성하면 활성화된다.</li>
<li>구성에 따라서 모듈 형태의 store를 형성할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue]vuex - Helper함수]]></title>
            <link>https://velog.io/@na_jeong/Vuevuex-Helper%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@na_jeong/Vuevuex-Helper%ED%95%A8%EC%88%98</guid>
            <pubDate>Fri, 17 Mar 2023 08:28:04 GMT</pubDate>
            <description><![CDATA[<h2 id="👩💻helper">👩‍💻Helper</h2>
<h4 id="각-속성들을-더-쉽게-사용하는-방법이다">각 속성들을 더 쉽게 사용하는 방법이다.</h4>
<p>Store에 있는 아래 4가지 속성들을 간편하게 코딩하는 방법</p>
<ul>
<li>state -&gt; mapState</li>
<li>getteres -&gt; mapGetters</li>
<li>mutations -&gt; mapMutations</li>
<li>actions -&gt; mapActions</li>
</ul>
<h3 id="📌헬퍼의-사용법">📌헬퍼의 사용법</h3>
<p>헬퍼를 사용하고자 하는 vue 파일에서 아래와 같이 해당 헬퍼를 로딩한다.
<strong>필요한 속성의 키값을 배열로 입력</strong>하고, <strong>객체 전개 연산자(ES6 문법)로 적용</strong>한다.</p>
<pre><code>//App.vue
import { mapState, mapGetters, mapMutations, mapActions } from &#39;vuex&#39;

export default {
    computed() {
        ...mapState([&#39;num&#39;], ...mapGetters([&#39;countedNum&#39;])
    },

    methods: {
        ...mapMutations([&#39;clickBtn&#39;]), ...mapActions([&#39;asyncClickBtn&#39;])
    }
}</code></pre><h3 id="📌mapstate">📌mapState</h3>
<p>Vuex에 선언한 state 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
computed()에 선언한다.</p>
<pre><code>//App.vue
import { mapState } from &#39;vuex&#39;

computed() {
    ...mapState([&#39;num&#39;])
    //num() { return this.$store.state.num; } 과 같음
}

//store.js
state: {
    num: 10
}

&lt;p&gt;{{ this.num }}&lt;/p&gt;
</code></pre><h3 id="📌mapgetters">📌mapGetters</h3>
<p>Vuex에 선언한 state 속성을 뷰 컴포넌트에 더 쉽게 연결해주는 헬퍼
computed()에 선언한다.</p>
<pre><code>//App.vue
import { mapGetters } from &#39;vuex&#39;

computed() {
    ...mapGetters([&#39;reverseMsg&#39;])
}

//store.js
getters: {
    reverseMsg(state) {
        return state.msg.split(&#39;&#39;).reverse().join(&#39;&#39;);
    }
}

&lt;p&gt;{{ this.reverseMsg }}&lt;/p&gt;
</code></pre><h3 id="📌mapmutations">📌mapMutations</h3>
<p>Vuex에 선언한 메서드들을 Vue 컴포넌트에 더 쉽게 연결해주는 헬퍼
methods 필드에 선언한다.</p>
<pre><code>//App.vue
import { mapMutations } from &#39;vuex&#39;

methods: {
    ...mapMutations([&#39;clickBtn&#39;]),
    authLogin() {},
    displayTable() {}
}

//store.js
mutations: {
    clickBtn(state) {
        alert(state.msg);
    }
}

//component
&lt;button @click=&quot;clickBtn&quot;&gt;popup message&lt;/button&gt;</code></pre><h3 id="📌mapactions">📌mapActions</h3>
<p>Vuex에 선언한 메서드들을 Vue 컴포넌트에 더 쉽게 연결해주는 헬퍼
methods 필드에 선언한다.</p>
<pre><code>//App.vue
import { mapActions } from &#39;vuex&#39;

methods: {
    ...mapActions([&#39;delayClickBtn&#39;]),
}

//store.js
actions: {
    delayClickBtn(context) {
        setTimeout(() =&gt; context.commit(&#39;clickBtn&#39;), 2000);
    }
}

//component
&lt;button @click=&quot;delayCLickBtn&quot;&gt;delay popup message&lt;/button&gt;</code></pre><h3 id="헬퍼의-유연한-문법">헬퍼의 유연한 문법</h3>
<p><strong>Vuex에 선언한 속성을 그래도 컴포넌트에 연결하는 문법</strong></p>
<pre><code>//배열 리터럴
...mapMutations({
    &#39;clickBtn&#39;, //&#39;clickBtn&#39; : clickBtn
    &#39;addNumber&#39; //addNumber(인자)
])</code></pre><p><strong>Vuex에 선언한 속성을 컴포넌트의 특정 메서드에다가 연결하는 문법</strong></p>
<pre><code>//객체 리터럴
...mapMutations({
    popupMsg: &#39;clickBtn&#39; //컴포넌트 메서드 명 : Store의 mutation 명
})</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[2차 프로젝트 회고]]></title>
            <link>https://velog.io/@na_jeong/2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@na_jeong/2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 10 Feb 2023 06:19:46 GMT</pubDate>
            <description><![CDATA[<h2 id="🛫프로젝트-소개">🛫프로젝트 소개</h2>
<p>2차 프로젝트로 세계 최대의 숙박 공유 서비스(Airbnb)를 모델링 한 Abnb 웹 사이트를 선정하였다.
<img src="https://velog.velcdn.com/images/na_jeong/post/47b5069e-5d8d-4e19-b20d-ff877bd6c702/image.png" alt=""></p>
<p>에어비엔비 라는 사이트는 단순 거주 목적의 숙박 플랫폼이 아니라, 그들의 일상을 공유할 수 있다고 생각 했다. </p>
<p>에어비엔비의 브랜드 슬로건은 &#39;어디에서나 우리집처럼&#39; 이다.
여행자들이 머무는 곳 이상의 다양한 경험을 찾을 수 있는 플랫폼으로, 물리적 숙소대여의 개념을 벗어나 게스트가 여행지를 마치 현지인처럼 즐길 수 있도록 특별한 기회를 제공한다.</p>
<p>UI/UX적으로 접근 했을때에도, 다른 숙박시설과는 다른 관점에서 categorization을 함으로써, 호기심을 자극하고, 여행 욕구를 더욱 자극 시킨다고 생각하였다.</p>
<p>이에 우리 Abnb도 여행 욕구를 자극 시킬 수 있는 사이트를 진행하기로 하였다.</p>
<blockquote>
</blockquote>
<p>💡개발 기간
2022/12/23 ~2023/01/05
💡기술 스택
FrontEnd : React, Javascript, Styled Components
BackEnd : JavaScript, Node.js, MySQL, Rest
common : Trello, slack</p>
<p>1차 프로젝트 때와 마찬가지로 Project Manager를 맡게 되었다.
이미 1차때 일정 조율과 Front, Back간의 소통의 중요성을 알았기 때문에 잘할 수 있을 것 같다는 생각이 들었다.
프로젝트 매니저로써 팀과 소통할 수 있는 slack 채널과 , Trello 관리를 하고, 2차 프로젝트에선 Pigma툴을 사용하여, 팀원들이 구현해야 하는 페이지들을 정리해 조금 더 편하게 화면 구성을 하도록 하였다.</p>
<h2 id="🛫구현-사항">🛫구현 사항</h2>
<p>로그인 및 회원가입
메인페이지
검색 Bar
리스트 페이지
상세 페이지
✅호스트 페이지</p>
<p>Abnb에 필요한 필수 구현사항은 총 6개가 있었는데, 나는 그 중에서 호스트 페이지 구현을 담당하였다.
호스트 페이지는 총 9개의 페이지로 구성되어 있다.</p>
<h2 id="🛫구현-영상">🛫구현 영상</h2>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/61d3cf96-816a-430a-becd-1756d6925e70/image.gif" alt=""></p>
<p>각 단계로 이동마다 url 이동은 없고, 카카오 맵 api를 사용하여, 지도 검색 및 마커를 띄우도록 해주었다.
다음 버튼을 누를때마다 사용자가 선택한 사항이 INITFORM이라는 배열에 담겨 차곡차곡 쌓여 나가도록 해주었다.</p>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/0bb212cd-d380-4aba-8388-b5f1e94a87d9/image.gif" alt=""></p>
<p>다음은 사진 추가!
사진은 5장이상 선택하도록 해주었고, image의 length를 비교하여 5장이상 등록을 안하면 다음으로 넘어가지 않도록 하였다.
사진을 업로드 했을 때, 미리보기를 할 수 있도록 구현하였다.</p>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/1ab8907e-7bd5-49a2-b5f2-5e7e23142301/image.gif" alt=""></p>
<p>마지막으로 이름, 설명, 가격을 작성하면 호스트가 작성한 모든 숙소 정보를 검토할 수 있는 검토 페이지까지 나오게 된다.</p>
<h2 id="🛫이미지-다중-업로드-및-미리보기">🛫이미지 다중 업로드 및 미리보기</h2>
<p>구현하면서 가장 어려웠던 코드는 다중 이미지 업로드 였다.
<img src="https://velog.velcdn.com/images/na_jeong/post/4fcbad5d-a514-4ab7-bd58-d6324ab99249/image.png" width=40% />
업로드를 사용할때는 label 태그를 사용해주고, input태그에 type=&#39;file&#39; multiple을 써주면 다중으로 업로드가 가능하다. 이러한 코드들은 별로 어렵지 않게 구현 할 수 있었다.</p>
<h4 id="🧐미리보기">🧐미리보기..!</h4>
<p>사진을 첨부할 때마다, 미리보기를 구현하게 까다로웠다. 이미지의 <strong>상대경로</strong>를 알아내서 src에 그 상대경로를 사용해야 미리보기를 할 수 있기 때문이다.</p>
<p><strong>상대경로</strong>는 어떻게 알아내야 할까?
<strong><span style="color:red">URL.createObjectUrl()</span></strong>메소드를 사용하면 된다.
URL.createObjectUrl() 메소드는 주어진 객체를 가리키는 URL을 DOMString으로 변환하는 기능을 한다.</p>
<p>이미지를 선택 후 file 객체를 URL.createObjectUrl() 메소드를 사용해주면 아래 이미지처럼 상대경로를 반환 받을 수 있게 된다!</p>
<img src="https://velog.velcdn.com/images/na_jeong/post/5f1bd1bb-814f-4d29-8963-1593b102240a/image.png" width=90% />

<h4 id="🧐어려웠던-formdata">🧐어려웠던 Formdata</h4>
<p>호스트 페이지는 페이지 전환 없이 폼 데이터를 제출해야 하기 때문에 fetch로 backend와 통신할 때 FormData 객체를 사용하여 폼 데이터를 제출 하도록 했다.</p>
<blockquote>
<p>FormData란 HTML단이 아닌 자바스크립트 단에서 폼 데이터를 다루는 객체이다.
이미지 같은 멀티미디어 파일을 페이지 전환 없이 폼 데이터를 비동기로 제출하고 싶을 때나, 자바스크립트로 좀더 <strong>타이트</strong>하게 폼 데이터를 관리하고 싶을 때 FormData를 사용한다고 한다.</p>
</blockquote>
<pre><code>//생성자
const newFormData = new FormData();</code></pre><p>먼저 생성자를 작성한 다음, newformData.append(name, value) 를 호출해 저장해준 다음 body에 newformData를 보내는 방식으로 구현 성공!</p>
<img src="https://velog.velcdn.com/images/na_jeong/post/dadf08ee-de6e-42e1-8d77-74bdab2c289a/image.png" width=70%/>

<p>지금 보면 별거 아닌것 같지만, 구현 당시에는 새벽까지 싸매고 있었던 formDataㅠㅠ
하면서 어렵지만 너무 재밌었던, 그래서 기억하고 싶은 formData였다!</p>
<h2 id="🛫회고">🛫회고</h2>
<p>처음에 에어비엔비 사이트를 모델링 하기로 하였을 때, 멘토님들께서 가장 어려운 사이트라고 하셔서 지레 겁부터 먹었었다. 호스트 페이지 난이도가 가장 높을거라고 하셨지만, 왠지 해보고 싶은 마음에, 팀원들과 페이지 분담할 때 제일 먼저 호스트 페이지 하고 싶다고 손들었었던 ...! 
다행히 다들 양보 해주셔서 할 수 있었다. url 이동 없이 페이지 이동하는 것부터 어려웠지만, 이미지 업로드와 카카오 맵 api 등을 다양하게 구현할 수 있어서 더 의미있고 재밌었던 프로젝트였다.</p>
<p>1차 프로젝트 막바지에 있었던 프론트와 백엔드의 충돌을 막고자 PM으로써도 백엔드와 계속해서 소통하려고 노력하였고, 다들 1차때 경험을 해봐서 그런지 ERD 검토부터 컨벤션 맞추기까지 처음부터 다같이 맞추어 나가서 더 수월하게 프로젝트를 할 수 있었다!</p>
<p>프로젝트가 총 2주의 기간이였는데, 나는 1주차 주말에 코로나에 걸리고 말았었다.
진짜 PM으로써 팀원들한테 너무 미안했던 ㅠㅠㅠ 그래서 격리하면서 위코드에 있었을 때보다 더욱 더 열심히 프로젝트에 임한 것 같다.
PM의 역할은 아침마다 스탠덥 미팅을 주관하는 것이였는데, 팀원분들께 양해를 구하고 온라인으로 하면서 일정 조율을 진짜 열심히 하려고 하긴했다..</p>
<p>시간에 쫓기지 않으려고, 일부터 타이트하게 일정을 짜서 팀원들에게 배분했는데 다들 군소리 없이 잘 따라와주셔서 마지막엔 다들 기본 기능구현을 다 완료해, 이제 할게 없다고 하시던 우리 팀원분들 ..😇 다들 너무 잘하시는거 아니냐고 ... </p>
<p>마지막으로, 정말 어려운게 있을 때마다 물어보면 밤늦게까지 열정적으로 알려주시던 ㅇㄱ멘토님.. 프로젝트 마지막날까지 backend와 통신도 같이 해주시며 도와주셔서 너무 감사했다 ㅠㅠ 진짜 당신은 천사...</p>
<p>프로젝트를 진행하면서 느낀게 정말 <strong>팀워크가 중요</strong>하다는 점
서로 blocker가 생기면, 자기가 하던 일도 멈추고 팀원의 blocker를 같이 해결해주려 했기 때문에 수월하게 모든 파트가 일정대로 진행될 수 있었던 것 같았다!</p>
<p>회고를 하면서 곱씹어볼수록 좋았던 점 밖에 없었던 2차 프로젝트 였던 것 같다.
진짜 아쉬운게 있다면 내가 코로나에 걸려서 같이 진행하지 못했다는 것 뿐...?</p>
<p>모두들 너무 고생 많았고, 하면서 너무 즐거웠던 Abnb프로젝트 안녕 ! 👋</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue]Vuex Store 사용법]]></title>
            <link>https://velog.io/@na_jeong/VueVuex-Store-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@na_jeong/VueVuex-Store-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Fri, 13 Jan 2023 06:22:36 GMT</pubDate>
            <description><![CDATA[<p>Vuex는 Vue.js <strong>애플리케이션을 위한 상태 관리 패턴 + 라이브러리</strong>이다.
상태가 예측 가능한 방식으로만 변경될 수 있도록 하는 규칙을 사용하여 응용 프로그램의 모든 구성 요소에 대한 집중식 저장소 역할을 한다.</p>
<p>만약 이게 없다면, 컴포넌트 간 데이터를 주고받기 위해 <strong>부모는 자식에서 props의 방식으로, 자식은 부모에게 Emit event의 방법</strong>으로 데이터를 주고 받아야 한다.</p>
<p>또 형제 컴포넌트 간 데이터를 주고 받으려면 너무 복잡해져서 <strong>EventBus를 활용</strong>해야 사용할 수 있게 된다.</p>
<p>이런 문제를 해결해주는 것이 <strong><span style='color:red'>Vuex</span></strong>이다!
<strong>데이터</strong>를 Store라는 파일을 통해 관리하고 프로젝트 전체에 걸쳐 활용할 수 있게 해주는 방법이다.</p>
<h3 id="💡상태-관리-패턴이란">💡상태 관리 패턴이란?</h3>
<p>많은 애플리케이션을 구축하는 데 있어 발견되는 전형적인 문제는 서로 다른 UI component에서 동일한 데이터를 보여줄 때, 이를 동기화 하는 것이 문제다.
종종, 상태의 변화는 다수의 컴포넌트에 반영될 필요가 있으며, 애플리케이션 규모가 커짐에 따라 복잡성이 증가한다.</p>
<p>단순한 앱이면 상관 없지만, 규모가 크고 복잡한 앱일수록 컴포넌트 간의 통신이나 데이터 전달이 좀 더 유기적으로 관리해야 한다.</p>
<p>앱의 규모가 커지면,</p>
<ul>
<li>props, emit이 거쳐야 할 컴포넌트가 많아진다.</li>
<li>EventBus를 사용한다고 하더라도 이벤트를 어디서 보내고 받았는지 데이터 흐름을 파악하기에 어렵다.</li>
</ul>
<p><strong>이러한 문제점을 해결하기 위해 모든 데이터 통신을 한 곳에서 중앙 집중식으로 관리하는 것이 <span style='color:red'>상태 관리</span> 이다.</strong></p>
<h2 id="🔥vuex의-구조">🔥VUEX의 구조</h2>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/065ada56-f449-4363-af46-d95bab8f8053/image.png" alt=""></p>
<p>vuex는 state, mutations, actions, getter 4가지 형태로 관리가 된다.</p>
<h4 id="🎈state">🎈State</h4>
<ul>
<li>state는 쉽게 말하면 프로젝트에서 공통으로 사용할 변수를 정의한다.</li>
<li>프로젝트 내의 모든 곳에서 참조 및 사용이 가능하다.</li>
<li>state를 통해 각 컴포넌트에서 동일한 값 사용 가능하다.</li>
<li>state는 mutations를 통해서만 변경이 가능하다.<pre><code>export const state = () =&gt; ({
list: [],
});</code></pre></li>
</ul>
<h4 id="🎈mutations">🎈Mutations</h4>
<ul>
<li>Mutations의 주요 목적은 <strong>state를 변경시키는 것</strong>이다.</li>
<li>비동기 처리가 아닌 <strong>동기 처리</strong>를 한다.
위의 함수가 실행되고 종료된 후 그 다음 아래의 함수가 실행된다.</li>
<li>commit(&#39;함수명&#39;, &#39;전달인자&#39;)으로 실행 시킨다.</li>
<li>mutations 내에 함수 형태로 작성한다.<pre><code>export const mutations = {
add(state, payload) {
  state.list.push({
    id: payload.id,
    user_name: payload.name,
  });
}
}</code></pre></li>
</ul>
<h4 id="🎈actions">🎈Actions</h4>
<ul>
<li>Actions의 주요 목적은 *<em>mutations를 실행시키는 것 *</em>이다.</li>
<li>동기 처리가 아닌 <strong>비동기 처리</strong>를 한다. 순서에 상관없이 먼저 종료된 함수의 피드백을 받아 후속 처리 하게 된다.</li>
<li>dispatch(&#39;함수명&#39;,&#39;전달인자&#39;)로 실행시킬 수 있다.
ex) dispatch(&#39;함수명&#39;, &#39;전달인자&#39;, {root:true})</li>
<li>actions 내에 <strong>함수 형태</strong>로 작성한다.</li>
<li>비동기 처리이기 때문에 콜백 함수로 주로 작성한다.<pre><code>export const actions = {
setAdd({ commit, dispatch }, payload) {
  commit(&#39;currentUser&#39;, payload);
  dispatch(&#39;setUserId&#39;, payload.id);
}
}</code></pre></li>
</ul>
<h4 id="🎈getters">🎈Getters</h4>
<ul>
<li>각 components의 계산된 속성의 공통 사용 정의</li>
<li>여러 components에서 동일한 computed가 사용 될 경우 Getters에 정의하여 공통으로 쉽게 사용할 수 있다.</li>
<li>하위 모듈의 getters를 불러오기 위해서는,</li>
<li><em>this.$store.getters[&quot;경로명/함수명&quot;];*</em>을 사용해야 한다.</li>
</ul>
<pre><code>export const getters = {
  isAuthenticated(state) { 
    return !!state.user;
  },

  getAccount(state) {
    return state.account;
  },
};</code></pre><h2 id="🔥mutations와-actions의-사용가능-인자">🔥Mutations와 Actions의 사용가능 인자</h2>
<p>Mutations와 Actions 내에 있는 함수에서 인자의 사용은 약간의 규칙이 있다.</p>
<h4 id="mutations-내-함수-인자">Mutations 내 함수 인자</h4>
<p>Mutations내에 있는 함수의 인자는 state와 payload이다.
기본 인자는 state만 사용할 수 있고, commit으로 넘어온 전달 인자는 payload만 있다.
payload는 여러개를 묶은 객체 형태로 전달될 수 있다.</p>
<p>또한 바로 중괄호로 묶어서 개체 형태로도 전달 받을 수 있다.
<strong>mutationA(state, payload){ }</strong>
<strong>mutationA(state,{data1, data2}){ }</strong></p>
<h4 id="actions-내-함수-인자">Actions 내 함수 인자</h4>
<p>Actions는 비동기 처리를 한다. 일단 실행 시키고 회신을 기다렸다가 먼저 회신 온 것부터 처리한다.
actions에서는 {rootState, state, dispatch, commit}의 기본 인자를 받을 수 있다.
기본 인자는 중괄호로 묶어서 전달 받는다.
또한 payload는 mutations와 마찬가지로 객체 형태로 받을 수 있다.
actionsA({rootState, state, dispatch, commit}, payload){ }</p>
<h2 id="🔥components에서-각-store-모듈에-접근하는-방법">🔥Components에서 각 store 모듈에 접근하는 방법</h2>
<p>Components에서 store에 있는 state, mutations, actions, getters에 접근하는 방법은 아래와 같다.</p>
<h4 id="state에-접근하는-방법">state에 접근하는 방법</h4>
<p>state에 접근하기 위해서는 component의 <strong>computed</strong> 내에 작성을 해야한다.</p>
<ol>
<li>접근 방법 : this.$store.state.items</li>
<li>mapState 접근 방법<pre><code>computed: {
 ...mapState({
     items: state =&gt; state.items,
 }),
}</code></pre></li>
</ol>
<h4 id="mutations에-접근하는-방법">mutations에 접근하는 방법</h4>
<p>mutations를 실행하기 위해서는 component의 <strong>methods</strong> 영역에서 작성을 해야한다.</p>
<ol>
<li>접근 방법 : this.$store.commit(&#39;경로명/함수명&#39;)</li>
<li>mapMutations 접근 방법<pre><code>methods: { //methos 영역에서 호출해야 함
 ...mapMutations({
     add: &#39;item/increment&#39; //this.add()를this.$store.commit(&#39;item/incremetn&#39;)에 매핑한다.
 }),
}</code></pre></li>
</ol>
<h4 id="actions에-접근하는-방법">actions에 접근하는 방법</h4>
<p>Actions를 실행하기 위해서는 component의 <strong>methods</strong> 영역에서 작성을 해야한다.</p>
<ol>
<li>접근 방법 : this.$store.dispatch(&#39;경로명/함수명&#39;)</li>
<li>mapActions 접근 방법<pre><code>methods: { //methos 영역에서 호출해야 함
 ...mapActions({
     add: &#39;item/increment&#39; //this.add()를this.$store.dispatch(&#39;item/incremetn&#39;)에 매핑한다.
 }),
}</code></pre></li>
</ol>
<h4 id="getters에-접근하는-방법">Getters에 접근하는 방법</h4>
<p>Getters를 실행하기 위해서는 component의 <strong>computed</strong> 영역에서 작성을 해야한다.</p>
<ol>
<li>접근 방법 : this.$store.getters[&quot;경로명/함수명&quot;];</li>
<li>mapGetters 접근 방법<pre><code>methods: { 
 ...mapActions({
     doneCount : &#39;item/doneTodosCount&#39;
 })
}</code></pre></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nuxt.js]]></title>
            <link>https://velog.io/@na_jeong/Nuxt.js</link>
            <guid>https://velog.io/@na_jeong/Nuxt.js</guid>
            <pubDate>Thu, 12 Jan 2023 08:09:22 GMT</pubDate>
            <description><![CDATA[<h2 id="🧐nuxtjs-뭔데">🧐Nuxt.js 뭔데?</h2>
<p><strong>Nuxt.js</strong>는 Vue.js를 기반으로 하여 SSR 기반의 Web Application을 컴포넌트 단위로 개발 할 수 있게 해주는 프레임워크이다.
웹 애플리케이션을 제작할 때 필요한 <strong><span style='color:lightgreen'>vuex, router,axios</span></strong>와 같은 라이브러리들을 미리 구성하여 싱글 페이지 애플리케이션, 서버 사이드 렌더링, 정적 웹 사이트를 쉽게 제작할 수 있다.</p>
<blockquote>
<p>Nuxt.js에 대해 알아보기 전에, CSR과 SSR에 대해 알아보는것 먼저해야한다!
이 두가지 개념이 Nuxt.js의 가장 큰 특징이라고 할 수 있다.</p>
</blockquote>
<h3 id="✳️-csrssr">✳️ CSR&nbsp;&nbsp;|&nbsp;&nbsp;SSR</h3>
<h4 id="📌csr-client-side-rendering">📌CSR (Client Side Rendering)</h4>
<p>SPA(Single Page Application)에서 사용되는 방식이다.
SPA란, 최초 한번 페이지를 전체 로딩한 후 데이터만 변경해서 사용할 수 있는 웹 어플리케이션을 말한다.</p>
<p>최초 페이지를 로딩한 시점부터는 리로딩없이 필요한 부분만 받아서 렌더링 하는 방식이다.</p>
<pre><code>👍 장점
1. 화면 이동이 자연스러움
2. 필요한 부분만 부분적으로 로딩가능 -&gt; 트래픽이 감소함
3. 컴포넌트 별 개발이 용이함

👎 단점
1. SEO(검색 엔진 최적화)어려움
2. 보안 이슈
3. 자바스크립트 파일을 번들링해서 받기 때문에 속도가 느림.</code></pre><h4 id="📌ssrserver-side-rendering">📌SSR(Server Side Rendering)</h4>
<p>MPA(Multiple Page Application)에서 사용되는 방식이다.
서버에서 사용자에게 보여줄 페이지를 모두 렌더링 하여 띄우는 방식.
request를 할 때마다 새로고침이 일어난다.
SSR은 SEO에 매우 강력하고, 초기 로드 시간도 SPA보다 훨씬 유리한 측면을 가지고 있다.</p>
<pre><code>👍 장점
1. SEO(검색엔진 최적화)
2. CSR에 비해 초기 로드 속도가 빠름

👎 단점
1. 페이지 이동 시 화면이 깜빡임 및 중복된 렌더링 비용 발생
2. 서버 렌더링에 따른 부하 발생
3. 컴포넌트 단위의 개발이 어려움
4. SPA에 비해 초기 로드 속도는 빠르지만, 매 페이지 마다 템플릿에 대한 새로운 로드가 필요하다.</code></pre><h4 id="📌ssr을-왜-쓸까">📌SSR을 왜 쓸까?</h4>
<p>서버 사이드 랜더링을 쓰는 목적은 크게 <strong>검색 엔진 최적화</strong>와 <strong>빠른 페이지 렌더링</strong>이다.
SEO란 검색 사이트에서 검색했을 때 결과가 사용자에게 많이 노출될 수 있도록 최적화 하는 기법이다.
특히, SNS에서 링크를 공유했을 때 해당 웹 사이트의 정보를 이미지와 설명으로 표시해주는 OG(Open Graph)Tag를 페이지 별로 적용하기 위해서는 서버 사이드 렌더링이 효율적이다.
또한, SSR은 빈 HTML 페이지를 받아 브라우저에서 그리는 클라이언트 사이드 렌더링과 다르게 서버에서 미리 그려서 브라우저로 보내주기 때문에 페이지를 그리는 시간을 단축할 수 있다. 
사용자 입장에서는 화면에 유의미한 정보가 표시되는 시간이 빨라지는 것이다 !</p>
<h2 id="🧐nuxtjs의-장점">🧐Nuxt.js의 장점</h2>
<ul>
<li>검색 엔진 최적화</li>
<li>초기 프로젝트 설정 비용 감소와 생산성 향상
• ESLint, Prettier
• 라우터, 스토어 등의 라이브러리 설치 및 설정 파일 필요 X
• 파일 기반의 라우팅 방식, 설정 파일 자동 생성</li>
<li>페이지 로딩 속도와 사용자 경험 향상
• 브라우저가 하는 일에 서버를 나눠준다.
• 모르면 지나칠 수 있는 코드 스플리팅이 기본으로 설정</li>
</ul>
<h2 id="🧐nuxtjs의-특징">🧐Nuxt.js의 특징</h2>
<ul>
<li>서버 사이드 렌더링</li>
<li>코드 분할 자동화</li>
<li>비동기 데이터 기반의 강력한 라우팅 시스템</li>
<li>정적 파일 전송</li>
<li>코드 스플리팅</li>
<li>ES6/ES6+ 변환</li>
<li>웹팩을 비롯한 기타 설정</li>
</ul>
<h2 id="🧐nuxtjs-언제-사용하지-">🧐Nuxt.js 언제 사용하지 ?</h2>
<p>딱 ! 결정적으로, <span style='backgroundColor: #FFA07A'>SEO 개선</span>을 할 때 사용한다.</p>
<h2 id="🧐nuxtjs-life-cycle">🧐Nuxt.js Life Cycle</h2>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/17de989d-990f-4886-b924-1b61eed0cdd0/image.png" alt=""></p>
<blockquote>
<p>2023.01.12 어렵다 어렵다 어렵다 !!!!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Vue] 뷰 인스턴스]]></title>
            <link>https://velog.io/@na_jeong/Vue-%EB%B7%B0-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</link>
            <guid>https://velog.io/@na_jeong/Vue-%EB%B7%B0-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</guid>
            <pubDate>Thu, 12 Jan 2023 06:30:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>갑자기 Vue는 왜하세요 ?
✅ 위코드를 통해 기업협업 나온 회사에서 Vue.js 와 Nuxt.js를 사용하므로 당분간 열심히 공부를 할 예정 ...!! 화이팅 화이팅 화이팅</p>
</blockquote>
<h2 id="💡vue란-">💡Vue란 ?</h2>
<p>먼저 vue란 사용자 인터페이스를 만들기 위한 <em>프로그레시브 프레임워크</em>이다.
다른 단일형 프레임워크와 달리 vue는 점진적으로 채택할 수 있도록 설계하였다.
핵심 라이브러리는 뷰 레이어만 초점을 맞추어 다른 라이브러리나 기존 프로젝트와의 통합이 매우 쉽다. 그리고 Vue는 <span style='color: orange'>현대적 도구</span>및 <span style='color: orange'>지원하는 라이브러리</span>와 함께 사용한다면 정교한 단일 페이지 응용프로그램을 완벽하게 지원할 수 있다.</p>
<h2 id="💡뷰-인스턴스">💡뷰 인스턴스</h2>
<p>인스턴스는 뷰로 화면을 개발할 때 필수로 생성해야 하는 코드이다.</p>
<h3 id="👩💻인스턴스-생성">👩‍💻인스턴스 생성</h3>
<p>인스턴스는 아래와 같이 생성한다.</p>
<pre><code>new Vue();</code></pre><p>인스턴스를 생성하고 나면 아래와 같이 인스턴스 안에 어떤 속성과 API가 있는지 콘솔 창에서 확인 가능하다.</p>
<pre><code>const vm = new Vue();
console.log(vm);</code></pre><p>크롬 개발자 도구에서 console 패널을 확인하면 아래처럼 결과가 나온다.
<img src="https://velog.velcdn.com/images/na_jeong/post/4cca5185-dddc-4757-a240-ad7100deba74/image.png" alt=""></p>
<p>이처럼 인스턴스 안에는 미리 정의되어 있는 속성들과 메서드들이 있다.</p>
<h3 id="👩💻인스턴스의-속성-api들">👩‍💻인스턴스의 속성, API들</h3>
<p>인스턴스에서 사용할 수 있는 속성과 API는 아래와 같다.</p>
<pre><code>new Vue({
    el: ,
    template: ,
    data: ,
    methods: ,
    created: ,
    watch: ,
});</code></pre><ul>
<li>el : 인스턴스가 그려지는 화면의 시작점 (특정 HTML 태그)</li>
<li>template : 화면에 표시할 요소 (HTML, CSS 등)</li>
<li>data : 뷰의 반응성(Reactivity)이 반영된 데이터 속성</li>
<li>methods : 화면의 동작과 이벤트 로직을 제어하는 메서드</li>
<li>created : 뷰의 라이프 사이클과 관련된 속성</li>
<li>watch : data에서 정의한 속성이 변화했을 때 추가 동작을 수행할 수 있게 정의하는 속성</li>
</ul>
<h3 id="👩💻뷰-인스턴스의-유효범위">👩‍💻뷰 인스턴스의 유효범위</h3>
<p><strong>인스턴스의 유효범위란 ??</strong>
뷰 인스턴스를 생성하면 HTML의 특정 범위 안에서만 옵션 속성들이 적용되어 나타나는데, 이를 인스턴스의 유효 범위라고 한다.
인스턴스의 유효 범위는 <span style='color:red'>el</span>속성과 밀접한 관계 가 있음</p>
<pre><code>&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;
        &lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;
        &lt;script&gt;
            //vue instance
            const vm = new Vue({
                //body태그 안에서 app이라는 이름을 가진 태그를 찾아서 인스턴스를 붙히겠다라는 의미.
                //왜하나? 붙이는 순간부터 vue의 기능과 속성을 사용할 수 있다.
                //element가 없으면 data를 사용할 수 없다.
                el: &#39;#app&#39;,
                data: {
                    message: &#39;hi&#39;,
                },
            });
        &lt;/script&gt;</code></pre><p>위에 코드의 뷰 인스턴스에서 <span style='color:red'>el</span>속성의 값인 &#39;#app&#39;은, app이라는 아이디 값을 가진 div 태그를 가리키며, 이 태그가 인스턴스의 유효 범위이다.</p>
<p>그래서 위의 코드를 실행시켜보면 vue 콘솔 화면에 hi가 출력되는 것이 보임 !
<img src="https://velog.velcdn.com/images/na_jeong/post/2e389120-5fdb-4894-9e0c-a91281792080/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS]즉시 실행 함수]]></title>
            <link>https://velog.io/@na_jeong/JS%EC%A6%89%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@na_jeong/JS%EC%A6%89%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%95%A8%EC%88%98</guid>
            <pubDate>Thu, 12 Jan 2023 01:30:03 GMT</pubDate>
            <description><![CDATA[<h2 id="🧐즉시실행함수">🧐즉시실행함수</h2>
<p>즉시실행함수(Immediately Invoked Function Expression)은 <strong>정의되자마자 즉시 실행되는 함수</strong>이다.</p>
<pre><code>(function () {
    statements
})();

//화살표 함수일 경우
(() =&gt; {
    statements
})();</code></pre><p>즉시실행함수는 다음과 같이 소괄호로 함수를 감싸서 실행하는 문법이다.</p>
<blockquote>
<p>즉시실행함수에 이름을 붙일 순 없을까 ?
: 즉시실행함수에도 이름을 붙여 사용할 수 있지만, 선언과 동시에 호출되어 반환되면 재사용을 할 수 없기 때문에 이름ㅇ르 지어주는 것이 의미가 없다.</p>
</blockquote>
<h3 id="💡즉시실행함수-사용-이유">💡즉시실행함수 사용 이유</h3>
<h4 id="1-전역변수-사용을-억제할-수-있다">1. 전역변수 사용을 억제할 수 있다.</h4>
<blockquote>
<p><strong>전역변수를 사용하면</strong></p>
</blockquote>
<ul>
<li>모든 코드에서 전역변수를 참조하고, 변경하기 때문에 상태 변경의 위험성이 높다.</li>
<li>생명주기가 어플리케이션의 생명주기와 동일하므로 메모리 리소스 소비기간이 길고, 상태 변경에 의한 오류발생 확률이 높다.</li>
<li>스코프 체인 상에서 종점에 존재하기 때문에 가장 마지막에 검색된다. <strong>즉, 검색 속도가 가장 느리다.</strong></li>
<li>다른 파일 내에서 동일한 이름으로 전역 변수나 전역 함수를 재할당 할 경우 예상치 못한 결과를 가져올 수 있다.</li>
</ul>
<p>전역변수는 이런 문제점이 있으므로 사용을 하지 않는것이 좋다.</p>
<h4 id="2-private한-변수를-만들-수-있다">2. private한 변수를 만들 수 있다.</h4>
<p><span style='color:orange'>즉시실행함수</span>는 외부에서 접근할 수 없는 자체적인 스코프를 가지게 된다. 이는 클로저의 사용 목적과도 비슷하며 내부 변수를 외부로부터 private하게 보호할 수 있다는 장점이 있다.</p>
<h3 id="💡예제">💡예제</h3>
<p>아래 함수는 즉시실행되는 함수 표현이다. 표현 내부의 변수는 외부로부터의 접근이 불가능하다.</p>
<pre><code>(function){
    const aName = &quot;Barry&quot;;
})();
//IIFE 내부에서 정의된 변수는 외부 범위에서 접근이 불가능하다.
aName //throws &quot;Uncaught ReferenceError : aName is not defined&quot;</code></pre><p>IIFE를 변수에 할당하면 IIFE 자체는 저장되지 않고, 함수가 실행된 결과만 저장한다.</p>
<pre><code>const result = (function() {
    const name = &quot;Barry&quot;;
    return name;
})();
//즉시 결과를 생성한다.
result; //&quot;Barry&quot;</code></pre><p>참조 : <a href="https://developer.mozilla.org/ko/docs/Glossary/IIFE">https://developer.mozilla.org/ko/docs/Glossary/IIFE</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1차 프로젝트 회고]]></title>
            <link>https://velog.io/@na_jeong/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@na_jeong/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 02 Jan 2023 12:48:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>위코드에서 진행한 1차 프로젝트가 끝이났다.
길다면 길고, 짧다면 짧은 2주였지만, 나름 만족스럽게 끝이났다고 생각하며 회고시간을 가져보고자 한다!</p>
</blockquote>
<h2 id="프로젝트-소개">프로젝트 소개</h2>
<p>이번에 우리가 진행한 프로젝트는 코스메틱 브랜드(Aesop)를 모델링 한 Cesop 웹 사이트이다.
<img src="https://velog.velcdn.com/images/na_jeong/post/8c31b49c-ae93-48f4-bc4c-aac6ce03747b/image.png" alt=""></p>
<p>프로젝트를 시작하기에 앞서 PET 분석을 통해 사이트에 대해 자세히 분석을 하게 되었다.
우리가 생각하기에, 이솝의 키워드는 <span style='color:red'>&#39;조화&#39;</span>였다.
실제로 이솝은 패키징보다는 피부와 제품의 조화를 우선시하고, 필요 없는 것은 모두 뺀 디자인으로 어느 장소에서든 이솝의 제품이 어울릴 수 있게끔 특성을 지니고 있다.
어떻게 보면, 이솝 매장 자체가 브랜드 비주얼 마케팅이라고 할 수 있는 것이다.
이에 우리 Cesop도 조화를 생각하며 프로젝트를 진행하기로 했다. </p>
<h3 id="기술-스택">기술 스택</h3>
<ul>
<li><strong><span style='color:red'>FrontEnd</span></strong> : React, Javascript, SCSS</li>
<li><strong><span style='color:red'>BackEnd</span></strong> : Node.js, MySQL, Express</li>
<li>*<span style='color:red'>common</span>** : <a href="https://trello.com/b/qMujrAg2/cesop">Trello</a>, slack</li>
</ul>
<p>이번 Cesop에서 Product Manager, Project Manager를 뽑아야 했었는데, 내가 Project Manager를 자진해서 해보기로 하였다.
팀 프로젝트의 진행상황 등을 관리하는 역할로써 코드를 짜면서 함께 하기 힘들것 같다는 생각은 있었으나, 한번쯤은 협업하는 과정에 있어서 이 역할을 해보고 싶었기 때문이다.
프로젝트 매니저로써 팀과 소통할 수 있는 slack 채널과 , Trello 관리를 하게 되는데, 특히나 이 Trello가 프로젝트 관리의 핵심이라고 할 수 있다.
처음 사용해보는 툴이라 처음엔 티켓들만 나열해놓기 바빴는데, 멘토님들의 도움으로 Label사용, Membe분배 등 티켓을 여러방면으로 활용해 볼 수도 있었다.</p>
<h3 id="구현-사항">구현 사항</h3>
<ol>
<li>메인페이지 ✅</li>
<li>Navbar + 상단 Banner + Footer ✅</li>
<li>카테고리 모달창 ✅</li>
<li>로그인 페이지</li>
<li>회원가입 페이지</li>
<li>제품 리스트 페이지</li>
<li>제품 상세 페이지</li>
<li>장바구니</li>
<li>결제 페이지</li>
</ol>
<p>나는 이 9가지의 필수 구현 사항 기능 중, ✅표시가 된 페이지를 구현하였다.
크게 나누어보면, 
메인 페이지 : 하단에 있는 이미지 캐러셀을 무한 슬라이드로 구현
           section을 컴포넌트화 시켜 Map을 사용해 반복되는 section 처리
Navbar : Nav bar의 메뉴 클릭 시 새로운 카테고리 Modal 창을 띄워주기
         각각 메뉴 tab 클릭 시, 카테고리 별 메뉴 띄우기
Modal : 카테고리 이름을 누르면 해당 상품 리스트 페이지로 이동
Banner &amp; Footer : 모든 페이지에 붙어있도록 함</p>
<p>추가적으로, 장바구니 페이지를 맡은 팀원에 팔로우하여 상단에 Modal창으로 띄우는 작업까지 마무리 하였다.</p>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/f05c549d-92dc-4f1b-9be5-ebf1434f1327/image.png" alt="">
<img src="https://velog.velcdn.com/images/na_jeong/post/1b90e7a7-38c8-494a-9071-7dcbc8a7d78f/image.png" alt="">
<img src="https://velog.velcdn.com/images/na_jeong/post/78c986b9-ea11-4149-8814-b3fd3f795cc0/image.png" alt=""></p>
<h3 id="가장-어려웠던-가장-기억하고-싶은-무한-캐러셀-구현">가장 어려웠던, 가장 기억하고 싶은 무한 캐러셀 구현</h3>
<img src='https://velog.velcdn.com/images/na_jeong/post/f94c8080-c42b-4f41-8347-be02b0a2fce6/image.png' width= '400px'  />
진짜 안뒤져본 블로그가 없었다.
그 정도로 공부하는데 가장 오래걸렸고, 그러기에 구현에 성공한 후 가장 뿌듯했던 무한 캐러셀이다.
무한 슬라이드를 구현하려면, 약간의 눈속임이 필요했다.
캐러셀 image 배열의 맨 앞 사진과, 맨 뒷 사진을 복사하여 마지막 장에서 맨앞으로 넘어갈 때, 복사해 두었던 앞의 사진을 눈속임용(?)으로 보여주면서 실제 첫번째 사진을 띄워주도록 한다.
말로 풀어 설명해도 어렵다 !
<img src='https://velog.velcdn.com/images/na_jeong/post/629bf0fb-dc74-4ec0-86cc-aa29d9359b65/image.png' width= '400px' />
버튼을 클릭했을 때, Transition을 사용해서 사진을 넘겨주다가, 맨 마지막 사진이면 moveToNthSlide() 함수로 이동한다.

<p>그럼 moveToNthSlide() 함수에서 setTimeout을 사용해 첫번째 사진으로 돌아가게끔 작성해주면 된다 !</p>
<h3 id="회고">회고</h3>
<p>나는 FrontEnd 담당이기 때문에, Front 팀원들의 일정이나 어려운 상황 등은 한번에 바로 파악이 가능하고, 일정 조율이 보다 쉽고 빠르게 이루어질 수 있었다. </p>
<p>모두가 일정한 속도로 코드를 짤 수 있도록, 티켓 조율과 함께 수시로 소통을 하면서 서로의 Blocker에 대해서 토론도 하면서 그렇게 잘 진행을 했다고 생각했다.</p>
<p>하지만, BackEnd는 내가 맡은 파트가 아니란 이유로, BackEnd의 상황은 깊숙히 몰라도 된다는 안일한 생각을 하게 되었고, 팀원들이 말해주는 기간만 고려해 일정 조율을 하다보니 Demo Day 하루를 앞두고, BackEnd API가 완성이 되지 않아 기다리게 되는 상황이 생겨버렸다.</p>
<p>그러다 일어났으면 안되는 일이 일어나게 되었다.
다른 팀원이 맡은 페이지의 key, value 값과 BackEnd에서 보내는 값이 달라 다시 처음부터 맞춰야하는 상태가 되어버린 것이다. 
하지만, 팀원 모두가 밤을 새다시피 하여 어느정도 상황 수습을 하고, 프로젝트를 마무리 지을 수 있었다.</p>
<h3 id="pm으로써의-역할을-잘-하였는가-">PM으로써의 역할을 잘 하였는가 ?</h3>
<p>Project Manager로써 Front와 Back 두 파트 모두의 상황을 신경쓰고 서로간의 소통 컨벤션을 처음부터 제대로 잡아놨어야 했는데, 내가 맡은 파트에만 집중을 하다보니 하나하나 신경을 쓰지 못한것 같았다. 백엔드와의 소통도 중요한 것인데 그 중요한 것을 잊어버린 것이다.
이번 프로젝트를 통해 BackEnd와 FrontEnd간의 사소한 소통 오류 하나가 큰 실수를 범한다는 것을 깨달았고, Project Manager의 역할에 대해 다시 한번 곱씹어보는 기회가 되었다.</p>
<p>그래도 좋은 팀원들을 만났기에, 힘들지만 재밌게 프로젝트를 마무리 할 수 있었던 것 같다.
모두가 짜기라도 한듯 Blocker를 만났을 때, 합심해서 서로 도와주고, 안되는 부분에 있어 남탓 하지 않고 서로 북돋아주고 서로가 서로의 멘탈을 케어해주며 그렇게 2주동안 시간을 보냈다.</p>
<p>처음 프로젝트 시작할때는 Project Manager로써 그들을 이끌어야 한다고 생각했는데 지금 곱씹어보면, 팀원들이 부족하지만 PM의 말을 잘 들어주고, 하자고 하는대로 팔로우 해주었고, 역으로 나를 이끌어주며 진행이 되었던 것 같다.</p>
<p>우리 팀 중 누가 읽을까 싶지만, Cesop팀 정말 수고 많았고 다들 감사하다는 말을 전하고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React]동적라우팅]]></title>
            <link>https://velog.io/@na_jeong/React%EB%8F%99%EC%A0%81%EB%9D%BC%EC%9A%B0%ED%8C%85</link>
            <guid>https://velog.io/@na_jeong/React%EB%8F%99%EC%A0%81%EB%9D%BC%EC%9A%B0%ED%8C%85</guid>
            <pubDate>Tue, 20 Dec 2022 00:35:45 GMT</pubDate>
            <description><![CDATA[<h2 id="📓동적라우팅">📓동적라우팅</h2>
<p>라우팅을 설정하는 가장 기본적인 방법은 정적(static, pre-defined)라우팅이다. 
즉, Router 컴포넌트에서 미리 프로젝트에서 사용할 수 있는 경로들과 해당 경로로 접속했을 때 보여줄 컴포넌트를 모두 정의해두는 방식이다.
하지만, 복잡하고 규모가 큰 애플리케이션에서는 경로를 미리 설정하는 방식으로는 처리가 힘들다.</p>
<p>정적 라우팅의 예시는 아래와 같다.</p>
<pre><code>import React from &#39;react&#39;;
import { BrowserRouter, Route, Routes } from &#39;react-router-dom&#39;;

const Router = () =&gt; {
  return (
    &lt;BrowserRouter&gt;
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={&lt;ListComponent /&gt;} /&gt;
        &lt;Route path=&quot;/post/1&quot; element={&lt;First /&gt;} /&gt;
        &lt;Route path=&quot;/post/2&quot; element={&lt;Second /&gt;} /&gt;
      &lt;/Routes&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default Router;</code></pre><p>이러한 route가 한두개 일 때는 무리가 없지만, 100개 이상으로 쌓이게 된다면 /post/1 ~ 100의 Route를 모두 설정해야 한다. 중간에 삭제한다면 다시 해당 Route를 삭제해야 한다. 
이러한 정적 라우팅은 <strong><span style='color:red'>Route를 유연하게 정의할 수 없다</span></strong>는 단점을 가지고 있다.</p>
<p>이 문제를 해결하기 위해서 나온 개념이 <strong>동적 라우팅</strong>이다.
동적 라우팅은 Route를 설정할 때, 특정 규칙을 정의한 후 규칙에 부합하는 URL의 경우에는 해당 element를 보여주게 설정하는 방식이다.</p>
<p>동적 라우팅을 사용하면 규칙을 만족하는 모든 URL에 대해서 상세페이지로 연결시킬 수 있기 때문에 애플리케이션을 확장성있게 만들 수 있다.</p>
<h2 id="📓동적-라우팅-구현">📓동적 라우팅 구현</h2>
<p>동적 라우팅은 react-router-dom 라이브러리를 이용해서 구현할 수 있다.
구현 방법은 Route 컴포넌트의 path prop에 <strong><span style='color:red'>:</span></strong> 기호를 활용하는 것이다.
<span style='color:red'>경로/:문자열</span>형태로 path를 설정하면 URL에서 <span style='color:red'>경로/</span>뒤에 무슨 글자가 오든 이 Route로 연결된다.</p>
<pre><code>import React from &#39;react&#39;;
import { BrowserRouter, Route, Routes } from &#39;react-router-dom&#39;;

export default function Router() {
  return (
    &lt;BrowserRouter&gt;
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={&lt;ListComponent /&gt;} /&gt;
        &lt;Route path=&quot;/post/:id&quot; element={&lt;DetailComponent /&gt;} /&gt;
      &lt;/Routes&gt;
    &lt;/BrowserRouter&gt;
  );
}</code></pre><p>위와 같이 Route를 설정하면 경로를 따로 지정해주지 않아도 DetailComponent로 연결이 된다.
위의 코드에서 : 기호 뒤에 붙은 <strong>id</strong>와 같은 문자열이 <strong>path parameter</strong>이다.</p>
<h2 id="📓동적-라우팅과-path-parameter">📓동적 라우팅과 Path Parameter</h2>
<p>path parameter는 URL에 있는 값을 마치 매개변수처럼 사용하는 것이다. 똑같은 함수에 다른 매개변수를 통해서 다양한 결과를 낼 수 있는 것처럼 path parameter를 통해서 큰 틀은 동일하되 다른 UI를 보여주도록 처리할 수 있따.</p>
<p>동적 라우팅을 설정하려면 Route의 path prop에 <span style='color:red'>경로/:문자열</span>을 넣어줘야 한다. 이때 문자열 자리에 작성되는 것이 path parameter의 이름이다.이름은 자유롭게 작성 가능하다.
이렇게 컴포넌트 안에서 path parameter로 전달된 값을 이용해 특정한 처리를 하는 코드를 작성하면 동일한 컴포넌트에서 다양한 UI를 보여주는 것이 가능하다.</p>
<h2 id="📓path-parameter-활용">📓Path Parameter 활용</h2>
<h3 id="📙useparams-hook">📙useParams hook</h3>
<p>react-router-dom에서는 useParams hook을 제공한다. useParams hook은 path parameter의 값을 편하게 가져올 수 있게 해주며 마치 state처럼 path parameter의 값이 바뀌면 컴포넌트를 리렌더링 해주는 기능을 제공해준다.</p>
<p>useParams를 호출하면 path params의 값을 <strong>객체 형태</strong>로 반환해준다. 이때 객체의 프로퍼티의 key는 Route에서 설정한 path parameter의 이름이며 value는 path parameter에 실제로 전달된 값이다.
위에서 사용했던 코드에서는 path parameter의 이름을 <span style='color:red'>id</span>로 지정했기 때문에 <span style='color:red'>post/1</span>로 접속했다면 useParams hook의 return 값은 <span style='color:red'>{id:1}</span>이 되는 것이다.</p>
<pre><code>// useParams 활용 예시

import { useParams } from &#39;react-router-dom&#39;;

const params = useParams();
// { [path-parameter-name]: value }
</code></pre><p>useParams로 가져온 path params 값을 활용하면 하나의 컴포넌트에서 다양한 UI를 보여줄 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS]]></title>
            <link>https://velog.io/@na_jeong/AWS</link>
            <guid>https://velog.io/@na_jeong/AWS</guid>
            <pubDate>Mon, 19 Dec 2022 05:27:34 GMT</pubDate>
            <description><![CDATA[<h3 id="📓aws란">📓AWS란?</h3>
<p>Amazon Web Service의 줄임말로 아마존에서 제공하는 클라우드 서비스이다.
클라우드 서비스란 다양한 컴퓨팅 자원을 온디맨드로 사용할 수 있는 서비스이기 때문에 AWS 사용자는 직접 물리적인 서버 장비를 구입하거나 임대하여 설치할 필요없이 원격으로 손쉽고 빠르게 서버를 구축할 수 있다.</p>
<h4 id="💡aws를-사용하는-이유">💡AWS를 사용하는 이유</h4>
<ul>
<li>AWS는 클라우드 마켓의 선구자이자 리더이다.</li>
<li>AWS는 클라우드 컴퓨팅의 특징과 장점을 그대로, 혹은 그 이상으로 제공한다.</li>
<li><blockquote>
<p>뛰어난 유연성, 확장성, 우수한 보안성, 안정성</p>
</blockquote>
</li>
</ul>
<p>AWS는 어떤 규모의 기업이든 그 기업에 필요한 유연하고 경제적이며, 확장 가능하고 사용하기 간편함에 더해 안정성까지 보장되는 차별점 때문에 전세계 수많은 기업들과 개발자들이 사용한다.</p>
<p><strong><span style='color:red'>AWS의 서비스 지역은 크게 Regions, Availability Zones, Edge Location으로 나눌 수 있다.</span></strong></p>
<h4 id="💡regions리전">💡Regions(리전)</h4>
<ul>
<li>AWS가 전 세계에서 데이터 센터를 클러스트링하는 기준이 되는 물리적 위치</li>
<li>사용자와 리전이 가까울수록 네트워크 지연을 최소화할 수 있다.</li>
<li>AWS에서 제공하는 다양한 서비스들은 대부분 리전을 기반으로 제공된다.</li>
</ul>
<h4 id="💡availability-zones가용-영역">💡Availability Zones(가용 영역)</h4>
<ul>
<li>리전안에 존재하는 데이터 센터의 논리적인 그룹을 의미</li>
<li>리전들보다 빠르게 통신할 수 있고, 서비스 결합도 높다.</li>
<li>동일한 리전 내에 있더라도 물리적으로는 격리되어 있으므로 자연재해 등의 피해를 최소화한다.</li>
<li>사용자는 여러 가용 영역에 걸쳐 서비스를 배치해 내결함성을 한층 더 강화한 서비스를 제공가능</li>
</ul>
<h4 id="💡edge-location">💡Edge Location</h4>
<ul>
<li>AWS의 CDN(Content Delivery Network)서비스인 CloudFront의 캐싱 콘텐츠가 위치하는 곳</li>
<li>사용자와 근처에 있을 수록 더욱 빠른 전달을 받을 수 있기 때문에 리전보다 훨씬 많다.</li>
</ul>
<h3 id="📓aws의-주요-서비스-8가지">📓AWS의 주요 서비스 8가지</h3>
<h4 id="💡ec2elastic-compute-cloud">💡EC2(Elastic Compute Cloud)</h4>
<ul>
<li>단순 클릭 몇번을 통해 쉽게 사양을 고르고, 이를 통해 즉시 구동 가능한 서버를 제공하는 서비스</li>
<li>운영 서버에 필요한 대부분의 Operating System을 지원하고, 사용 목적에 맞는 사양 제공</li>
</ul>
<h4 id="💡rdsrelational-database-service">💡RDS(Relational Database Service)</h4>
<ul>
<li>클라우드에서 간편하게 데이터베이스를 설치, 운영 및 확장할 수 있는 AWS의 대표적인 서비스</li>
<li>다양한 RDBMS 제공</li>
<li>백업과 같은 소프트웨어 유지 보수를 위한 관리 태스크를 제거하여 효율적인 운용이 가능하다.</li>
</ul>
<h4 id="💡s3simple-storage-service">💡S3(Simple Storage Service)</h4>
<ul>
<li>파일을 쉽게 저장할 수 있는 공간을 제공하는 서비스</li>
<li>파일마다 고유 주소를 부여하여 S3에 저장한 파일을 웹상에서 쉽게 읽을 수 있다.</li>
<li>주로 사이트상의 이미지들을 저장하고 사이트에서 읽어들여 렌더링 해주는데 사용한다.</li>
</ul>
<h4 id="💡vpcvirtual-private-cloud">💡VPC(Virtual Private Cloud)</h4>
<ul>
<li>클라우드 환경을 계정 별로 독립된 네트워크 환경을 구성할 수 있게 도와주는 서비스</li>
<li>사용자가 네트워크 환경 설정에 대한 완전한 통제권을 가질 수 있다.</li>
</ul>
<h4 id="💡cloudfront">💡CloudFront</h4>
<ul>
<li><p>AWS에서 제공하는 CDN(Content Delevery Network)서비스이다.</p>
<blockquote>
<p>CDN이란?
인터넷상에 콘텐츠를 캐싱하여 좀 더 빠르게 사용자에게 전달 할 수 있게 도와주는 역할을 한다.
마치 멀리 있는 은행에 직접 안가고, 가까운 ATM기를 통해 현금을 찾을 수 있는 것!</p>
</blockquote>
</li>
<li><p>Latency(자연시간)을 비교해서 가장 가까운 곳에 위치한 엣지 로케이션을 통해 사용자 요청을 처리한다.</p>
</li>
</ul>
<h4 id="💡route-53">💡Route 53</h4>
<p>AWS에서 제공하는 DNS(Domain Name Service)서비스</p>
<blockquote>
<p>DNS란?
사람이 읽을 수 ㅣㅇㅆ는 도메인 이름을 머신이 읽을 수 있는 IP주소로 변환해주는 역할</p>
</blockquote>
<ul>
<li>가용성과 확장성이 뛰어나고 AWS 인프라의 각종 네트워크를 제어할 수 있으며, 도메인 등록, DNS라우팅, 상태 확인과 같은 주요 기능들을 간편하게 사용할 수 있다.</li>
<li>AWS 내의 다른 서비스들과의 호환성도 뛰어남.</li>
</ul>
<h4 id="💡elbelastic-load-balancer">💡ELB(Elastic Load Balancer)</h4>
<p>로드 밸런서를 제공하는 서비스</p>
<blockquote>
<p>로드 밸런스란?
서버로 들어오는 높은 애플리케이션 트래픽을 여러 대상에 적절하게, 자동으로 분산시켜줌으로써 안정저인 서버 운영을 도와준다.</p>
</blockquote>
<ul>
<li>다양한 보안 옵션을 제공하고, 애플리케이션 서버의 사용률에 따라 자동으로 추가되거나 제거되는 고가용성 및 탄력성을 갖추고 있다.</li>
<li>모니터링 및 로깅의 기능도 있다.</li>
</ul>
<h4 id="💡iam">💡IAM</h4>
<ul>
<li>AWS의 리소스에 대해 개별적으로 접근제어를 하거나 권한을 가지도록 계정 또는 그룹을 생성 및 관리하는 서비스</li>
<li>AWS에서는 관리와 같은 일상적인 작업조차도 루트 계정으로 하지 않는 것을 권장한다. IAM 계정이 없다면 AWS 루트 계정 자체가 모든 서비스에 대한 권한이 있기에 보안상 매우 취약하기 때문이다.</li>
<li>IAM 계정을 생성해서 각각 필요한 권한만 갖도록 설정할 수 있고 각각 access key를 개별적으로 관리할 수 있기 때문에 보안성이 높아진다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cloud Computing Services -(2)]]></title>
            <link>https://velog.io/@na_jeong/Cloud-Computing-Services-2</link>
            <guid>https://velog.io/@na_jeong/Cloud-Computing-Services-2</guid>
            <pubDate>Sun, 18 Dec 2022 15:32:20 GMT</pubDate>
            <description><![CDATA[<p>(1)에 이어서 운영 서버를 구축하는 방법에 대해 알아보려고 한다.</p>
<h2 id="💻온프레미스on-premise">💻온프레미스(On-premise)</h2>
<h3 id="💾온프레미스란">💾온프레미스란?</h3>
<p>IT 서비스를 기업이 자체적으로 보유한 물리적인 서버에 직접 설치해 운영하는 방식.
이러한 방식은 클라우드 컴퓨팅 기술이 나오기 전까지 기업들이 사용하던 일반적인 인프라 구축 방식이기도 하다.</p>
<h3 id="💾온프레미스의-특징">💾온프레미스의 특징</h3>
<p>인프라를 물리적으로 직접 구축하여 운영하는 방식이므로 프로젝트에 필요한 시스템을 구축하기 위해서 기업이 직접 구성에 맞게 하드웨어를 구입해야 한다.
보통 프로젝트에 필요한 자원을 예측하여 인프라 기술자가 물리적인 구성을 설계하는데, 이때 물리적인 구성은 최대 사양을 기준으로 구성되기 때문에 불필요한 비용이 사용될 수도 있다.
또한, 구축 후에도 지속적인 모니터링이 필요하며 유지, 보수가 필요하다.</p>
<p>위와 같은 이유로 많은 기업들이 클라우드 컴퓨팅 서비스를 사용하지만, 보안에 민감한 조직의 경우 자체적으로 강력한 보안 시스템을 개발하거나 외부망과의 단절을 위해 여전이 온프레미스 환경으로 구축한다.</p>
<h2 id="💻클라우딩-컴퓨팅cloud-computing">💻클라우딩 컴퓨팅(Cloud Computing)</h2>
<h3 id="💾compute란">💾Compute란?</h3>
<p>컴퓨팅은 스토리지 및 네트워킹과 함께 클라우드 컴퓨팅 인프라 계층의 핵심 컴포넌트 중에 하나이다. 기본적으로 compute란 Linux, Ubuntu, Debian, Window, MacOS와 같은 운영 체제를 실행하는 데 필요한 CPU, Memory, Storage와 일부 가상화된 네트워크 기능으로 구성된 물리적인 서버이다.</p>
<p><strong>CPU(Central Processing Unit)</strong>는 프로그램의 명령을 수행한다.
<strong>RAM(Random Access Memoty)</strong>은 초고속 임시 저장 장치로 CPU와 저장장치 사이에서 처리 속도를 향상시켜주기 위해서 데이터를 임시로 저장하는 역할을 수행한다.
<strong>Stod=rage</strong>는 운영체제 파일 또는 모든 소스코드 및 데이터가 저장되는 저장소이다.
<strong>Network</strong>는 보통 인터넷을 통해서 다른 서버와 연결할 수 있도록 만들어주는 네트워크 인터페이스 카드 이다.</p>
<p>정리하면, <strong><span style='color:red'>Compute</span></strong>란 CPU, Storage, Network 기능으로 구성된 물리적인 서버를 의미한다.</p>
<h3 id="💾클라우드-컴퓨팅이란">💾클라우드 컴퓨팅이란?</h3>
<p>현재 IT 분야에서 가장 빠르게 발전하는 기술 중 하나이다.
만약, 사용자에게 compute(물리적 서버)에 대한 요구가 들어올 때 마다 시스템 엔지니어가 CPU, Storage, Network를 담은 물리적인 서버를 설치한 후에 이를 대여해 준다면 시간도 오래걸리고, 비효율적이다.
그래서 클라우드 컴퓨팅 서비스를 제공하는 업체는 서로 다른 물리적 위치에 존재하는 컴퓨팅 자원을 가상화 기술로 통합하여 인터넷에서 제공한다.
즉, 사용자는 이러한 IT 리소스를 인터넷을 통해 온디맨드로 제공받고 사용한 만큼만 비용을 지불하면 된다.</p>
<p>위에서 말한것 처럼, 서로 다른 위치에 존재하는 컴퓨팅 자원을 제공하는 것이 클라우드 컴퓨팅 서비스이다. 클라우드 컴퓨팅 서비스를 제공하는 업체는 흔히 <span style='color:red'>서버팜</span>이라고 불리는 곳에 엄청난 수의 물리적 서버를 갖추고 있다.
서버 팜은 전 세계에 흩어져 있고, 이곳에 데이터를 저장한다.</p>
<h3 id="💾클라우드-컴퓨팅의-특징">💾클라우드 컴퓨팅의 특징</h3>
<ul>
<li><p>직접 서버 장비를 구매하지 않고도, 요청하는 즉시 컴퓨팅 자원을 제공해주는 기술로 원하는 시간동안 원하는 만큼의 컴퓨팅 자원을 언제 어디서나 이용할 수 있다. -&gt; 불필요한 절차없이 쉽게 프로젝트를 구성할 수 있으므로 프로젝트 초기 구성 시 사용되는 비용을 줄이는 효과를 가져온다.</p>
</li>
<li><p>온디맨드로 IT 리소스를 제공하므로, 사용자는 사용한 만큼의 비용만 지불하면 된다.</p>
</li>
<li><p>서비스의 규모에 따라 리소스를 확장하거나 축소할 필요가 있는데, 대부분의 클라우드 컴퓨팅 서비스는 이러한 기능을 기본적으로 지원하기 때문에 손쉽게 서비스를 확장 및 축소할 수 있다.</p>
</li>
</ul>
<h3 id="💾주요-기능-3가지">💾주요 기능 3가지</h3>
<h4 id="1-서비스형-인프라스트럭처laas">1. 서비스형 인프라스트럭처(laaS)</h4>
<p>laaS(lnfrastructure as a Service)비즈니스 운영에 필요한 스토리지, 네트워킹 및 컴퓨터 자원을 제공한다. 다른 모델들과 비교하여 사용자가 관리할 수 있는 영역이 가장 넓다. 
사용자가 직접 OS, Middleware, Runtime등을 직접 구성하고 관리할 수 있다.
laaS는 사용자가 직접 많은 부분을 구성하고 관리할 수 있지만, 인프라 운영에 대한 지식이나 경험이 준비되지 않은 경우에는 활용하기 어렵다.</p>
<h4 id="2-서비스형-플랫폼paas">2. 서비스형 플랫폼(PaaS)</h4>
<p>PaaS(Platform as a Service)는 애플리케이션 및 서비스를 구축할 수 있는 플랫폼을 제공한다.
OS, Middleware, Runtime 등 개발 환경을 미리 구축해 서비스 형태로 제공하기 때문에 관리적인 측면에서 laaS보다 자유도가 낮다. 사전에 구축된 환경에서 개발하기 때문에 의존성이 생기기 때문이다.</p>
<p>하지만, 서비스를 제외한 외적인 부분을 신경쓸 필요가 없기 때문에, 오로지 개발, 비즈니스에만 집중할 수 있으며 인프라를 운영하는 인력이 필요하지 않으므로 유지 및 보수 비용을 절약할 수 있다.</p>
<h4 id="4-서비스형-소프트웨어saas">4. 서비스형 소프트웨어(SaaS)</h4>
<p>SaaS(Software as a Service)는 클라우드 컴퓨팅 서비스의 주요 기능 3가지 중 <strong>가장 완성된 형태의 서비스</strong>이다.
해당 서비스의 제공 업체가 대부분의 기능을 구축한 뒤 제공하기 때문에 사용자가 직접 관리해야 하는 영역이 가장 좁다. 
기본적인 클라우드 인프라와 소프트웨어를 함께 제공하는 형태로, 소프트웨어 업데이트, 버그 픽스 등의 서비스를 업체가 직접 도맡아 제공한다.
사용자는 별도의 라이센스를 구매할 필요 없이 이미 구축된 소프트웨어를 무료 혹은 비용 지불을 통해 이용한다.</p>
<p>하지만, 이미 만들어 놓은 소프트웨어를 그대로 활용하기 때문에 필요하지 않은 기능에 대해서도 비용을 지불해야 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cloud Computing Services -(1)]]></title>
            <link>https://velog.io/@na_jeong/Cloud-Computing-Services-1</link>
            <guid>https://velog.io/@na_jeong/Cloud-Computing-Services-1</guid>
            <pubDate>Sun, 18 Dec 2022 15:06:24 GMT</pubDate>
            <description><![CDATA[<h2 id="💻운영-서버와-아키텍쳐">💻운영 서버와 아키텍쳐</h2>
<h3 id="💾운영-서버란">💾운영 서버란?</h3>
<p>애플리케이션을 개발할 때에는 주로 로컬 환경에서 개발, 테스트를 진행한다. 이런 로컬환경에서 실행되는 애플리케이션은 사용자에게 서비스를 제공할 수 없다.
운영 서버는 <strong>실제 사용자들을 대상으로 서비스하는 서버</strong>이다.
운영 서버는 트래픽 대응도 해야하고, 빠른 응답 속도와 높은 가용성을 보장해 안정적으로 제품이 서비스될 수 있도록 해야한다. 그러기 위해서는 로컬 서버와 다르게 서버 환경을 구성해야 하는데, 서비스의 특성에 따라 서버 환경 구성이 다르다.</p>
<h3 id="💾단일-서버">💾단일 서버</h3>
<p>가장 기본적인 서버.
환경을 구축하기 쉬워서 테스트 서버나 간단한 애플리케이션을 서비스 할 때 많이 사용하고, 데이터베이스와 애플리케이션이 같은 서버에서 실행되고 있어서 별도의 네트워크 설정이 필요 없다.</p>
<h4 id="🤔단일-서버의-단점">🤔단일 서버의 단점</h4>
<ol>
<li>전체 서비스의 장애 발생 가능성이 높다. -&gt; 같은 자원을 공유하기 때문에 애플리케이션과 DB 둘 중 하나라도 장애가 발생할 경우 전체가 다운될 수 있다.</li>
<li>서버 자원을 효율적으로 사용하기 어렵다. -&gt; 서비스의 속성에 따라 필요하거나 최적의 OS설정과 리소스의 종류가 다를 수 있다.</li>
<li>보안성이 떨어진다. -&gt; DB는 보안상 IP 주소나 포트 등 접속 지점을 최소화해야한다. 그러나 간단한 애플리케이션이라고 할지라도 그 특성 상, 여러 불특정한 IP 주소나 포트에 대해 요청을 받아야 하기에, 애플리케이션과 DB가 한 서버에 구축되어 있다면 보안에 취약하다.</li>
<li>서버의 수를 여러개로 늘려 자원을 확장하는 방식인 Scale-out이 어렵다. -&gt; 단일 서버의 구조처럼 애플리케이션과 DB가 하나의 서버로 구성되면 똑같은 데이터를 여러 서버에 복제해야 하므로 관리가 힘들다.</li>
</ol>
<h3 id="💾애플리케이션과-db-서버를-분리">💾애플리케이션과 DB 서버를 분리</h3>
<p>단일 서버 구성에서 하나로 이루어져 있던 애플리케이션과 데이터베이스를 각각의 서버로 구성하는 방식.
두 서버가 다른 자원을 사용하기 때문에 단일 서버의 단점을 어느 정도 해소해 주지만, 두개의 서버를 관리하므로 구성이 복잡해지고, 애플리케이션 서버와 DB서버 사이의 지연 시간과 네트워크 보안을 고려해야 한다.
또한, <strong>클라이언트는 여전히 하나의 애플리케이션 서버를 바라보기 때문에 <span style='color:red'>Scale-out</span>은 여전히 어렵다.</strong></p>
<h3 id="💾서버-내-앱-단위의-로드-밸런서">💾서버 내 앱 단위의 로드 밸런서</h3>
<blockquote>
<p>로드 밸런서란?
하나의 인터넷 서비스가 발생하는 트래픽이 많을 때 여러 대의 서버가 분산처리하여 네트워크 트래픽을  서버의 로드율 증가, 부하량, 속도저하 등을 고려하여 적절히 분산처리하여 해결해주는 서비스.
최신 애플리케이션은 수백만 명의 사용자를 동시에 처리하고 많은 데이터를 빠르고 안정적인 방식으로 각 사용자에게 반환해야 한다. 이렇게 많은 양의 트래픽을 처리하기 위해 대부분의 애플리케이션에는 데이터가 중복되는 리소스 서버가 많이 있다.
로드 벨런서는 사용자와 서버 그룹 사이에 위치하며 보이지 않는 촉진자 역할을 하여 모든 리소스 서버가 동일하게 사용되도록 하는 디바이스이다.</p>
</blockquote>
<p>출처 : <a href="https://aws.amazon.com/ko/what-is/load-balancing/">https://aws.amazon.com/ko/what-is/load-balancing/</a></p>
<p>기존에 하나의 로드 밸런서가 여러개의 서버로 요청을 분산해주었던 방식에서, 서버 내에 앱 단위의 로드 밸런서가 추가된 방식.
기존의 애플리케이션 서버 안에서 똑같은 애플리케이션을 여러 프로세스로 만들어 실행 해놓고 외부에서 들어온 요청을 프로세스 중 하나로 보내주는 방식이다.</p>
<p>하나의 서버에 여러 개의 프로세스를 실행해 하나의 서버에서 여러 개의 요청을 동시에 처리할 수 있으며, 서버의 자원을 최대한으로, 효율적으로 사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[인증&인가] - Session | Token ]]></title>
            <link>https://velog.io/@na_jeong/%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-Session-Token</link>
            <guid>https://velog.io/@na_jeong/%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-Session-Token</guid>
            <pubDate>Sat, 03 Dec 2022 10:31:22 GMT</pubDate>
            <description><![CDATA[<p>사용자와 시스템간 데이터를 교환하기 위해 HTTP 방식을 사용한다. HTTP 통신은 요청과 응답에 의해 동작하며, HTTP 특징 중 가장 중요한 특징은 <strong>Stateless</strong>이다.</p>
<p>각각의 HTTP 통신은 독립적이기 때문에 과거의 통신에 대한 내용을 알지 못한다. 이전의 상태를 전혀 알지 못하면 <strong>매 통신마다 필요한 모든 정보를 담아서 요청을 보내야 한다.</strong></p>
<p>이런 불편함을 없애기 위해 일부 정보에 대해서 <strong><span style='color:red'>Stateful 상태</span>를 유지할 필요</strong>가 있다. 이를 위해서 Session과 Cookie 또는 Token 같은 기술을 사용할 수 있다.</p>
<h2 id="📓session과-token">📓Session과 Token</h2>
<h3 id="📘session">📘Session</h3>
<p>클라이언트가 브라우저를 통해 웹 서버에 접속한 시점으로부터 브라우저를 종료하여 연결을 끝내는 시점 동안 클라이언트와 웹 서버가 논리적으로 연결된 상태이다.</p>
<p>서버는 Session 정보를 저장하고 클라이언트에게는 <strong>Session을 구분할 수 있는 Session ID</strong>를 부여한다. 이것을 Session ID라고 한다.</p>
<p>클라이언트 Request를 보낼 때 해당 Session ID를 함께 보냄으로써, 클라이언트의 상태를 확인할 수 있다.</p>
<h3 id="📘cookie">📘Cookie</h3>
<p>Cookie는 클라이언트의 컴퓨터에 저장되는 데이터 파일이다.</p>
<p>Cookie에는 <strong>이름, 값, 만료 날짜/시간, 경로 정보</strong>등으로 구성이 되어있다. Cookie는 하나의 도메인 당 20개를 가질 수 있으며, 1개 당 4Kbyte를 넘길 수 없다.</p>
<p>서버에서는 HTTP Resonse Header에 <strong>Set-Cookie</strong> 속성을 이용해 클라이언트에 Cookie를 제공하여 저장하게 하고, 클라이언트는 HTTP Request에 저장된 Cookie를 함께 전달하여 이전의 통신에서 사용된 정보들을 파악할 수 있다.</p>
<p>사용자별로 다른 정보를 표시하는 것이 가능하며, 사용자의 행동과 패턴을 분석할 수 있다.</p>
<h2 id="📓session과-cookie를-이용한-인증-flow">📓Session과 Cookie를 이용한 인증 Flow</h2>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/90258a82-aa13-432d-9504-06c609e702f1/image.png" alt=""> </p>
<ul>
<li>사용자가 로그인을 하기 위해 인증 정보를 가지고 인증 과정을 요청한다.</li>
<li>인증이 완료 되면 사용자의 Session 정보를 서버의 메모리에 저장 후 해당 Session을 식별할 수 있는 Session ID를 발급한다.</li>
<li>발급한 session ID가 Cookie에 저장될 수 있도록 HTTP Response Header의 Set-Cookie 속성을 이용하여 사용자에게 전달한다.</li>
<li>전달받은 session ID는 브라우저의 Cookie에 저장되고, request를 서버에 보낼 때 함께 전달된다.</li>
<li>서버는 사용자가 보낸 session ID와 서버 메모리에서 관리하고 있는 session ID를 비교하여 verification을 수행 후 권한을 인가한다.</li>
</ul>
<h2 id="📓session-기반-인증의-특징">📓Session 기반 인증의 특징</h2>
<h3 id="📘장점">📘장점</h3>
<ol>
<li>session ID 자체에는 유의미한 개인정보를 담고 있지 않다.</li>
<li>서버에서 정보를 관리하기 때문에 데이터의 손상 우려에 대해 상대적으로 안전하다.</li>
<li>서버에서 상태를 유지하고 있으므로, 사용자의 로그인 여부 확인이 쉽다.</li>
<li>경우에 따라서 강제 로그아웃 등의 제재를 가할 수 있다.</li>
</ol>
<h3 id="📘단점">📘단점</h3>
<ol>
<li>서버에서 모든 사용자의 상태를 관리해야 하므로 사용자의 수가 증가할 수 록 서버에 가해지는 부하가 증가한다.</li>
<li>사용자가 증가하여 서버의 Scale Out(규모확대)를 해야할 때 session관리가 어려워진다.</li>
<li>모바일 기기와 브라우저에서 공동 사용할 때 중복 로그인 처리가 되지 않는 문제 등 신경 써야할 부분이 증가한다.</li>
</ol>
<h2 id="📓token">📓Token</h2>
<p>Token의 사전적 의미는 버스 요금이나 자동판매기 등에 사용하기 위하여 상인, 회사 등에서 발행한 동전 모양의 주조물이다.
웹에서의 토큰도 이와 비슷한 의미를 가지고 있다.
웹에서 토큰을 가지고 있으면 해당 서비스를 이용할 수 있는 권리가 있다고 간주한다.</p>
<p>자세히 말하면,
Token은 제한된 리소스에 대해 일정 기간 동안 접근할 수 있는 권한을 캡슐화 한것이다.
Token은 일반적으로 의미를 알 수 없는 임의의 문자열 형태로 사용자에게 발급한다. 또한, 제한된 리소스에 대한 접근 권한을 캡슐화할 뿐만 아니라 접근할 수 있는 리소스의 범위와 접근 가능한 기간도 통제가 가능하다.</p>
<h2 id="📓token을-이용한-인증-flow">📓Token을 이용한 인증 Flow</h2>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/5201c5cf-6fb9-4538-b626-4baa5122700d/image.png" alt=""></p>
<ol>
<li>사용자가 로그인을 하기 위해 인증 정보를 가지고 인증 과정을 요청한다.</li>
<li>인증이 완료되면 서버의 메모리에 session을 저장하는 대신에 사용자의 식별 정보를 가지고 있는 Token을 발급한다.</li>
<li>발급한 Token은 Response의 body에 담아 사용자에게 전달한다.</li>
<li>사용자는 발급된 Token을 local storage에 저장한다.</li>
<li>사용자는 Request를 할 때마다 저장된 토큰을 Header에 포함시켜 서버로 보낸다.</li>
<li>서버는 사용자로부터 전달받은 Header의 토큰 정보를 Verification한 뒤, 해당 유저에 권한을 인가한다.</li>
</ol>
<h2 id="📓token의-특징">📓Token의 특징</h2>
<h3 id="📘장점-1">📘장점</h3>
<ol>
<li>Token을 사용자 측에서 저장하므로 서버의 메모리나 DB등의 부담이 없다.</li>
<li>사용자의 상태 정보를 서버에서 관리하지 않기 때문에 서버의 Scale Out에 용이하다.</li>
<li>모바일과 브라우저의 멀티 환경에서 사용이 용이하다.</li>
<li>Token의 만료 시간을 짧게 설정하여 안정성을 높일 수 있다.</li>
<li>CORS 방식을 사용하기에 용이하다.<blockquote>
<p>CORS(Cross Origin Resource Sharing)란?
우리가 가져오는 리소스들이 안전한지 검사하는 브라우저의 방화벽</p>
</blockquote>
</li>
</ol>
<h3 id="📘단점-1">📘단점</h3>
<ol>
<li>서버에서 사용자의 상태를 저장하고 있지 않기 때문에 사용자의 로그인 여부 확인, 경우에 따른 강제 로그아웃 등의 제재를 가하기 어렵다.</li>
<li>사용자가 임의로 토큰을 수정하거나 구조가 변경되게 되면 서버에서 확인할 수가 없다.</li>
<li>Payload 부분에 사용자 식별을 위한 여러 정보들이 포함되어 있어 session ID의 길이보다 길어져 HTTP request 전송 데이터의 크기가 증가한다.</li>
<li>XSS 공격에 취약하여 Payload에 민감한 정보를 포함하는 경우 위험할 수 있다.</li>
</ol>
<h2 id="📓token-based-authentication의-이점">📓Token based Authentication의 이점</h2>
<h3 id="📘stateless">📘Stateless</h3>
<p>Session 방식처럼 상태 정보를 서버측에서 관리 하지 않고, 사용자 측에서 관리하기 때문에 서버의 상태를 Stateless하게 유지하게 된다. 따라서 서버측에서는 사용자로부터 받은 Request만을 가지고 작업을 수행할 수 있다.</p>
<h3 id="📘scalability">📘Scalability</h3>
<p>서버의 상태를 Stateless하게 유지한다는 것은 사용자와 서버 사이에 관계가 없다는 의미도 된다. 일반적으로 session 기반 인증에서는 로그인 상태를 유지하기 위해서는 최초 로그인 시에 Request한 서버로 계속 session ID를 보내주어야 한다.
하지만 Token 기반의 인증 방식은 이러한 관계가 존재하지 않기 때문에 서비스를 운영 중인 어떤 서버로든지 Request를 보낼 수 있다.
그래서 token 기반의 인증 방식을 사용하면 서버의 확장에 유리하다.</p>
<h3 id="📘security">📘Security</h3>
<p>클라이언트가 서버로 요청을 보낼 때 더 이상 Cookie를 전달하지 않으므로, CSRF 공격을 방지하는 데 도움이 된다.</p>
<blockquote>
<p>CSRF(Cross-Site Request Forgery)는 악성 웹 사이트 공격 유형이다. CSRF 공격을 원클릭 공격 또는 세션 라이딩 이라고도 한다. 이 공격 유형은 웹 사이트가 신뢰하는 사용자로부터 권한 없는 요청을 전송한다.</p>
</blockquote>
<p>하지만 토큰 환경의 취약점이 존재할 수 있으므로 이에 대비해야 한다.</p>
<h3 id="📘extensibility">📘Extensibility</h3>
<p>Token 기반의 인증 시스템에서는 토큰을 통해 권한의 범위를 지정할 수 있다. 
이를 이용하여 Kakao, Facebook, Google 등과 같은 소셜 계정을 이용해 다른 웹서비스에서도 로그인이 가능하다.</p>
<h3 id="📘multiple-devices-and-domains">📘Multiple Devices and Domains</h3>
<p>서버 기반 인증 시스템의 문제점 중 하나인 CORS를 해결할 수 있다.
애플리케이션과 서비스의 규모가 커지면 여러 기기들을 호환시키고 더 많은 종류의 서비스를 제공하게 된다.
토큰을 사용한다면 어떤 기기, 어떤 도메인에서도 토큰의 유효성 검사를 진행한 후에 요청을 처리할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[인증&인가] - 인증과 인가]]></title>
            <link>https://velog.io/@na_jeong/%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@na_jeong/%EC%9D%B8%EC%A6%9D%EA%B3%BC-%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Fri, 02 Dec 2022 00:44:08 GMT</pubDate>
            <description><![CDATA[<h2 id="📓인증authentication">📓인증(Authentication)</h2>
<h3 id="🧐인증이란">🧐인증이란?</h3>
<p>누군가 또는 시스템이 실제로 그 누구인지 또는 시스템인지를 결정하는 과정이다. 인증 기술은 사용자의 자격 증명 정보와 인증 버서의 자격 증명 정보를 비교하여 시스템에 대한 엑세스 권한을 제공한다.</p>
<blockquote>
<p>ex)은행에 가면 통장과 도장을 제시해야 하고, 경우에 따라서 신분증을 추가적인 정보로 제공해야 한다.
만약 사용자가 제시한 정보와 데이터베이스에 존재하는 정보가 일치하지 않으면 은행 업무를 볼 수 없다.</p>
</blockquote>
<h3 id="📙인증의-유형">📙인증의 유형</h3>
<ol>
<li><p>SFA(단일 요소 인증)
자격증명 정보로서 ID와 비밀번호 만을 요구하는 방식.
쉽게 보안에 문제가 생긴다.</p>
</li>
<li><p>2FA(2단계 인증)
고유 코드나 지문 등의 추가적인 인증요소를 요구하는 방식.</p>
</li>
<li><p>MFA(다중 요소 인증)
2FA 유형에서 조금 더 보안을 강화하기 위해 3개 이상의 신원 확인 요소를 요구하는 방식</p>
</li>
</ol>
<h2 id="📓인가authorization">📓인가(Authorization)</h2>
<h3 id="🧐인가란">🧐인가란?</h3>
<p>사용자에게 특정 리소스 또는 기능에 대한 액세스 권한을 부여하는 프로세스이며, 종종 액세스 또는 클라이언트 권한과 같은 의미로 사용된다.</p>
<p>누군가에게 서버의 특정 파일을 다운로드 할 수 있는 권한을 부여하거나 개별 사용자에게 애플리케이션에 대한 관리 엑세스 권한을 제공하는 것 등이 인가의 예로 들 수 있다.</p>
<p>사용자에게 권한을 부여하기 위해서는 항상 인증 절차를 진행해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS]fetch]]></title>
            <link>https://velog.io/@na_jeong/JSfetch</link>
            <guid>https://velog.io/@na_jeong/JSfetch</guid>
            <pubDate>Wed, 30 Nov 2022 05:23:40 GMT</pubDate>
            <description><![CDATA[<h2 id="📓fetch의-정의">📓fetch의 정의</h2>
<p>특정 정보가 필요할 때 클라이언트는 서버에 HTTP 통신으로 요청(request)을 보내고, 정보를 응답(response) 받을 수 있다.
이때 사용되는 메서드가 fetch 메서드이다.
클라이언트는 fetch 메서드로 서버로 데이터를 요청해서 받을 수도 있고, 데이터를 생성, 수정, 삭제 할 수 있다.</p>
<h2 id="📓fetch-요청request">📓fetch 요청(request)</h2>
<p>fetch 메서드를 호출할 때, 첫 번째 인자로 전달한 API 주소에 정보를 달라고 요청하고 응답을 받는다. 
아래의 형태가 fetch 메서드의 기본 구조이다. </p>
<pre><code>// fetch 전문 예시

fetch(&#39;api주소&#39;, {
  method: &#39;...&#39;,
  headers: { &#39;key&#39;: &#39;value&#39; },
  body: JSON.stringify({ &#39;key&#39;: &#39;value&#39; }),
})                                      //요청
  .then((response) =&gt; response.json())
  .then((data) =&gt; console.log(data));
                                        //응답</code></pre><p>fetch 메서드를 호출할 때. 인자 2개를 전달할 수 있다. 첫 번째 인자 자리에는 데이터를 요청할 API 주소를 필수로 넣는다. 두 번째 인자는 요청의 옵션 값들로 필요에 따라 객체 형태로 넣을 수 있는데, <span style='color:red'>method, headers, body, mode, credentials, omit, same-origin, include, cache, redirect, referrer, referrerPolicy, integrity, keepalive, signal</span>등의 key와 각각 해당하는 value를 넣을 수 있다.
여기에서 중요한 건, 클라이언트의 입장에서 서버에게 요청하는 것이다.어디에서 요청하고, 어디에서 응답받는지 방향이 혼동되면 개념 정립에 좀 더 많은 시간이 할애될 수 있다.</p>
<p>fetch는 크게 요청과 응답 부분으로 나눌 수 있는데 여기서는 두 번째 인자로 전달하는 객체의 key중 자주 사용하는 <strong>method, headers,</strong> 그리고 <strong>body가 있는 요청</strong>과 <strong>body가 없는 요청</strong>으로 나눌 수 있다.</p>
<h3 id="📗첫번째-인자api주소---필수">📗첫번째 인자(api주소) - 필수</h3>
<p>fetch()첫 번째 인자 자리에 정보를 요청할 API 주소를 입력한다. API 주소는 서버에서 받아야 한다.
API 주소는 http:// 혹은 https://, IP 주소(with 포트번호) 혹은 도메인 주소, 엔드 포인트로 구성돼있다.</p>
<pre><code>// 첫번째 인자 예시

fetch(&#39;http://10.58.113.116:8000/sign-in&#39;);
fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;);</code></pre><h3 id="📗두번째-인자method---선택사항">📗두번째 인자(method) - 선택사항</h3>
<p>어떤 method로 요청할지 적는다. 
(GET, POST, PUT, PATCH, DELETE ...)</p>
<pre><code>// method 예시

fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;, {
  method: &#39;POST&#39;,
});</code></pre><h3 id="📗두번째-인자headers---선택사항">📗두번째 인자(headers) - 선택사항</h3>
<p>headers 는 서버에 요청할 때 보낼 부가적인 정보를 담는다.
(HOST, user-Agent, Authorization, Content-Type ...)</p>
<pre><code>// headers 예시

fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;, {
  method: &#39;POST&#39;,
  headers: {
    &#39;Content-Type&#39;: &#39;application/json;charset=utf-8&#39;,
  },
});</code></pre><h3 id="📗두번째-인자body---선택사항">📗두번째 인자(body) - 선택사항</h3>
<p>body에는 서버에 요청할 때 보낼 실질적인 정보를 담는다.
여기에서 요청 body가 있는 경우와 없는 경우로 나눌 수 있다.</p>
<h4 id="📖요청-body가-있는-경우">📖요청 body가 있는 경우</h4>
<p>서버에 보낼 정보가 있는 경우, 요청 body에 담아서 보낸다. 그런데 body value를 보면 JSON.stringify라는 메서드에 담아서 보내고 있다.</p>
<pre><code>fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;, {
  method: &#39;POST&#39;,
  headers: {
    &#39;Content-Type&#39;: &#39;application/json;charset=utf-8&#39;,
  },
  body: JSON.stringify({
    title: &#39;update title&#39;,
    content: &#39;서버에 요청할때 담아서 보내는 정보&#39;,
  }),
});</code></pre><p>body에 담긴 정보를 서버로 보낼 때 데이터 형태를 JSON 형태로 보내고 받아야 하는데, JSON으로 형 변환을 해주는 메서드가 JSON.stringify이다.</p>
<blockquote>
<p>💡왜 JSON일까 ?
통신 간, 서버와 클라이언트는 같은 언어일 수도 있고, 다른 언어일 수도 있다.  같은 언어라면 문제가 없겠지만 다른 언어라면 주고 받을 수가 없다.
JSON 형태를 사용하면 어떤 언어에서든 원하는 데이터를 주고받을 수 있다. JSON의 형태는 자바스크립트의 객체와 유사하지만, javascript가 아니더라도 JSON을 읽고 쓸 수 있는 기능이 대부분 언어에서 제공된다. 
그래서 JSON 형태로 통신을 주고받아야 한다. 메서드 사용 방법은 JSON.stringify 메서드 인자에 데이터를 담으면, JSON문자열로 반환된다.</p>
</blockquote>
<pre><code>//JSON.stringify로 변환된 body 형태 예시

// object
{
  title: &#39;update title&#39;,
  content: &#39;서버에 요청할때 담아서 보내는 정보&#39;,
};

// JSON
{ &quot;title&quot;: &quot;update title&quot;, &quot;content&quot;: &quot;서버에 요청할때 담아서 보내는 정보&quot; }
// JSON.stringify 형 변환 예시

console.log(JSON.stringify({ x: 5, y: 6 }));
// expected output: &quot;{&quot;x&quot;:5,&quot;y&quot;:6}&quot;

console.log(
  JSON.stringify([new Number(3), new String(&#39;false&#39;), new Boolean(false)])
);
// expected output: &quot;[3,&quot;false&quot;,false]&quot;

console.log(JSON.stringify({ x: [10, undefined, function () {}, Symbol(&#39;&#39;)] }));
// expected output: &quot;{&quot;x&quot;:[10,null,null,null]}&quot;

console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5)));
// expected output: &quot;&quot;2006-01-02T15:04:05.000Z&quot;&quot;</code></pre><h4 id="📖요청-body가-없는-경우">📖요청 body가 없는 경우</h4>
<p>요청 body가 없는 경우는 서버에 전달해 줄 정보 없이 정보만 달라고 요청만 한다.</p>
<pre><code>//body가 없는 요청 예시

fetch(&#39;https://jsonplaceholder.typicode.com/users/1&#39;, { method: &#39;GET&#39; });</code></pre><h2 id="📓비동기asynchronous">📓비동기(asynchronous)</h2>
<pre><code>console.log(1);
console.log(2);
setTimeout(() =&gt; console.log(3), 3000);
console.log(4);

//output
1
2
4
3</code></pre><p>위의 코드를 보면 1,2,3,4 로 출력되는 것이 아니라 1,2,4,3으로 출력이 된다. 
이유는 setTimeout 메서드가 비동기 함수이기 때문이다.</p>
<p><strong>동기(synchronous)</strong>적인 처리 방식은 이전의 작업이 끝나야 다음 작업으로 이어지는 처리 방식이다.
이 방식은 설계가 비교적 간단하고 처리의 순서를 파악하기 용이하다.
다만, 이전 처리가 끝날 때까지 기다려야 해서 연산이 오래 걸리거나, 언제 종료될지 모르는 예측 불가능한 처리 방식에는 아무것도 못하고 기다려야만 하는 단점이 있다.</p>
<p><strong>비동기(asynchronous)</strong>적인 처리방식은 이전 작업의 종료 여부와 상관없이 기다리지 않고 다른 작업을 할 수 있다. 동기적인 방식보다는 복잡하다는 단점이 있다.</p>
<p>그래서 통신은 중간에 인터넷 연결이 끊긴다거나, 속도가 느려 언제 통신이 끝날지 예측하기 어렵다.
그래서 통신은 동기적으로 처리하면 화면에 아무것도 출력되지 않은 채 마냥 기다려야 할 수도 있고, 에러 화면이 나오면서 정상적인 접근이 어려울 수도 있다.
그래서 통신과정은 동기적인 처리 순서에 영향을 주지 않도록 비동기로 처리해야 하고, fetch 함수는 그래서 비동기적으로 동작하도록 설계되어 있다.</p>
<h2 id="📓fetch-응답response">📓fetch 응답(response)</h2>
<p>.then() 메서드는 Promise를 처리할 수 있는 메서드이다. 
.then()은 Promise를 리턴하고 두 개의 콜백 함수를 인자로 받는다. 하나는 Promise가 이행됬을 때, 다른 하나는 거부했을 때를 위한 콜백 함수이다.
.then() 메서드는 Promise를 리턴 하기 때문에 첫번째 .then()에서 반환된 값을 두번째 .then()에 이어서 처리할 수 있는 메서드 체이닝(chaning)이 가능하다.</p>
<pre><code>.then() 메서드 문법
.then(function onFullfilled, [function onRejected]</code></pre><p>요청을 했으면 응답을 받을 차례이다.
아래의 코드를 보면 .then() 메서드가 2번 나온다.</p>
<pre><code>fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;, {
  method: &#39;POST&#39;,
  headers: {
    &#39;Content-Type&#39;: &#39;application/json;charset=utf-8&#39;,
  },
  body: JSON.stringify({
    title: &#39;update title&#39;,
    content: &#39;서버에 요청할때 담아서 보내는 정보&#39;,
  }),
}) 
                                              //요청
  .then((response) =&gt; response.json())
  .then((data) =&gt; console.log(data));
                                              //응답</code></pre><p>첫 번째 응답을 반환하는 then의 콜백에 response라는 매개변수를 console.log로 실행해 보면 아래의 값이 반환된다.</p>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/13bb4f32-24d4-4ac4-8e88-8a8d099e665f/image.png" alt=""></p>
<h3 id="📗status-code에-따른-첫번째-분기-처리">📗status code에 따른 첫번째 분기 처리</h3>
<p>아래는 response를 console로 출력한 코드이다. response 객체에 여러가지 key가 반환되는데, 여기서 반환된 key를 활용해 그 다음 처리 방법을 판단할 수 있다.
<img src="https://velog.velcdn.com/images/na_jeong/post/c208413b-773b-4438-84bc-c00c3e2f6c75/image.png" alt="">-요청 성공-
<img src="https://velog.velcdn.com/images/na_jeong/post/9e7d87bd-df05-42eb-9c77-1b3c10c7d50b/image.png" alt="">-요청 실패-</p>
<p>통신의 성공, 실패 여부를 판단하는 기준은 status이다. status는 statuscode를 의미한다. 통신 성공은 200 - 299일 때 ok값이 true이고, 통신이 실패한 경우 statuscode가 400 - 499 | 500 - 599이고 ok 값은 false로 반환된다.</p>
<pre><code>//첫번째 응답 분기처리 예시

fetch(&#39;https://jsonplaceholder.typicode.com/posts&#39;, {
  method: &#39;POST&#39;,
  headers: {
    &#39;Content-Type&#39;: &#39;application/json;charset=utf-8&#39;,
  },
  body: JSON.stringify({
    title: &#39;update title&#39;,
    content: &#39;서버에 요청할때 담아서 보내는 정보&#39;,
  }),
})
  .then((response) =&gt; {
    if (response.ok === true) {
      return response.json();
    }
    throw new Error(&#39;에러 발생!&#39;); //reponse.ok가 true가 아닐 경우 error를 throw
  })
  .catch((error) =&gt; console.log(error)); //throw된 error를 받아서 console에 출력</code></pre><p>통신은 성공과 실패 여부를 예측하기 어렵기 때문에 첫 번째 응답받은 status 코드에 따라 처리 방법을 나눌 수 있다. 통신에 성공하면 response의 body를 객체로 만드는 메서드를 호출하고, 통신에 실패하면 console에 메시지를 출력하는 예시이다. 만약 실패하면 원인을 찾아 수정한다.</p>
<p>여기서 통신에 성공하면 응답받은 response 객체 중 body의 값은 JSON 형태이다.
JSON은 자바스트립ㅇ트의 문법으로 처리할 수 없다. 자바스크립트 데이터 타입으로 만들어야 데이터를 가공할 수 있다.
첫 번째 then에서 response.json()메서드가 JSON 형태를 자바스크립트 객체로 변환해주는 메서드이다. 이렇게 첫번째 then에서 JSON에서 객체로 변했고, 리턴된 객체는 두번째 then() 메서드로 넘겨진다.</p>
<h3 id="📗첫-번째-응답에서-반환된-객체로-두번째-응답에서-분기-처리">📗첫 번째 응답에서 반환된 객체로 두번째 응답에서 분기 처리</h3>
<p>통신에 성공해서 JSON을 객체로 변환했다면, 변환된 객체를 활용해서 분기 처리할 수 있다.</p>
<pre><code>//두번째 응답 분기처리 예시

fetch(&#39;로그인 API&#39;, {
  method: &#39;post&#39;,
  body: JSON.stringify({
    id: &#39;qawsedrf&#39;,
    password: &#39;123456&#39;,
  }),
})
  .then((response) =&gt; {
    if (response.ok === true) {
      return response.json();
    }
    throw new Error(&#39;에러 발생!&#39;);
  })
  .catch((error) =&gt; console.log(error))
  .then((data) =&gt; {
    if (data.message === &#39;login success&#39;) {
      localStorage.setItem(&#39;TOKEN&#39;, data.token);
      alert(&#39;로그인 성공&#39;);
    } else {
      alert(&#39;로그인 실패&#39;);
    }
  });

//data 예시
  data: {
    message: &#39;login success&#39;,
    token:    &#39;eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1fQ.Dy3PPHIOFFe3ScGTb8x3hewItnpOcgC9YDdW7v27XHg&#39;,
  },</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Mock Data]]></title>
            <link>https://velog.io/@na_jeong/React-Mock-Data</link>
            <guid>https://velog.io/@na_jeong/React-Mock-Data</guid>
            <pubDate>Wed, 30 Nov 2022 01:38:07 GMT</pubDate>
            <description><![CDATA[<h2 id="📓mock-data">📓Mock Data</h2>
<h3 id="📙-mock-data란">📙 Mock Data란?</h3>
<p>UI 구성에 필요한 백엔드 API가 완성되기 전에 프론트엔드는 데이터가 들어오는 상황에 대비해 의도한대로 UI가 구현되는지 확인을 해야한다. 이때 사용되는 데이터가 Mock Data이다.
<strong>즉, 실제 API에서 받아온 데이터가 아닌 <span style='color:red'>프론트엔드 개발자가 필요에 의해 샘플로 만든 데이터</span>이다.</strong></p>
<h3 id="📙mock-data를-사용하는-이유">📙Mock Data를 사용하는 이유</h3>
<p>백엔드 API가 미완성인 상황에서 Mock Data를 사용하지 않는다면, 대부분은 실제 데이터가 들어올 부분들을 하드코딩으로 대체하고 작업을 하게 된다. 그렇게 개발을 진행한다면 여러 문제가 발생할 수 있다. </p>
<p>우선 개발이 진행됨에 따라 코드가 확장된 상태이기 때문에, 백엔드 API가 완성되고 실제 데이터를 반영하는 작업을 수행할 때 번거로울 수 있다.
또한, 실제 데이터에서는 존재하지 않는 값을 토대로 UI를 그렸거나, 반대로 실제 데이터를 기반으로 작업해야 하는 내용이 누락되었을 수도 있다.</p>
<p>Mock Data를 사용하면 위와 같은 문제를 해결할 수 있다.</p>
<ul>
<li>백엔드 API가 미완성인 상태에서도 작업에 차질 없이 개발할 수 있다.</li>
<li>백엔드 API의 구성을 미리 맞춰볼 수 있다.</li>
<li>실제로 API 통신을 진행할 때 원활하게 할 수 있다.</li>
</ul>
<h3 id="📙mock-data-생성">📙Mock Data 생성</h3>
<h4 id="🖍형태">🖍형태</h4>
<p>Mock Data는 실제 서버에서 보내주는 데이터의 형식과 동일하게 만들어야 하기 때문에 <span style='color:red'>json</span> 확장자 파일로 JSON 형식의 데이터를 생성한다.</p>
<blockquote>
<p>JSON이란 Java Script Object Notation의 줄임말로, 단어 기준 그대로 자바스크립트를 객체로 표현한 것이다.
key : value 의 객체 형태이고, 백엔드와의 데이터 통신을 위해 사용하는 형식이다.</p>
</blockquote>
<p>마켓컬리 데이터로 예를 들면 이런식으로 사용할 수 있다.</p>
<pre><code>// public/data/productData.json

{
  &quot;id&quot;: 3,
  &quot;image_url&quot;: &quot;https://img-cf.kurly.com/shop/data/goods/1648203571907l0.jpg&quot;,
  &quot;name&quot;: &quot;[콜린스그린] 더 오렌지 1000mL&quot;,
  &quot;short_description&quot;: &quot;물 한방울 넣지 않고 순수한 오렌지 과육을 짜낸 100% 착즙 오렌지 주스&quot;,
  &quot;discounted_price&quot;: 14080,
  &quot;discount_rate&quot;: 20,
  &quot;original_price&quot;: 17600,
  &quot;unit_text&quot;: &quot;1병&quot;,
  &quot;weight&quot;: &quot;1000ml&quot;,
  &quot;delivery_type&quot;: [
    { &quot;id&quot;: 0, &quot;text&quot;: &quot;샛별배송&quot; },
    { &quot;id&quot;: 1, &quot;text&quot;: &quot;택배배송&quot; }
  ],
...
}</code></pre><p>Mock Data는 서버에서 받아올 데이터의 모조 데이터인 만큼 프론트엔드 개발자가 <strong>로컬 서버</strong>에서 Mock Data를 받아오도록 구현해야 하기 때문에 <span style='color:red'>.json</span> 파일로 생성해야 한다.</p>
<h4 id="🖍위치">🖍위치</h4>
<p>Mock Data는 로컬 서버에서 받아오도록 구현해야 하기 때문에 파일의 위치는 npm start시 로컬 서버에 올라가는 폴더인 <strong>public 폴더 하위</strong>에서 관리해야 한다. public 폴더 하위에 data 폴더 생성 후 해당 폴더에서 Mock Data를 관리한다.</p>
<h3 id="📙mock-data-사용">📙Mock Data 사용</h3>
<h4 id="🖍호출">🖍호출</h4>
<p>Mock Data는 실제 데이터와 동일하게 <strong>fetch</strong> 메서드에서 호출한다.
fetch 메서드의 첫 번째 인자로 http 요청을 보낼 API 주소를 받는데, 여기에 생성한 Mock Data의 주소를 입력한다. <span style='color:red'><a href="http://localhost:3000">http://localhost:3000</a></span>은 생략 가능하며 생략 안하고 사용 시, 로컬 서버가 여러개 열려있다면 새로운 로컬 서버를 실행할 때마다 포트번호가 바뀌게 되어 일일이 수정을 해야한다. </p>
<pre><code>fetch(&#39;/data/recommendData.json&#39;, {
  method: &#39;GET&#39;
})</code></pre><p>두 번째 인자는 요청을 보낼 때의 옵션 객체를 전달하는 부분이다. 위의 코드인 경우 서버로부터 데이터를 받아오는 <strong>GET</strong> 요청이기 때문에 method옵션에 명시해주었다. <em>(대부분의 경우 method가 GET일 때 생략 가능)</em></p>
<pre><code>fetch(&#39;/data/recommendData.json&#39;, {
  method: &#39;GET&#39;
})
  .then(res =&gt; res.json())
  .then(data =&gt; {
    setProductList(data);
  });</code></pre><p>이후 JSON 형태의 response 데이터를 자바스크립트 객체 형태로 바꿔준 다음, 받아온 데이터를 화면에 그려주기 위해 productList state를 업데이트 해준다.</p>
<h4 id="🖍호출시점">🖍호출시점</h4>
<p>fetch 메서드를 통해 Mock Data를 받아오는 시점은 실제로 데이터를 불러오는 시점이 언제인지에 따라 다르다. 버튼을 클릭했을 때 받아와야 하는 경우도 있고, 페이지를 불러올 때 바로 화면에 그려줘야 하는 경우도 있ㄷ.</p>
<pre><code>useEffect(() =&gt; {
  fetch(&#39;/data/recommendData.json&#39;, {
    method: &#39;GET&#39;
  })
    .then(res =&gt; res.json())
    .then(data =&gt; {
      setProductList(data);
    });
},[]);</code></pre><p>위의 코드는 페이지를 불러올 때 바로 화면을 그려줘야한다. 그러므로 useEffect hook을 통해 컴포넌트가 마운트 된 후 한번만 데이터를 받아오도록 한다.</p>
<p><strong>fetch method는 반드시 useEffect와 함께 사용해야만 하는 것은 아니다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 상수 데이터]]></title>
            <link>https://velog.io/@na_jeong/React-%EC%83%81%EC%88%98-%EB%8D%B0%EC%9D%B4%ED%84%B0</link>
            <guid>https://velog.io/@na_jeong/React-%EC%83%81%EC%88%98-%EB%8D%B0%EC%9D%B4%ED%84%B0</guid>
            <pubDate>Tue, 29 Nov 2022 15:03:33 GMT</pubDate>
            <description><![CDATA[<h2 id="📓상수-데이터">📓상수 데이터</h2>
<h3 id="📙상수-데이터란">📙상수 데이터란?</h3>
<p>페이지를 구성하다 보면 UI 구성에는 필요하지만 값이 변하지 않아서 백엔드 API 등을 통해 가져올 필요가 없는 데이터들이 있다.이런 데이터들을 상수 데이터로 만들어 UI를 구성할 수 있다.
즉, 상수 데이터란 이름 그대로 <strong>변하지 않는 정적인 데이터</strong>를 의미한다.</p>
<p><img src="https://velog.velcdn.com/images/na_jeong/post/35ba96c8-5714-4ca8-8cb9-c0113114ac26/image.png" alt="">
GitHub 페이지를 예로 들어 상단의 드롭다운 메뉴는 UI 구성에는 필요하지만 고정적인 데이터이기 때문에 API에서 따로 데이터를 가져올 필요가 없다.
이것이 정적 데이터이다.</p>
<h3 id="📙상수-데이터를-사용하는-이유">📙상수 데이터를 사용하는 이유</h3>
<p>반복되는 UI를 하드코딩으로 일일이 만들어두면 가독성이 좋지 않고, 수정이 필요할 시에 해당하는 부분을 찾기 힘들어 유지보수가 어렵다는 문제가 있다.</p>
<p>상수 데이터를 사용하면 <strong><span style='color:red'>Array.map()</span></strong> 메서드와 조합해서 반복되는 UI를 보다 간결하게 표현할 수 있다. 이후 수정이 필요한 경우 레이아웃은 map 메서드에서 return 하는 JSX 부분만, 내용은 상수 데이터 부분만 수정해주면 되기 때문에 유지보수도 용이해진다.</p>
<h2 id="📓활용">📓활용</h2>
<h3 id="📙상수-데이터-선언">📙상수 데이터 선언</h3>
<p>중복되는 코드를 기반으로 상수 데이터를 만들 때는 map 메서드를 활용해 <strong>동일한 UI를 반복할 것</strong>이기 때문에, 배열로 만들어준다.
<strong>상수 데이터의 <span style='color:red'>변수명</span>은</strong> <strong><span style='color:red'>UPPER_SNAKE_CASE</span></strong> naming convention에 따라 명명한다.</p>
<img src='https://velog.velcdn.com/images/na_jeong/post/09c1ed8e-20ad-4475-a3f2-ad0ee79050ce/image.png' width=400px />

<p>요소의 형태는 구조에 따라서 위와 같은 객체 형태 뿐만 아니라 숫자, 문자열, 배열 등이 될 수도 있다.</p>
<h3 id="📙상수-데이터-적용">📙상수 데이터 적용</h3>
<img src='https://velog.velcdn.com/images/na_jeong/post/b2589013-c87a-4cb1-80ee-cce0f7deccf5/image.png' width=400px />

<p>map 함수를 활용해 실제 코드에 적용해보았다.
이후의 유지보수는 쉽다. 특정 학목의 데이터를 수정하고 싶다면, 상수 데이터에서 해당 항목을 쉽게 찾아 수정할 수 있기 때문이다.</p>
<h3 id="📙선언-위치">📙선언 위치</h3>
<p>상수 데이터는 어디서 선언하고 관리해야 할까 ?</p>
<ol>
<li>컴포넌트 파일 내부에 선언해서 사용</li>
<li>별도의 js파일로 분리해서 사용
의 두가지 경우가 있다.</li>
</ol>
<h4 id="💎컴포넌트-파일-내부에서-선언">💎컴포넌트 파일 내부에서 선언</h4>
<p>상수 데이터가 해당 컴포넌트 내에서만 사용되고 가독성을 해치지 않는다면, 컴포넌트 파일 내부에서 상수 데이터를 선언해 사용한다. 이떼, 상수 데이터의 구성에 따라 다른 위치에 작성한다.</p>
<ul>
<li>컴포넌트의 state나 props 등, 컴포넌트 리렌더링 시 변하는 값을 포함하는 상수 데이터는 컴포넌트 내부에서 작성</li>
<li>컴포넌트가 리렌더링 될 때마다 새로 선언되고 할당될 필요가 없는 상수 데이터는 컴포넌트 외부에서 작성</li>
</ul>
<p>위에서 내가 사용한 상수 데이터는 후자의 경우이기 때문에 컴포넌트 외부에서 작성하였다.</p>
<h4 id="💎별도-파일로-분리">💎별도 파일로 분리</h4>
<p>상수 데이터가 해당 컴포넌트 뿐만 아니라 다른 컴포넌트에서도 공통적으로 사용되는 경우, 혹은 상수 데이터의 길이가 너무 길어서 가독성을 해치는 경우에는 별도의 JS 파일로 분리해서 사용할 수 있다.</p>
<p>이 경우, 해당 파일에서 export한 상수 데이터를 사용할 컴포넌트에서 import하여 사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 구조 분해 할당]]></title>
            <link>https://velog.io/@na_jeong/React-DestructuringAssignment</link>
            <guid>https://velog.io/@na_jeong/React-DestructuringAssignment</guid>
            <pubDate>Tue, 29 Nov 2022 12:03:58 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>컴포넌트를 나누어 props를 받아와 comment 컴포넌트 구현을 하던 중, 
오류는 없지만 코드상으로 노란줄이 찍히면서 아래의 문구가 찍혔다.
Must use destructuring props assignmenteslintreact/destructuring-assignment
처음엔 무시할까.. 하다가 아무리 오류 내용을 찾아봐도 알 수가 없어 멘토님께 호다닥 감</p>
</blockquote>
<pre><code>//코드 생략
&lt;strong&gt;{props.userName}&lt;/strong&gt;
&lt;span&gt;{props.list}&lt;/span&gt;
//코드 생략</code></pre><p>저 props.<strong>____</strong> 부분들이 노란줄이 그어져있었다.
대충 props. 을 반복해서 사용하니 eslint에서 오류로 구분이 되어졌다고 한다. 해결방법으로 <strong><span style='color:red'>&quot;구조 분해 할당&quot;</span></strong> 을 검색해보라는 조언이 있었다 !</p>
<h3 id="🧐구조-분해-할당">🧐구조 분해 할당?</h3>
<p>구조 분해 할당 구문은 배열이나 객체의 속성을 해체하여 값들을 개별 변수에 저장하는 JavaScript의 표현식이다.
React에서 구조 분해를 사용하면 객체 안에 있는 필드 값을 원하는 변수에 대입할 수 있어서 코드의 가독성을 높이고 간략화를  할 때 유용하게 사용된다.</p>
<h3 id="🔥해결">🔥해결</h3>
<img src='https://velog.velcdn.com/images/na_jeong/post/7e7a4a6e-e44f-4d3c-a715-b07c66b00ae0/image.png' width=600px />

<p>먼저 부모 컴포넌트에서 받아온 props에 구조 분해 할당을 수행했다.
그 다음 return 부분에서,
<img src='https://velog.velcdn.com/images/na_jeong/post/293c83f6-488b-4002-8d83-ff212b6c54c5/image.png' width=600px /></p>
<p>저장된 변수를 사용해주었더니, 노란줄이 사라졌다 !
일일히 props. 을 사용하지 않아도 되니 편리하기도 하고, 코드가 많아질 수록 구조 분해 할당을 잘 쓰는게 중요하다고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useEffect]]></title>
            <link>https://velog.io/@na_jeong/React-useEffect</link>
            <guid>https://velog.io/@na_jeong/React-useEffect</guid>
            <pubDate>Tue, 29 Nov 2022 04:48:35 GMT</pubDate>
            <description><![CDATA[<h2 id="📓useeffect">📓useEffect</h2>
<p>Data Fetching, 구독 등의 side effect는 매우 조심스럽게 다뤄야 한다.
리액트에서 side effect는 언제 어떻게 발생시켜야 할까 ?</p>
<h3 id="📙react에서-side-effect의-올바른-발생-시점">📙React에서 side effect의 올바른 발생 시점</h3>
<pre><code>const App = () =&gt; {
    return &lt;h1&gt;Hello World&lt;/h1&gt;
};</code></pre><p>위의 코드에서 <span style='color:red'>Hello World</span>형태의 JSX를 브라우저에 렌더링 한다. 이 상황에서 side effect를 발생시키고 싶다면 어떻게 해야할까 ??
가장 먼저 떠올릴 수 있는 생각은 &#39;함수의 return문 위에 하고싶은 동작을 넣어두자&#39;이다.</p>
<pre><code>const App = () =&gt; {
    const doSideEffect = () =&gt; {
        //do some side effect
    };

    doSideEffect();

    return &lt;h1&gt;Hello World&lt;/h1&gt;;
};</code></pre><p>하지만 위와 같이 랜더링 단계에서 side effect를 발생시키면 두 가지 문제가 발생한다.</p>
<ol>
<li><strong>side effect가 렌더링을 blocking한다.</strong></li>
<li><strong>매 랜더링마다 side effect가 수행된다.</strong></li>
</ol>
<p>무슨말인가하면 !</p>
<h4 id="🔥side-effect가-렌더링을-blocking">🔥side effect가 렌더링을 blocking</h4>
<pre><code>const App = () =&gt; {
    const doSideEffect = () =&gt; {
        //do some side effect
    };

    doSideEffect();

    return &lt;h1&gt;Hello World&lt;/h1&gt;;
};</code></pre><p>기본적으로 코드는 위에서 아래로 순차적으로 실행된다. 따라서 App 함수 컴포넌트는 <span style='color:red'>doSideEffect()</span>동작이 끝날 때까지 JSX를 리턴하는 코드로 넘어가지 않는다. 컴포넌트가 JSX를 return하기 전까지는 UI가 브라우저상에 랜더링 되지 않기 때문에 결국 사이드 이펙트가 끝나기 전까지 렌더링을 하지 못하고 멈춰있게 된다.</p>
<p>즉, 사용자가 UI가 업데이트되는 것을 보기까지 오랜 시간이 소요된다는 것이다. 이는 곧 사용자에게 좋지 못한 사용자 경험을 제공한다는 의미이다.</p>
<h4 id="🔥매-랜더링마다-side-effect가-수행">🔥매 랜더링마다 side effect가 수행</h4>
<p>특정한 side effect들은 매번 실행될 필요가 없을 수도 있다. 예를 들어 인스타그램에서 피드에 대한 정보를 받아서 리스트를 보여주는 화면이 있다. 피드를 보여주기 위해서는 최초에 피드 데이터들을 가져오는(Data Fetching) side effect가 필요하다. </p>
<p>생각을 해보면, 외부에서 가져오는 side effect는 매 랜더링마다 수행될 필요는 없다.</p>
<pre><code>const App = () =&gt; {
    //data fetching side effect

    getFeeds();

    return FeedList;
};</code></pre><p>피드리스트에서 특정 피드에 좋아요를 눌르면 하트 색깔이 변경된다. 색상을 변경하려면 컴포넌트에서 리랜더링을 발생시켜야 하는데, 리랜더링이 된다는 것은 함수 컴포넌트를 다시 한번 호출한다는 뜻이다.
<strong>(리액트는 컴포넌트의 state나 props가 변하면 자동으로 해당 함수 컴포넌트를 다시 호출하면서 리랜더링을 수행해준다.)</strong></p>
<p>즉, App이라는 함수가 다시 호출되고 그렇다면 다시 함수 내부의 코드를 위에서 아래로 순차적으로 실행시킨다.
그 말은 다시 한번 <span style='color:red'>getFeeds()</span> side effect를 발생시킨다는 의미이다.</p>
<p>작은 UI 업데이트 발생 시 마다 매번 모든 피드 데이터를 다 가져온다면 불필요한 동작을 계속 수행하기에 비효율적이다.</p>
<h4 id="🔥정리하자면">🔥정리하자면</h4>
<p>React에서 side effect는</p>
<ol>
<li><strong>랜더링을 blocking 하지 않기 위해서 <em>랜더링이 모두 완료되고 난 후 실행할 수 있어야 한다.</em></strong></li>
<li><strong>매 랜더링마다 실행되는 것이 아니라 <em>내가 원할 때만 조건부로 실행할 수 있어야 한다.</em></strong></li>
</ol>
<p>위 두가지 조건을 충족시키면서 발생시키는 것이 좋다.
이 두가지를 충족시키면서 side effect를 발생시킬 수 있게 도와주는 것이 <strong><span style='color:red'>useEffect</span></strong> 라는 hook이다.</p>
<h3 id="📙useeffect-사용법">📙useEffect 사용법</h3>
<p>useEffect는 리액트에서 side effect를 편리하고 안전하게 발생시킬 수 있게 도와주는 hook이다.
사용법은,
<span style='color:purple'>useEffect(콜백함수);</span></p>
<p>useEffect는 함수이고, 매개변수로 콜백 함수를 가진다. 우리는 useEffect에 인자로 전달하는 콜백 함수에서 특정한 side effect를 수행시킬 수 있다.</p>
<pre><code>const App = () =&gt; {
    doSideEffect();

    return &lt;h1&gt;Hello World&lt;/h1&gt;
};</code></pre><p>위 코드는 useEffect없이 side effect를 발생시키는 코드이다. 여기서는 side effect를 랜더링 전에 발생시키고 있다. 이러한 코드는 렌더링을 blocking하기에 좋지 않기에 이를 해결하기 위해서 useEffect를 사용할 수 있다.</p>
<pre><code>import { useEffect } from &#39;react&#39;;

const App = () =&gt; {
  // 코드 생략

  useEffect(doSideEffect);

  return &lt;h1&gt;Hello, Wecoder&lt;/h1&gt;;
};</code></pre><p>side effect를 발생시키는 함수를 바로 후철하는 것이 아니라 useEffect의 인자로 전달했다.
위와 같이 useEffect의 인자로 전달된 콜백 함수는 곧바로 호출되는 것이 아니라 모든 랜더링이 완료된 후에 호출된다.
즉, 랜더링을 blocking 하지 않고 side effect를 발생시킬 수 있게 되는 것이다.</p>
<h3 id="📙조건부로-side-effect-발생시키기">📙조건부로 side effect 발생시키기</h3>
<p>useEffect를 통해서 <strong>랜더링이 모두 완료되고 난 후 side effect를 실행한다는 요구사항은 충족되었지만</strong> 아직도 매 랜더링마다 side effect가 실행된다는 사실은 변함이 없다.
특정 조건이 충족할 때만 발생시키는 방법은 무엇일까 ?</p>
<p>useEffect는 콜백 함수 외에 의존성 배열이라는 두번째 매개변수를 가진다.
의존성 배열은 배열의 형태이다. 이 배열이 side effect의 발생 여부르 결정짓는 조건이다.</p>
<p><strong><span style='color:purple'>useEffect(콜백 함수, 의존성 배열)</span></strong></p>
<p>useEffect의 동작 방식
첫 번째 랜더링 이후에는 무조건 useEffect에 전달된 콜백 함수를 호출하고 다음 랜더링부터는 아래의 조건에 따라 동작한다.</p>
<ol>
<li>의존성 배열이 전달되지 않았다면 매 랜더링마다 콜백 함수를 호출한다.</li>
<li>의존성 배열이 전달되었다면 의존성 배열의 값을 검사한다.</li>
</ol>
<ul>
<li>의존성 배열에 있는 값 중 <strong>하나라도 이전 랜더링과 비교했을 때 달라졌다면</strong> 콜백 함수를 호출한다.</li>
<li>의존성 배열에 있는 값이 <strong>이전 랜더링과 비교했을 때 모두 다 같다면</strong> 콜백 함수를 호출하지 않는다.</li>
</ul>
<p>즉, useEffect에서 첫 번째 인자인 콜백 함수는 <strong><em>실행시킬 동작</em></strong>을 결정하고 두 번쩨 인자인 의존성 배열은 <strong><em>실행시킬 타이밍을 결정</em></strong>짓는다고 할 수 있다.</p>
<h3 id="📙rendering--effect-cycle">📙Rendering &amp; Effect Cycle</h3>
<img src="https://velog.velcdn.com/images/na_jeong/post/7799a611-2496-4062-9844-962c5a3a388b/image.png" width='500px' />
출처: https://dmitripavlutin.com/react-useeffect-explanation/

<p>위의 그림은 <span style='color:red'>useEffect</span>와 <span style='color:red'>React Component</span>가 렌더링 되는 과정을 함꼐 도식화 한 다이어그램이다.</p>
<p>함수 컴포넌트의 렌더링과 useEffect가 발생하는 과정을 풀어서 설명하면,</p>
<ol>
<li>컴포넌트가 렌더링 된다. (최초로 진행되는 렌더링은 브라우저에 처음으로 이 컴포넌트가 보였다는 의미로 <span style='color:red'>mount</span>라고 표현한다.)</li>
<li>useEffect 첫 번째 인자로 넘겨준 콜백 함수가 호출된다 <strong>(side effect)</strong></li>
<li>컴포넌트의 state 또는 props가 변경되었을 경우 리렌더링이 발생한다. <strong>(update)</strong></li>
<li>useEffect는 두 번째 인자에 들어있는 의존성 배열을 확인한다.<ul>
<li>만약 <strong>의존성 배열이 전달되지 않았거나, 의존성 배열 내부의 값 중 이전 렌더링과 비교했을 때 변경된값이 하나라도 있다면</strong> 첫 번째 인자로 넘겨준 콜백 함수가 호출된다. <strong>(side effect)</strong></li>
<li>의존성 배열 <strong>내부의 값 중 이전 렌더링과 비교했을 때 변경된 값이 없다면</strong> 콜백 함수를 호출하지 않는다.</li>
<li>state 또는 props가 변경된다면 3 - 4 과정 반복</li>
</ul>
</li>
<li>컴포넌트가 더 이상 필요 없어지면 화면에서 사라진다. <strong>(컴포넌트가 브라우저의 화면에서 사라졌다는 의미로 <span style='color:red'>unmount</span>라고 표현한다.)</strong></li>
</ol>
<h2 id="📓clean-up">📓Clean Up</h2>
<h3 id="📙clean-up의-필요성">📙Clean Up의 필요성</h3>
<p>불필요하게 계속해서 side effect가 남아있어서 비효율적으로 작동할 수 있고, 프로그램의 동작이 의도한 대로 되지 않을 수 있기 때문에 지속적으로 남아있게되는 side effect를 반드시 <strong>clean up</strong>해줘야 한다.</p>
<pre><code>useEffect(() =&gt; {
    const cntTime = () =&gt; {
        console.log(&#39;100ms가 지남&#39;);
    };

    setInterval)cntTime, 100);
}, []);</code></pre><p>위의 side effect는 claen up이 필요하다.
코드를 보면 setInterval 함수를 이용해서 100ms마다 cntTime 함수가 호출된다.
useEffect의 의존성 배열에 빈 배열이 전달되었으므로 첫 번째 랜더링 이후에 side effect가 실핸된다.
그런데 이 side effect를 clean up 해주지 않는다면 컴포넌트가 unmount 되는 경우 등 setInterval을 통한 구독이 필요 없어진 상황에서도 계속해서 콘솔이 출력이 된다.</p>
<p>또 다른 예를 들어보면,</p>
<pre><code>useEffect(() =&gt; {
  const button = document.getElementById(&#39;consoleButton&#39;); // 1

  const printConsole = () =&gt; {
    console.log(&#39;button clicked&#39;);
  }; // 2

  button.addEventListener(&#39;click&#39;, printConsole); // 3
});</code></pre><p>useEffect에 의존성 배열을 전달하지 않았을 때 side effect가 매 렌더링마다 실행된다.
위의 코드는 아래의 순서로 동작을 하고 있다.</p>
<ol>
<li>document.getElementById 메서드를 통해서 consoleButton이란 ID를 가진 요소를 가져와서 button 변수에 할당한다.</li>
<li>printConsole 함수를 선언한다.</li>
<li>button에 클릭 이벤트가 발생할 때마다 printConsole이 실행되도록 button에 eventListener로 등록한다.</li>
</ol>
<p>이 side effect는 매 렌더링마다 실행되기 때문에 렌더링이 될 때마다 button에 eventListener가 추가된다. 즉 eventListener가 계속해서 중첩되고 있다는 뜻이다.</p>
<p>따라서, 첫 렌더링 이후에는 버튼을 누르면 콘솔이 한번만 출력되지만, 두 번째 렌더링이 되면 이벤트리스너가 한번 더 추가되기 때문에 렌더링이 될 때마다 콘솔 출력 횟수가 늘어나게 된다.</p>
<p>그래서 <strong>clean up</strong>이 필요한 것이다.</p>
<h3 id="📙clean-up-방법">📙Clean Up 방법</h3>
<p>useEffect는 side effect를 clean up 할 수 있는 방법을 제공해준다.
useEffect에서 side effect를 clean up 하기 위해서는 <strong>useEffect에 전달한 콜백 함수에서 claen up을 하는 함수를 리턴하면 된다.</strong></p>
<pre><code>useEffect(() =&gt; {
  const button = document.getElementById(&#39;consoleButton&#39;);

  const printConsole = () =&gt; {
    console.log(&#39;button clicked&#39;);
  };

  button.addEventListener(&#39;click&#39;, printConsole);

  // side effect를 clean up 하기 위한 함수를 선언한다.
  const removeEventListener = () =&gt; {
    button.removeEventListener(&#39;click&#39;, printConsole);
  };

  // clean up 함수를 return 한다.
  return removeEventListener;
});</code></pre><p>위의 코드로 보면 side effect를 없애기 위한 함수를 만들고, 그 함수를 리턴해주었다.
useEffect는 clean up 함수를 두 가지 경우에 호출한다.
    1. 다음 side effect를 발생시키기 전
    2. 컴포넌트가 unmount 될 때</p>
]]></description>
        </item>
    </channel>
</rss>