<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>vision_ing.log</title>
        <link>https://velog.io/</link>
        <description>나를 위한 업그레이드 아자아자</description>
        <lastBuildDate>Fri, 29 Dec 2023 16:35:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>vision_ing.log</title>
            <url>https://images.velog.io/images/vision_ing/profile/0c73a3ab-0df8-42bb-a318-509f7c91b164/KakaoTalk_20220313_161019117.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. vision_ing.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/vision_ing" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[elice track ep.22]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.22-cob7olfy</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.22-cob7olfy</guid>
            <pubDate>Fri, 29 Dec 2023 16:35:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h1 id="http-methods">HTTP Methods</h1>
<p>클라이언트가 웹서버에게 사용자 요청의 목적/종류를 알리는 수단</p>
<p>이 Method중 Axios 통신하면서 가장 많이 사용되는 메소드를 정리해보았다.</p>
<ol>
<li>GET
GET : 입력한 url에 존재하는 자원에 요청을 한다.</li>
</ol>
<p>문법
axios.get(url,[,config])
Q) Get이 데이터를 받아오는 것이라고 했는데, 저는 로그인을 구현할때 GET을 사용했는데요?</p>
<p>GET으로 로그인을 구현했을때 웹 사이트 주소창의 형태를 잘 보면 이러한 형태가 나온다.</p>
<p><a href="http://www.server.com/login?id=Hnk&amp;pw=1234">www.server.com/login?id=Hnk&amp;pw=1234</a>  // 실제로 없는 사이트이다, 이해를 돕기 위해서 추가했다. 오해하지 말자.
웹 사이트 뒤에 쿼리스트링이 붙여진 것을 확인할 수 있다.</p>
<p>✅ GET은 서버에서 어떤 데이터를 가져와서 보여준다거나 하는 용도이다.
주소에 있는 쿼리스트링을 활용해서 정보를 전달하는 것이지 GET메서드는 값이나 상태등을 바꿀 수 없다.</p>
<p>예제 코드</p>
<pre><code>//가상으로 보여주는 코드와 response 형태이다. 참고만 하길 바란다.
import axios from &#39;axios&#39;;

axios.get(&#39;https://localgost:3000/sewon/user&#39;)
  .then((Response)=&gt;{console.log(Response.data)})
  .catch((Error)=&gt;{console.log(Error)})
[
  { id: 1, pw: &#39;1234&#39;, name: &#39;sewon&#39; },
  { id: 2, pw: &#39;1234&#39;, name: &#39;hongil&#39; },
  { id: 3, pw: &#39;1234&#39;, name: &#39;daeyeon&#39; }
]</code></pre><p>응답은 json 형태로 넘어온다.</p>
<ol start="2">
<li>POST
POST : 새로운 리소스를 생성(create)할 때 사용한다.</li>
</ol>
<p>문법</p>
<pre><code>axios.post(&quot;url주소&quot;,{
  data객체
    },[,config])</code></pre><p>POST 메서드의 두 번째 인자는 본문으로 보낼 데이터를 설정한 객체 리터럴을 전달한다.</p>
<p>Q) Post는 새로운 리소스를 생성할 때 사용되는데 그러면 언제 POST를 사용하나요?</p>
<p>✅ 로그인, 회원가입 등 사용자가 생성한 파일을 서버에다가 업로드할때 사용한다.
Post를 사용하면 주소창에 쿼리스트링이 남지 않기때문에 GET보다 안전하다.</p>
<p>예제 코드</p>
<pre><code>
axios.post( &#39;url&#39;, 
  { 
   contact: &#39;Sewon&#39;, 
   email: &#39;sewon@gmail.com&#39; 
   }, 
  { 
   headers:{ 
    &#39;Content-type&#39;: &#39;application/json&#39;, 
    &#39;Accept&#39;: &#39;application/json&#39; 
      } 
    } 
) </code></pre><p>  .then((response) =&gt; { console.log(response.data); }) 
  .catch((response) =&gt; { console.log(&#39;Error!) });
3. Delete
REST 기반 API 프로그램에서 데이터베이스에 저장되어 있는 내용을 삭제하는 목적으로 사용한다.</p>
<p>문법
axios.delete(url,[,config]);
✅ Delete메서드는 HTML Form 태그에서 기본적으로 지원하는 HTTP 메서드가 아니다.</p>
<p>Delete메서드는 서버에 있는 데이터베이스의 내용을 삭제하는 것을 주 목적으로 하기에 두 번째 인자를 아예 전달하지 않는다.</p>
<p>예제 코드</p>
<pre><code>
axios.delete(&quot;/thisisExample/list/30&quot;).then(function(response){
    console.log(response);
      }).catch(function(ex){
      throw new Error(ex)
}</code></pre><ol start="4">
<li>PUT
REST 기반 API 프로그램에서 데이터베이스에 저장되어 있는 내용을 갱신하는 목적으로 사용된다.</li>
</ol>
<p>문법
axios.put(url[, data[, config]])
✅ PUT메서드는 HTML Form 태그에서 기본적으로 지원하는 HTTP 메서드가 아니다.</p>
<p>PUT메서드는 서버에 있는 데이터베이스의 내용을 변경하는 것을 주 목적으로 하고 있다.</p>
<p>마지막 회고~
2차 프로젝트가 마무리 되었다.
사실 마무리는 좋지 않았다...
개인적인 생각은 결과가 어떻든 발표는 마무리 하는게 좋다고 생각하지만 팀원들 대부분이 발표를 안하는걸로 의견이 모아져서 나도 따를 수 밖에 없었다.
이 부분은 요즘은 비전공자들이 많은 추세이고, 우리 팀 역시 비전공자들이 대부분이었다. 비전공자 자체가 문제가 아니라, 경험이 있는 사람이 진도가 빠른 편이다. 전공자 혹은 현직자 한명이 이끌고 가는 팀도 분명히 있을 것이다. 3주라는 시간이 길지 않다고 생각을 하는데, 완성이 되어도 되지않아도 포기하지 않고 달려왔다는 증거가 되는게 발표라고 생각했는데, 다른 사람이 많이 부끄럽다면... 그렇게 생각한다면 어쩔 수 없는 거다. 
나는 부끄럽지 않기 때문에.. 완성 못하면 뭐 어때.. 
다른 프로젝트 또 하면 되지.. ㅎ</p>
<p>솔직히 말하자면 나는 적극적인 사람이 아니다. 
답답하면 의견을 제시하지만 따르는걸 좋아하고, 몸을 맡기고 물 흐르듯 흘러가는 걸 좋아하는 사람이다.
그니까 나도 잘한건 없다는 얘기다.</p>
<h3 id="팀에서-적극적인-사람이-많으면-도움이-된다">팀에서 적극적인 사람이 많으면 도움이 된다.</h3>
<p>각자 할 일을 나눌 때, 하고 싶은 것을 맡는 것 보다 일의 우선 순위를 정하고 억지로라도 정하는 것이 좋다.</p>
<p>우리팀은 각자 하고싶은 파트를 맡아 했는데 시간관리에도 실패했고 각자 맡은 파트를 끝까지 붙잡고 있었다.</p>
<p>감을 못잡고 있는 나에게 언니가 mui를 활용해서 대충이라도 css를 만들면서 기능을 만들라고 했는데, 나에겐 도움이 많이 되었다.
내가 잘 모르는 탓에 joy를 써버려서 ㅎ 조금 당황했지만 
그래도 그나마 진도가 빨리 나갔던 것 같다. </p>
<p>로그인 회원가입 구현을 처음 해보았는데 생각보다 여러가지 구현할게 많아서 힘들었다. 형식검사, 중복검사, 형식검사를 못하면 중복검사를 못하게하는 로직 등
겨우 구현을 완료했을 땐 백엔드 쪽에서 오류가 나서 서로 소통을 오랫동안 하면서 고쳐나갔는데 오류 없이 완료되었을 땐 기분이 좋았다.</p>
<p>솔직히 말하자면, 1차 프로젝트 때는 잘하시는 분이 하드캐리해주셔서 괴로운 마음이 컸는데, 이번에는 괴로운 마음은 많이 없었다 ㅎ</p>
<p>그래도 이번 프로젝트로 나는 기획을 할 때 더 재밌고 즐거운 사람인걸 깨달았다.
오히려 사람들과 소통하고, 내 의견이 되지 않아도 이걸 추진해나가는 재미도 있었고 이런걸 재밌어하는구나 라는걸 많이 느꼈다.</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.21]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.21-9x6zyu9e</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.21-9x6zyu9e</guid>
            <pubDate>Fri, 29 Dec 2023 16:13:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h3 id="intro">Intro</h3>
<p>리액트는 효율적인 UI 구현을 위한 라이브러리이다. HTTP Client(HTTP 상에서 커뮤니케이션을 하는 자바 기반 컴포넌트)를 내장하고 있는 Angular와는 다르게, 리액트는 따로 내장 클래스가 존재하지 않는다.</p>
<p>따라서 리액트에서 AJAX를 구현하려면 Javascript 내장객체인 XMLRequest를 사용하거나, 다른 HTTP Client를 사용해야 한다.</p>
<p>그렇다면 어떤 HTTP Client 라이브러리를 사용하는게 좋을까? 리액트와 함께 쓰면 좋은 HTTP Client 라이브러리가 많지만, 여기에선 리액트에서 많이 쓰이는 것 중에 하나인 Fetch API를 비교하며 axios 라이브러리를 알아볼 것이다.</p>
<p>#짚고 넘어가기
AJAX (Asynchronous Javascript And XML)
AJAX란, Javascript의 라이브러리중 하나이며 Asynchronous Javascript And Xml(비동기식 자바스크립트와 xml)의 약자이다. 브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를 새로 고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법 이며,
JavaScript를 사용한 비동기 통신, 클라이언트와 서버간에 XML 데이터를 주고받는 기술이다.
정리하자면, 자바스크립트를 통해서 서버에 데이터를 요청하는 것이다.</p>
<p>비동기 방식이란?
비동기 방식은 웹페이지를 리로드하지 않고 데이터를 불러오는 방식이며,Ajax를 통해서 서버에 요청을 한 후 멈추어 있는 것이 아니라 그 프로그램은 계속 돌아간다는 의미를 내포하고 있다.</p>
<p>비동기 방식의 장점
페이지 리로드의 경우 전체 리소스를 다시 불러와야하는데 이미지, 스크립트 , 기타 코드등을 모두 재요청할 경우 불필요한 리소스 낭비가 발생하게 되지만 비동기식 방식을 이용할 경우 필요한 부분만 불러와 사용할 수 있으므로 매우 큰 장점이 있다.</p>
<h3 id="axios-vs-fetch-api">axios VS Fetch API</h3>
<p>우리는 일반적으로 자바스크립트에서 API를 연동하기 위해서 보통 Fetch API를 사용하곤 했다.
리액트도 자바스크립트 built-in 라이브러리중 하나인 Fetch API라는 훌륭한 API 연동 모듈을 사용한다.
하지만 Fetch API는 자바스크립트의 built-in 라이브러리라는 특성 때문인지 많은 사람들이 리액트에서 axios를 사용하는 것을 선호한다</p>
<pre><code>//fetch
const url =&#39;http://localhost3000/test`
const option ={
   method:&#39;POST&#39;,
   header:{
     &#39;Accept&#39;:&#39;application/json&#39;,
     &#39;Content-Type&#39;:&#39;application/json&#39;;charset=UTP-8&#39;
  },
  body:JSON.stringify({
      name:&#39;sewon&#39;,
        age:20
  })

  fetch(url,options)
      .then(response =&gt; console.log(response))</code></pre><pre><code>//axios
const option ={
  url =&#39;http://localhost3000/test`
   method:&#39;POST&#39;,
   header:{
     &#39;Accept&#39;:&#39;application/json&#39;,
     &#39;Content-Type&#39;:&#39;application/json&#39;;charset=UTP-8&#39;
  },
  data:{
      name:&#39;sewon&#39;,
        age:20
  }

  axios(options)
      .then(response =&gt; console.log(response))</code></pre><p>동일한 기능을 수행하는 코드이며, 간단한 코드이다.</p>
<p>위 코드에서 차이점을 찾아보자.</p>
<p>Fetch()는 body 프로퍼티를 사용하고,axios는 data 프로퍼티를 사용한다.
Fetch의 url이 Fetch()함수의 인자로 들어가고, axios에서는 url이 option객체로 들어간다.
Fetch에서 body부분은 stringify()로 되어진다.
이처럼 axios는 HTTP 통신의 요구사항을 컴팩트한 패키지로써 사용하기 쉽게 설계 되었다.</p>
<p>위와 같은 내용들을 보며, 이제 우리가 왜 axios를 배워야 하는지 알게 되었을거라 생각했고, 이제 진짜 axios에 대해 알아보도록 하자.</p>
<h4 id="axios란">Axios란?</h4>
<p>Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다.
(백엔드와 프론트엔드와 통신을 쉽게하기 위해 AJAX도 더불어 사용하기도 한다.)</p>
<h4 id="axios-특징">axios 특징</h4>
<p>운영 환경에 따라 브라우저의 XMLHttpRequest 객체 또는 Node.js의 HTTP API 사용
Promise(ES6) API 사용
요청과 응답 데이터의 변형
HTTP 요청 취소 및 요청과 응답을 JSON 형태로 자동 변경</p>
<h4 id="axios-사용법">Axios 사용법</h4>
<p>Axios 다운로드
HTTP Methods
Axios 사용해보기
GET
POST
PUT
DELETE</p>
<h4 id="axios-다운로드">Axios 다운로드</h4>
<pre><code>yarn add axios

npm i axios</code></pre><p>//자신이 진행중인 프로젝트 상위에 import 시켜주기
import axios from &#39;axios&#39;</p>
<p>출처 - <a href="https://velog.io/@shin6403/React-axios%EB%9E%80-feat.-Fetch-API">https://velog.io/@shin6403/React-axios%EB%9E%80-feat.-Fetch-API</a> </p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.20]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.20</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.20</guid>
            <pubDate>Wed, 27 Dec 2023 18:15:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>리덕스는 리액트에서 상태를 더 효율적으로 관리하는데 사용하는 상태 관리 라이브러리이다.</p>
<p>예시로 프로젝트가 복잡할 때, handleSomethin은 value를 업데이트하는 함수이다. 이 함수는 컴포넌트 두 개를 거쳐서 왼쪽 A 컴포넌트로 전달한다. 이 함수가 호출되면 맨 위에 있는 app 컴포넌트의 value 값을 바꾸고, 이 value 값을 b 컴포넌트로 전달하여 b 컴포넌트 안에서 렌더링된다.</p>
<p>이런식으로 특정 작업을 하려고 여러 컴포넌트를 거쳐서 props를 전달하는 것은 비효율적이다. 작업을 하면서 헷갈릴 수도 있고, 실제로 컴포넌트 자기 자신은 필요하지 않은데 자식 컴포넌트 때문에 필요한 props 개수가 너무 많아질 수도 있기 때문이다.
추가로 형제 컴포넌트에서 불필요한 렌더링이 일어나기 때문에 이 역시 상황에 따라 방지해 주어야 한다.
또 최상위 컴포넌트인 app에 상태 관리 로직이 너무 많아 컴포넌트의 코드 길이가 너무 길어지는 현상도 발생할 수 있다.
이런 문제점들은 리덕스라는 상태관리 도구를 사용하면 매끄럽게 해결가능하다.</p>
<p>리덕스는 쉽게 설명하면 상태 관리의 로직을 컴포넌트 밖에서 처리하는 것이다. 리덕스를 사용하면 store라는 객체 내부에 상태를 담게 된다. 
리덕스를 사용하면 스토어에서 모든 상태관리가 일어난다. 상태에 어떤 변화를 일으켜야 할 때는 액션이라는 것을 스토어에 전달한다. 액션은 객체 형태로 되어있으며, 상태를 변화 시킬 때 이 객체를 참조하여 변화를 일으킨다. 액션을 전달하는 과정은 디스패치라고 한다.
스토어가 액션을 받으면 리듀서(reducer)가 전달받은 액션을 기반으로 상태를 어떻게 변경시켜야할지 정한다. 액션을 처리하면 새 상태를 스토어에 저장한다.
스토어 안에 있는 상태가 바뀌면 스토어를 구독하고 있는 컼포넌트에 바로 전달한다. 부모컴포넌트로 props를 전달하는 작업은 생략하며, 리덕스에 연결하는 함수를 사용하여 컴포넌트를 스토어에 구독시킨다.</p>
<ul>
<li>스토어 : 애플리케이션의 상태 값들을 내장하고 있다.</li>
<li>액션 : 상태 변화를 일으킬 때 참조하는 객체이다.</li>
<li>디스패치 : 액션을 스토어에 전달하는 것을 의미한다.</li>
<li>리듀서 : 상태를 변화시키는 로직이 있는 함수이다.</li>
<li>구독 : 스토어 값이 필요한 컴포넌트는 스토어를 구독한다.</li>
</ul>
<h3 id="eslint">ESLint</h3>
<p>Lint는 보푸라기라는 뜻인데 프로그래밍 쪽에서는 에러가 있는 코드에 표시를 달아놓는 것을 의미한다. 즉 ESLint는 자바스크립트 문법 중 에러가 있는 곳에 표시를 달아놓는 도구를 의미한다.</p>
<p>코드를 분석해 문법적인 오류나 안티 패턴을 찾아주고 일관된 코드 스타일을 유지(포맷팅)하여 개발자가 쉽게 읽도록 코드를 만들어준다.</p>
<p>###</p>
<h4 id="0-token-왜-필요한가">0. token, 왜 필요한가?</h4>
<p>HTTP는 단기기억상실과 같은 stateless 특성을 가지고 있기 때문에 한 번 로그인을 한다고 그 사실을 계속 기억하지 못한다. 따라서 원래대로라면 로그인을 했더라도 마이페이지 등 로그인이 필요한 사이트에 접속할 때마다 로그인을 진행해야 한다.
이러한 상황을 막기 위한 것이 token이다 !
먼저 로그인을 완료하면 인증 스티커와 같은 token을 전달받고, 마이페이지 등 로그인이 필요한 사이트를 접속할 때마다 서버에 token을 보내며 로그인을 한 유저인지, 권한이 있는지 알려줌으로써 다시 로그인을 할 필요가 없다.</p>
<h4 id="1-jwt란-무엇인가">1. JWT란 무엇인가?</h4>
<p>JWT는 Jason Web Token의 약자이다.
 모바일 앱이나 웹에서 사용자 인증(Authentication)을 수행할 때 사용하는 암호화된 토큰이다.
사용자의 정보 등을 암호화하여 사용자 정보가 필요한 API를 호출할 때, 해당 토큰을 보내주면 백엔드에서 그 토큰을 검증(verity)하는 과정을 거친다. 그 후 response를 해주는 것이다.</p>
<h4 id="2-local-storage--session-storage">2. Local Storage ? Session Storage?</h4>
<p>둘 다 HTML5에 추가된 &#39;저장소&#39;이다. 
로컬 스토리지(Local Storage)에 들어간 데이터는 유저가 지우지 않는 이상 브라우저에 계속 남아있게 된다. 
하지만, 세션 스토리지(Session Storage)에 들어간 데이터는 브라우저 탭을 닫을 경우에 사라지게 된다. 
이를 통해 &#39;로그인을 유지&#39;시키기 위해서는 세션 스토리지가 아닌 로컬 스토리지에 token을 넣어주면 된다는걸 알 수 있다. </p>
<h4 id="3-로그인-과정">3. 로그인 과정</h4>
<ol>
<li>최초 회원가입 시 비밀번호를 DB에 바로 저장하지 않고 Bcrypt를 이용해 암호화를 한 후 비밀번호를 DB에 저장한다. 
  * Bcrypt: 현업에서 많이 사용하고 있는 패스워드 암호화 알고리즘/Bcrypt 모듈을 설치해서 사용가능하다.
 </li>
<li>유저 정보를 저장한 후에 로그인을 할 때 암호화된 비밀번호화 비교하는 검증 과정을 거친 후 일치하게 되면 로그인을 한다.
 </li>
<li>로그인을 할 때 JWT token을 생성하고 token을 localStorage에 저장하여 로그인을 유지시킨다.
 </li>
<li>로그아웃을 할 때엔 localStorage에 있는 토큰을 지운다. </li>
</ol>
<h4 id="4-어떻게-저장하고-서버에-보내는가">4. 어떻게 저장하고, 서버에 보내는가?</h4>
<ol>
<li>로그인 성공시 localStorage에 token 저장
1) 백엔드 측에서 설정한 로그인 성공시 response.MESSAGE와
2) 토큰의 발급 유무에 따라 로그인 성공 여부를 알 수 있다.
 
token이 true이면(있으면) localStorage에 login-token이라는 키 값으로 token을 저장한다.
(localStorage에 저장할 경우 해당 도메인에 영구저장된다.)</li>
<li>인가(Authorization)가 필요한 사이트에서 token 전달
이제 마이페이지, 장바구니 등 인가 과정이 필요한 사이트에서 데이터를 요청할 때, 
아래의 방법으로 localStorage에 저장해두었던 token을 꺼내 함께 전달하면 된다.
fetch 함수의 두 번째 인자는 조건 부분이므로, 이 부분을 headers에 아래 부분을 작성한다.
 </li>
</ol>
<ul>
<li>&#39;Content-Type&#39;: &#39;application/json&#39;: 데이터를 json 형태로 전송</li>
<li>Authorization: localStorage.getItem(&#39;login-token&#39;): localStorage에 login-token key로 저장한 값을 HTTP Authorization 요청 헤더로 전달</li>
</ul>
<p>출처: <a href="https://bo5mi.tistory.com/188">https://bo5mi.tistory.com/188</a> [대범하게:티스토리]</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.19]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.19</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.19</guid>
            <pubDate>Tue, 12 Dec 2023 15:01:35 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>2차 프로젝트가 시작되었다.
1차 프로젝트에서는 프론트엔드를 맡고 싶어하시는 분들이 많으셔서
똑같이 2차 프로젝트에도 그런 일이 일어나 백엔드 포지션을 맡게 되면 어쩌지 하는 걱정이 많았는데
다행히도 이번에는 백엔드 포지션을 맡고 싶어하는 분이 두분이나 계셨고,
두 포지션 다 상관 없다는 분이 한분 계셔서 
코치님 추천으로 총 3:3 으로 백엔드, 프론트엔드 포지션을 나누게 되었다.</p>
<p>1차 프로젝트에서는 이끌어가시는 분이 계셔서 
팀이 운영하는 배에 이것저것 짐을 껴안아 탑승했다면,</p>
<p>이번엔 팀장 한명만을 정하지 않고 모두가 팀장 역할을 하기로 해서
이번엔 배에 노를 가지고 탑승을 하게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/vision_ing/post/88b23431-0434-48e4-a6c0-9ca1a196b3a4/image.png" alt=""></p>
<p>이번에는 피그마도 쓰게 되었다.
사실 피그마 처음 써봄..
피그마 예쁘게 쓰는 분들 많던데 도대췌 어떻게 쓰는겅ㅇ임????
암턴
이젠 기획 쪽에 부쩍 관심이 생겼는데 
화면 구현에 많은 일을 하게 되어 기쁘다.</p>
<p>그리고 아무리 살펴봐도 없었던 하자가 내일 발견하고, 또 내일 발견하게 되는건 참..
참 힘든것 같다..</p>
<p>원래는 쉽게 웹으로 생각을 했는데, 코치님께서 모바일쪽 화면을 생각하라 하셔서
사실 갈아엎고 다시 만든 화면들이다. </p>
<p>백엔드 코치님과 프론트엔드 코치님께서 공통적으로 하시는 말씀이
백엔드 일이 적고 프론트엔드 일이 많을것이었다.
그래서 백엔드분들에게도 일이 될만한 기획이 없을까 생각중인데 아무래도 혼자 생각하기는 어려운것 같다.</p>
<p>디자인이 참 어려운 것 같다. 음.
사실 단순하게 디자인해서 깔끔해보일뿐. 색깔을 입히고 디자인을 하게 되야
좀 있어보이는 홈페이지가 나올텐데, 쓰기 쉬운 직관적인 것을 생각하면서 동시에 요구해야 되니까 어려운 것 같다.</p>
<p>구현이 목적으로 잡고 쉬운 것부터 할까요? -&gt; 너무너무 좋아요 !
였는데 사실 기간이 긴건 아니지만
그래도 사용자 입장에서 다시 생각하게 되었다.
이 홈페이지의 목적은 무엇인가?
홈페이지에 들어온 사용자는 편하게 사용하고 원하는 목적을 이룰 수 있는가?</p>
<p>흔하지 않은 아이디어를 생각하다보니 그쪽에만 너무 치우친것 같아서 아쉽기도 하다.
좀 더 사용자 입장과 흥미, 목적 등 여러가지를 생각해야겠다.</p>
<p>다음 시간에는 깃 브랜치 방법도 다시 복습해야겠다.</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.18 (13-3)]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.17-13-3</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.17-13-3</guid>
            <pubDate>Tue, 12 Dec 2023 14:44:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>Styled Components
Styled Components에 대해 이해하기 위해서는 CSS in JS 개념에 대해 알아야 한다. 이는 말 그대로 CSS를 JS 파일 안에 작성하는 것이다. 대두되면서 탄생한 라이브러리이다. HTML+JS+CSS를 묶어서 하나의 JS파일에 넣은 뒤 컴포넌트 단위로 개발할 수 있게 만들어준다.</p>
<p>styled-components는 이러한 라이브러리 중 가장 인기있다.
설치하기</p>
<pre><code># with npm
$ npm install --save styled-components

# 버전이 안 맞아서 에러가 날 경우 가장 최신 버전으로 설치
$ npm install styled-components@latest

# with yarn
$ yarn add styled-components</code></pre><p>Styled Components는 pakage.json에 다음 코드를 추가하도록 권장한다.</p>
<p>여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여준다.</p>
<pre><code>
{
  &quot;resolutions&quot;: {
    &quot;styled-components&quot;: &quot;^5&quot;
  }
}</code></pre><p>그리고 Styled Components를 사용할 파일에 아래와 같이 import하면 준비는 끝난다.</p>
<pre><code>import styled from &quot;styled-components&quot;</code></pre><ol>
<li>컴포넌트 만들기<pre><code>import styled from &quot;styled-components&quot;;
</code></pre></li>
</ol>
<p>//Styled Components로 컴포넌트를 만든다.
const BlueButton = styled.button<code>background-color: blue;
  color: white;</code>;</p>
<p>export default function App() {
  // React 컴포넌트를 사용하듯이 사용하면 된다.
  return <BlueButton>Blue Button</BlueButton>;
}</p>
<pre><code>

Styled Component 또한 컴포넌트이기 때문에 첫글자를 무조건 대문자로 시작해야 한다



템블릿 리터럴(백틱)안에 작성을 하느라 문자열처럼 표시 돼 자동완성도 안 되고 구분이 힘들 수 있는데,  vscode-styled-components 익스텐션을 설치하면 편리해진다

2. 컴포넌트를 재활용해서 새로운 컴포넌트 만들기</code></pre><p>//만들어진 컴포넌트를 재활용한다.
const BigBlueButton = styled(BlueButton)<code>padding: 10px;
  margin-top: 10px;</code>;</p>
<p>//재활용한 컴포넌트를 재활용할 수도 있다.
const BigRedButton = styled(BigBlueButton)<code>background-color: red;</code>;</p>
<p>export default function App() {
  return (
    &lt;&gt;
      <BlueButton>Blue Button</BlueButton>
      <br />
      <BigBlueButton>Big Blue Button</BigBlueButton>
      <br />
      <BigRedButton>Big Red Button</BigRedButton>
    &lt;/&gt;
  );
}</p>
<pre><code>
이렇게 사용하면 코드 중복을 줄여준다.
3. Props 사용하기
Styled Component로 만든 컴포넌트 또한 React Component처럼 props를 내려줄 수 있다.



내려준 props 값에 따라서 컴포넌트를 조건부 렌더링하는 식으로 사용한다.
이렇게 props를 줄 수도, 안 줄 수도 있다.

</code></pre><p>const Button1 = styled.button<code>background: ${(props) =&gt; (props.skyblue ? &quot;skyblue&quot; : &quot;white&quot;)};</code>;</p>
<p>export default function App() {
  return (
    &lt;&gt;
      <Button1>Button1</Button1>
      <Button1 skyblue>Button1</Button1>
    &lt;/&gt;
  );
}</p>
<pre><code>
혹은 이렇게 활용하는 방법도 있다.


</code></pre><p>const Button = styled.button<code>background: ${(props)=&gt; props.color ? props.color : &quot;white&quot;}
    /* background: ${(props) =&gt; props.color || &quot;white&quot;}; */</code>;</p>
<p><Button color="orange">Button1</Button>
<Button color="tomato">Button2</Button></p>
<pre><code>4. 전역 스타일 설정하기
UI를 구현하기 전, margin:0, padding:0 같은 전역 스타일을 세팅하곤 한다. styled-components에서도 이러한 전역 스타일을 지원한다.



우선 전역 스타일 설정을 위한 createGlobalStyle 함수를 불러온다.
</code></pre><p>import { createGlobalStyle } from &quot;styled-components&quot;;</p>
<pre><code>

그리고 css파일에서 작성하는 것처럼 설정하고 시싶은 스타일을 작성한다.
</code></pre><p>const GlobalStyle = createGlobalStyle<code>button {
        padding : 0;
        margin : 0;
    }</code></p>
<pre><code>

이렇게 만든 &lt;GlobalStyle&gt; 컴포넌트를 최상위에 사용해주면 전역에 Global 컴포넌트의 스타일이 적용된다.
</code></pre><p>function App() {
    return (
        &lt;&gt;
            <GlobalStyle />
            <Button>전역 스타일 적용하기</Button>
        &lt;/&gt;
    );
}</p>
<pre><code>
  5. 조건부 CSS 보여주기
조건에 따라 CSS를 다르게 보여주고 싶다면 styled-components 라이브러리에서 css 를 사용하면 된다.

</code></pre><p>import { css, styled } from &#39;styled-components&#39;;</p>
<p>const Button = styled.button<code>width: 50px;
    background-color: white;
    ${(props) =&gt;
        props.isClicked ?
        css</code>
            background-color: purple;
        <code>;
    }</code>;</p>
<pre><code>

위 코드는 인자로 받은 props에 따른 background-color 조건부 렌더링을 구현한 모습이다.







6. 자주 사용하는 css 따로 관리하기
아까와 같이 css 를 사용하면 된다. 아래와 같이 자주 사용하는 CSS를 변수로 관리하면 코드 중복을 줄이는 데 용이하다.
</code></pre><p>cosnt FlexCenter = css<code>display: flex;
    justify-content: center;
    align-items: center</code>;</p>
<p>const Flexbox = div<code>${FlexCenter}</code>;</p>
<p>// 이렇게 인자를 주고 작성하면 가독성이 더 좋다
const RingVariant = (radius, stroke = &quot;10&quot;) =&gt; css<code>height: ${radius * 2}px;
    width: ${radius * 2}px;
    border: ${stroke}px solid black;</code>;</p>
<pre><code>




7. CSS 셀렉터 사용하기
styled-component 에서 셀렉터 사용은 다음과 같다. &amp; 는 현재 요소를 뜻한다.</code></pre><p>// 컴포넌트 위에 마우스가 올라갈때
  &amp;:hover {
    color: red;
  }</p>
<p>  // 바로 옆은 아니지만 형제요소일 때
  &amp; ~ &amp; {
    background: tomato;
  }</p>
<p>  // 현재 요소 바로 옆에 현재 요소가 붙어있을 때
  &amp; + &amp; {
    background: lime;
  }</p>
<p>  // 현재 요소가 something이라는 클래스를 갖고있을 때
  &amp;.something {
    background: orange;
  }</p>
<p>  // something-else라는 클래스를 가진 부모안에 있을 때
  .something-else &amp; {
    border: 1px solid;
  }</p>
<p>```</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.17 (13-2)]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.17-13-2</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.17-13-2</guid>
            <pubDate>Mon, 11 Dec 2023 14:58:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>CSS Module</p>
<ul>
<li>class, id 등에 random string을 달아주기 때문에 선택자가 겹칠 우려가 없음</li>
<li>스타일 충돌을 방지하고 코드를 격리하여 체계적으로 css 설계가 가능</li>
<li>스타일링 직접 하나하나 해야 함</li>
</ul>
<p>UI framework (ex. Ant Design, Material UI)</p>
<ul>
<li>이미 다 만들어져 있어서 간편하고 쉽게 쓰기에 좋음</li>
<li>이미 다 만들어져 있어서 styling의 학습 및 훈련이 필요한 초심자들에게는 비추천</li>
<li>해당 framework의 디자인 철학을 벗어나기 쉽지 않음</li>
<li>컴포넌트들을 커스터마이징 하기 어려움</li>
</ul>
<p>CSS framework (ex. W3CSS, TailwindCSS)</p>
<ul>
<li>거대한 CSS 파일 하나를 가져오는 것임</li>
<li>개발자가 따로 CSS 파일을 작성하지 않아도 html에 클래스만 적어주면 정해진 규칙대로 스타일링이 적용됨</li>
<li>css에 대한 이해력이 있어도 해당 framework를 사용하기 위한 학습을 또다시 해야 함</li>
<li>이미 다 만들어져 있어서 styling의 학습 및 훈련이 필요한 초심자들에게는 비추천</li>
</ul>
<p>CSS-in-JS library (ex. styled component, emotion)</p>
<ul>
<li>따로 css 파일 만들 것 없이 jsx 파일 안에서 스타일링까지 해결 가능함</li>
<li>컴포넌트 재사용성이 쉬워짐</li>
<li>js 값들을 props로 넘겨줘서 해당 js 값에 의도된 styling을 바로 적용 할 수 있음</li>
<li>class이름에 random string이 생성되기 때문에 선택자 이름이 겹칠 우려가 없음</li>
<li>스타일링을 직접 개발자가 하나하나 해야함</li>
</ul>
<h3 id="javascript-template-literal">JavaScript template literal</h3>
<p>템플릿 리터럴은 내장된 표현식을 허용하는 문자열 리터럴입니다.</p>
<pre><code>`string text ${expressiion} string text`</code></pre><p>쉽게 말해 문자열 안에서 js 표현식을 사용할 수 있게 하는 문법이다.</p>
<h3 id="css와-scss-비교">CSS와 SCSS 비교</h3>
<p>SCSS에서는 선택자 중복 회피 가능
이외에도 SCSS variable 등 여러 추가 기능 가능</p>
<h3 id="styled-components">Styled Components</h3>
<p>패키지 설치
Styled Components는 styled-components라는 NPM 패키지명을 가지고 있습니다. 따라서 React 프로젝트에 다음과 같이 npm 커맨드로 간단히 설치할 수 있습니다.</p>
<pre><code>$ npm i styled-components</code></pre><p>설치 후에 package.json에 styled-components가 추가된 것을 확인할 수 있습니다.</p>
<pre><code>  &quot;dependencies&quot;: {
    &quot;react&quot;: &quot;18.0.0&quot;,
    &quot;react-dom&quot;: &quot;18.0.0&quot;,
    &quot;styled-components&quot;: &quot;5.3.5&quot;
  },</code></pre><p>기본 문법
먼저 위에서 설치한 styled-components 패키지에서 styled 함수를 임포트합니다. styled는 Styled Components의 근간이 되는 가장 중요한 녀석인데요. HTML 엘리먼트나 React 컴포넌트에 원하는 스타일을 적용하기 위해서 사용됩니다.</p>
<p>기본 문법은 HTML 엘리먼트나 React 컴포넌트 중 어떤 것을 스타일링 하느냐에 따라 살짝 다릅니다.</p>
<p>HTML 엘리먼트를 스타일링 할 때는 모든 알려진 HTML 태그에 대해서 이미 속성이 정의되어 있기 때문에 해당 태그명의 속성에 접근합니다.</p>
<pre><code>import styled from &quot;styled-components&quot;;

styled.button`
  // &lt;button&gt; HTML 엘리먼트에 대한 스타일 정의
`;</code></pre><p>React 컴포넌트를 스타일링 할 때는 해당 컴포넌트를 임포트 후 인자로 해당 컴포넌트를 넘기면 됩니다.</p>
<pre><code>import styled from &quot;styled-components&quot;;
import Button from &quot;./Button&quot;;

styled(Button)`
  // &lt;Button&gt; React 컴포넌트에 스타일 정의
`;</code></pre><p>두가지 문법 모두 ES6의 Tagged Template Literals을 사용해서 스타일을 정의합니다. 그리고 styled 함수는 결국 해당 스타일이 적용된 HTML 엘리먼트나 React 컴포넌트를 리턴합니다.</p>
<p>예를 들어, 다음과 같이 Styled Components로 작성된 JavaScript 코드는</p>
<pre><code>import styled from &quot;styled-components&quot;;

styled.button`
  font-size: 1rem;
`;</code></pre><p>아래 CSS 코드가 적용된 <button> HTML 엘리먼트를 만들어낸다고 생각하면 쉽습니다.</p>
<pre><code>button {
  font-size: 1rem;
}</code></pre><p>이런 식으로 Styled Components를 이용해서 JavaScript 코드 안에 삽입된 CSS 코드는 글로벌 네임 스페이스를 사용하지 않습니다. 다시 말해, 각 JavaScript 파일마다 고유한 CSS 네임 스페이스를 부여해주기 때문에, 각 React 컴포넌트에 완전히 격리된 스타일을 적용할 수 있게 됩니다</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.16 (13-1)]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.16-13-1</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.16-13-1</guid>
            <pubDate>Wed, 06 Dec 2023 21:30:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>Server Side Rendering</p>
<ul>
<li>React, Vue, Angular 등 자바스크립트 프레임워크가 나오기 이전 
초기 웹 환경에서는 모든 페이지를 서버에서 빌드</li>
<li>클라이언트는 별도의 처리 없이 웹페이지 노출</li>
<li>이를 server Rendering이라고 함</li>
</ul>
<p>Client Side Rendering</p>
<ul>
<li>Ajax 등의 기술, 자바스크립트 프레임워크를 활용하여, 데이터를 받아 자바스크립트로 페이지를 동적으로 만들 수 있게 됨</li>
<li>데이터는 XML, JSON 형태로 클라이언트에 전송</li>
<li>이를 CSR(Client Side Rendering)이라고 함</li>
</ul>
<p>CSR의 장점</p>
<ul>
<li>csr은 자바스크립트만으로 완전히 페이지를 만들 수 있음</li>
<li>자바스크립트를 최대한도로 활용하여 html, css를 동적으로 생성</li>
<li>컴포넌트 단위로 코드를 나누고, 다양한 디자인 패턴을 적용하는 등,
클라이언트 개발의 수준을 한단계 끌어올림</li>
<li>Full page load 없이 라우팅</li>
</ul>
<p>CSR의 단점</p>
<ul>
<li>자바스크립트 코드가 많으면 앱 로딩이 느려짐</li>
<li>SEO가 좋지 않음</li>
</ul>
<p>Server side Rendering</p>
<ul>
<li>서버에서 자바스크립트를 이용해 페이지를 미리 빌드</li>
<li>컴포넌트 생성에 필요한 api 요청, routing, redux store 생성 등을 처리</li>
<li>클라이언트는 빌드된 페이지와 자바스크립트를 받아,
웹앱을 CSR처럼 동작하게 함</li>
<li>이런 특징으로, universal rendering이라고도 함</li>
</ul>
<p>웹 퍼포먼스</p>
<ul>
<li>웹페이지가 로드되고 유저와 상호작용하는 모든 것들을 측정</li>
<li>성능을 측정하여 웹앱의 사용성을 개선할 수 있음</li>
<li>열악한 네트워크 환경에서도 사용 가능한 앱을 만드는 등
좋은 유저 경험으로 유저의 만족을 얻음</li>
</ul>
<p>Time to First Byte</p>
<ul>
<li>페이지 요청 후, 처음 데이터가 도착하기까지 걸리는 시간</li>
<li>요청을  받았을 때, 서버에서 처리하는 시간이 오래 걸리거나, 
네트워크가 딜레이되는 등의 상황 발생 시 지표가 악화됨</li>
</ul>
<p>First Contentful Paint</p>
<ul>
<li>페이지에 진입하고부터, 브라우저가 어떤 DOM Content를 만들때까지 걸리는 시간</li>
<li>페이지 진입 후 FCP까지 평균 3초 이상 걸리면 성능 개선이 필요</li>
</ul>
<p>Time to interactive</p>
<ul>
<li>웹페이지 진입 후, 유저가 클릭, 스크릭, 인풋 등의 행위를 하기까지 걸리는 시간</li>
<li>자바스크립트가 로드되고 나서, 이벤트 핸들러 등이 부착되어
입력을 처리할 수 있기까지의 시간</li>
</ul>
<p>SSR의 페이지 로드 방식</p>
<ul>
<li>유저가 빠르게 페이지의 내용을 볼 수 있도록 html을 미리 빌드하여 FCP 등의 키 메트릭을 개선함</li>
<li>서버 자원을 활용하여, 초기 큰 성능이 필요한 페이지 등을 빌드하는데 활용</li>
</ul>
<p>SSR의 장점</p>
<ul>
<li>Crawler는 페이지를 Indexing 하기 위해 페이지에 관한 많은 정보가 필요</li>
<li>SSR을 활용하여 미리 페이지를 빌드하면, Crawler에게 많은 정보를 줄 수 있음</li>
<li>SEO(Search Engine Optimization)에 유리</li>
</ul>
<p>SSR의 단점</p>
<ul>
<li>CSRDP QLGO TTFB에 불리함 </li>
<li>별도의 서버를 유지하는 비용</li>
<li>Static rendering보다 CDN Caching에 불리</li>
</ul>
<p>ReactDOMServer</p>
<ul>
<li>ReactDOMServer를 활용하여, 특정 React COmponent를 html로 빌드</li>
<li>Node.js 서버에서 JSX를 사용하여 페이지 빌드</li>
</ul>
<p>renderToString</p>
<ul>
<li>React Component를 html로 변환함</li>
<li>클라이언트의 페이지 요청 시, 변환된 html string을 전달</li>
<li>renderToNodeStream은 readable stream을 생성
브라우저가 받아서 점진적으로 페이지를 그림</li>
</ul>
<p>ReactDOM.hydrate</p>
<ul>
<li>renderToString으로 생성한 HTML의 root을 기준으로
받아온 React code를 통해 markup에 이벤트 핸들러를 등록하는 등
컴포넌트화.</li>
</ul>
<p>Hydration 시 주의할 점</p>
<ul>
<li>서버에서 생성한 컴포넌트와 브라우저에서 hydration을 거친 후의 마크업이 다르면, react runtime은 경고를 보냄
ex) 현재 시간을 보여주는 컴포넌트</li>
<li>경고 발생 시, 어느 부분에서 차이점이 생기는지 반드시 파악해야 함<br></li>
<li>componentDidMount 역할을 하는 useEffect의 경우, SSR 시 서버에서 동작하지 않음</li>
<li>data loading 등의 처리를 별도로 해주어야 할 필요가 있음<br>
<br>

</li>
</ul>
<p>React 앱 배포 Overview</p>
<ul>
<li>인터넷에서 내가 만든 앱에 접근할 수 있어야 함</li>
<li>지속적으로 앱을 수정하고 배포해야 함</li>
<li>Public IP 주소로 직접 접근할 수 있도록 함</li>
<li>IP를 부여 받은 서버에 react 앱을 배포</li>
<li>앱을 서빙하는 웹서버를 통해 사용자에게 앱을 전달</li>
<li>사용자는 IP를 통해 앱에 접근</li>
</ul>
<p>react 앱 배포 프로세스 </p>
<ul>
<li>IP를 부여받은 서버(VM)에 React 앱을 배포</li>
<li>앱을 빌드하고, 웹 서버를 세팅</li>
<li>앱을 서빙하는 웹서버를 통해 사용자에게 앱을 전달</li>
<li>사용자는 필요한 데이터를 받아 앱을 로딩</li>
</ul>
<p>프론트엔드 앱 배포시 유의할 점</p>
<ul>
<li>서버와 통신 시, CORS가 허용되었는지 점검</li>
<li>브라우저, 디바이스별로 앱이 정상적으로 동작하는지 점검</li>
<li>앱의 로딩 속도, 각 동작 시 성능, 버그 등을 점검</li>
</ul>
<p>react 앱 준비</p>
<ul>
<li>yarn.lock, package-lock.json이 동시에 존재하지 않는지 점검</li>
<li>로컬에서 npm run build를 실행하여, 빌드 시 에러가 발생하지 않는지 점검</li>
<li>로컬에서 배포하여, production build가 제대로 실행되는지 점검</li>
</ul>
<p>github 연동</p>
<pre><code>git remote add origin https://gitlab.com/{gitlab_id}/{project_name}
git push --set-upstream origin master</code></pre><ul>
<li>작성한 프로젝트 코드를 gitlab에 배포</li>
<li>프로젝트가 gitlab에 잘 올라갔는지 점검</li>
<li>last commit까지 적용되었는지 점검</li>
</ul>
<p>Azure를 사용한 VM 배포</p>
<ul>
<li>Azure 계정을 만듦</li>
<li>portal.azure.com에 접속</li>
<li>Virtual Machine을 검색해, Virtual machine 리소스 페이지에 접속</li>
<li>Create &gt; Virtual machine 버튼을 클릭</li>
</ul>
<p>VM 설정</p>
<ul>
<li>Resource group은 필요하다면 새로 만들어 설정</li>
<li>Virtual machine name을 설정</li>
<li>Ubuntu Server 20.04 LTS 로 생성</li>
<li>그 외 세팅은 default로 유지</li>
<li>SSH public key로 설정</li>
<li>key pair는 다운받음</li>
<li>유저 이름은 azureuser로 유지</li>
<li>포트 접근은 모두 허용함</li>
</ul>
<p>Azure를 사용한 VM 배포</p>
<ul>
<li>Review &amp; Create 버튼을 눌러, 마지막으로 점검한 뒤에 생성</li>
</ul>
<p>접근 테스트</p>
<ul>
<li>다운받은 private key를 .ssh 밑으로 옮김</li>
<li>ssh 커맨드로 VM 서버에 접근<pre><code>&gt; mv {private_key} ~/.ssh
&gt; ssh -i ./{private_key} azureuser@{id_address}
# 나갈때는 exit</code></pre></li>
<li>다운 받은 private key를 .ssh 밑으로 옮긴다.</li>
<li>ssh 커맨드로 VM 서버에 접근한다.</li>
</ul>
<p>React 앱 배포를 위한 Azure VM 세팅</p>
<ul>
<li>VM 에서 nodejs, npm을 설치</li>
<li>앱을 빌드하는데 필요한 npm package를 설치</li>
<li>serve를 이용해 앱을 배포</li>
</ul>
<p>Node.js, NPM 설치</p>
<pre><code>&gt; sudo apt update
&gt; sudo apt instatll nodejs
&gt; sudo apt instatll npm</code></pre><ul>
<li>NPM, Node.js를 설치</li>
</ul>
<p>프로젝트 패키지 설치 </p>
<pre><code>&gt; git clone https://gitlab.com/{gitlab_id}/{project_name}
&gt; cd {project_name}
&gt; npm i</code></pre><ul>
<li>프로젝트 코드를 git clone으로 다운</li>
<li>npm i로, 빌드에 필요한 패키지를 설치</li>
</ul>
<p>빌드 후 배포</p>
<pre><code>&gt; sudo npm i -g serve
&gt; npm run build
&gt; sudo -s -p 80 build</code></pre><ul>
<li>프로젝트를 빌드</li>
<li>serve 웹서버를 사용해 프로젝트를 80번 포트에서 서빙</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.15]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.15</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.15</guid>
            <pubDate>Tue, 05 Dec 2023 20:43:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h3 id="react-테스팅">react 테스팅</h3>
<h4 id="코드테스트가-필요한-경우">코드테스트가 필요한 경우</h4>
<ul>
<li>코드를 작성하고 나면, 원하는 대로 동작하는지 알기 위해 테스트를 함</li>
<li>코드에 버그가 있으면, 어떤 상황에서 버그가 발생하는지를 알기 위해 테스트를 함</li>
<li>코드를 리팩토링하면, 원래대로 동작하는지 테스트함<br></li>
<li>리액트 앱의 컴포넌트가 늘어날수록, 컴포넌트끼리 서로 영향을 미치는 경우가 많아짐</li>
<li>특정 코드가 수정되면, 어떤 컴포넌트에 에러가 발생할 수 있음</li>
</ul>
<h4 id="테스팅-코드-작성의-이점">테스팅 코드 작성의 이점</h4>
<ul>
<li>언급한 상황들에 대한 테스팅 코드를 작성하여, 미연의 에러를 방지</li>
<li>TDD(Test Driven Development) 등의 방법론을 적용하여 생산성을 향상</li>
<li>테스트가 늘어나면서 테스트 코드가 구현 코드에 대한 문서화가 됨</li>
<li>테스트가 용이하게 코드를 작성하여, 코드 품질과 신뢰성을 높임</li>
</ul>
<h4 id="테스터블한-코드-작성하기">테스터블한 코드 작성하기</h4>
<ul>
<li>코드가 영향을 미치는 범위를 최대한 줄인다. 사이드 이펙트를 줄임</li>
<li>하나의 함수가 너무 많은 일을 하지 않게 함</li>
<li>기능들을 작게 분리함</li>
</ul>
<h4 id="주요-테스팅-용어">주요 테스팅 용어</h4>
<ul>
<li>Mocking - 특정 동작을 흉내내는 것
ex) 실제 API를 호출하는게 아니라, 가짜 payload를 반환하는 mocking function을 만듦</li>
<li>Stubbing - 더미를 채워 넣는 것
ex) Child 컴포넌트를 렌더링하지 않고, 대신 그 자리에 div등을 채워 넣음</li>
</ul>
<h4 id="테스팅의-구성">테스팅의 구성</h4>
<ul>
<li>setup - 테스트하기 위한 환경을 만든다. mock data, mock function 등을 준비함</li>
<li>expectation - 원하는 테스트 결과를 만들기 위한 코드를 작성함</li>
<li>assertion - 정말 원하는 결과가 나왔는지를 검증함</li>
</ul>
<h4 id="react-화이트-박스-테스팅-블랙박스-테스팅">React 화이트 박스 테스팅, 블랙박스 테스팅</h4>
<ul>
<li>화이트박스 테스팅은 컴포넌트 내부 구조를 미리 안다고 가정하고 테스트 코드를 작성</li>
<li>블랙박스 테스팅은 컴포넌트 내부 구조를 모른 채 어떻게 동작하는지에 대한 테스트 코드를 작성</li>
</ul>
<h4 id="테스팅의-범위에-따른-분류">테스팅의 범위에 따른 분류</h4>
<ul>
<li>Unit 테스팅</li>
<li>Intergration 테스팅</li>
<li>end-to-end(e2e) 테스팅</li>
</ul>
<h4 id="unit-테스팅">Unit 테스팅</h4>
<ul>
<li>다른 부분과 분리된 작은 코드를 만들고 그것을 테스트함</li>
<li>작은 코드는 function, module, class 등을 의미</li>
<li>각 부분이 원하는 대로 동작함을 보장하기 위함</li>
<li>테스트는 서로 분리되어야 함</li>
<li>ex) 특정 컴포넌트가 데이터에 따라 잘 렌더링되는지를 테스트하는 경우</li>
</ul>
<p>Intergration 테스팅</p>
<ul>
<li>앱의 특정 부분이 동작하는지 테스트함</li>
<li>ex) 여러 컴포넌트가 한꺼번에 동작하거나, 어떤 페이지의 부분이 잘 동작하는지를 테스트하는 경우</li>
<li>ex) react-router, redux 등이 특정 컴포넌트와 함께 잘 동작하는지를 테스트하는 경우</li>
</ul>
<p>end-to-end(e2e) 테스팅</p>
<ul>
<li>유저가 어떤 시나리오를 가지고 그 시나리오의 end-to-end로 잘 동작하는지 테스트함</li>
<li>필요한 경우 웹서버, 데이터베이스를 실행함</li>
<li>범위가 너무 넓어서 에러가 발생했을 때 특정 기능이 안된다는 것은 알 수 있지만, 정확히 어떤 부분에 문제가 생겼는지는 알기 힘듦</li>
<li>ex) 유저가 회원가입 후, 로그인하여 유저 정보 페이지를 볼 수 있는지 테스트하는 경우</li>
</ul>
<h3 id="jest">Jest</h3>
<ul>
<li>facebook에서 오픈소스화한 테스팅 프레임워크</li>
<li>assertion 함수들, test runner, mock 라이브러리 등을 모두 제공</li>
<li>create-react-app에서 기본적으로 사용됨</li>
<li>사용성이 좋고, 가장 인기 있는 프로젝트</li>
</ul>
<h4 id="jest의-핵심-기능들">jest의 핵심 기능들</h4>
<ul>
<li>assertion matchers</li>
<li>async assertion</li>
<li>mock functions</li>
<li>testing lifecycle functions</li>
<li>grouping</li>
<li>snapshot testing</li>
</ul>
<h4 id="assertion-matchers">Assertion matchers</h4>
<ul>
<li>jest는 풍부한 matcher를 제공하여, 여러 상황에서 match를 체크함</li>
<li>expect()는 expectation object를 리턴한다. 이 object의 메서드를 이용해 여러 매칭 상황을 assert함</li>
</ul>
<p>Async Assertion</p>
<ul>
<li>비동기 상황의 테스트를 처리할 수 있는 여러 방법을 제공함</li>
<li>callback, promise, async/await를 모두 활용할 수 있음</li>
</ul>
<p>Mock functions</p>
<ul>
<li>mock function을 만듦</li>
<li>모듈 전체를 mocking 함</li>
<li>라이브러리 전체를 mocking 함</li>
</ul>
<p>Lifecycle functions</p>
<ul>
<li>각 테스트의 시작과 끝, 전체 테스트의 시작과 끝에 원하는 작업을 할 수 있음</li>
<li>beforeEach, afterEach, beforeAll, afterAll 함수를 활용함 </li>
<li>descrebe 블록 안에 사용하면 별도의 scope를 가짐</li>
</ul>
<p>Grouping</p>
<ul>
<li>describe 함수를 이용해 여러 test() 함수를 논리적으로 나눔</li>
<li>describe 함수 안에 describe 함수가 중첩될 수 있음</li>
</ul>
<p>Snapshot Testing</p>
<ul>
<li>특정 함수, 모듈, 컴포넌트 등의 결과를 serializable한 형태의 snapshot으로 저장학고, 추후 변경이 ㅂ라생했을 때 이전의 snapshot과 새로운 snapshot을 비교하여 변경이 발생했는지를 추측함</li>
<li>jest의 주요 기능으로, 코드의 변경이 컴포넌트의 렌더링 결과에 영향을 미치는지를 파악하기에 적합함</li>
</ul>
<p>jest 함수의 실행 순서</p>
<ul>
<li>beforeAll, beforeEach, afterEach, afterAll의 순서로 Lifecycle 함수들이 실행됨</li>
<li>다만, describe 블록 안에 있는 before-<em>, after-</em> 함수는 해당 블록의 범위 안에서 실행됨</li>
<li>describe 함수는 모든 test() 함수 이전에 실행된다. 따라서 test() 함수들을 순차적으로 한꺼번에 실행됨</li>
</ul>
<p>Assertion Matchers 활용</p>
<ul>
<li>toBe()</li>
<li>toEqual()</li>
<li>toContain()</li>
<li>toMatch()</li>
<li>toThrow()</li>
</ul>
<p>Mockfunctions</p>
<ul>
<li>jest.fn()을 활용하여, mock function 객체를 만듦</li>
<li>mockReturnValueOnce() 등으로 리턴하는 값을 임의로 조작한다.
여러번 호출하면, 순서대로 세팅된 값을 반환함</li>
<li>mockResolvedValue()로 promise가 resolve하는 값을 조작함</li>
<li>jest.mock()으로 특정 모듈을 mocking함.</li>
</ul>
<p>Mock functions - assertion</p>
<ul>
<li>toHaveBeenCalled - 이 함수가 호출되었는지 검증 </li>
<li>toHaveBeenCalledWith(arg1, arg2, ...) - 이 함수가 특정 인자와 함께 호출되었는지 검증</li>
<li>toHaveBeenLastCalledWith(arg1, arg2, ...) - 마지막으로 특정 인자와 함께 호출되었는지 검증</li>
</ul>
<p>Lifecycle functions</p>
<ul>
<li>beforeEach</li>
<li>afterEach</li>
<li>beforeAll</li>
<li>afterAll</li>
</ul>
<p>Grouping</p>
<ul>
<li>describe()</li>
<li>test()</li>
</ul>
<p>Snapshot testing</p>
<ul>
<li>toMatchSnapshot()을 호출하면, 기존에 스냅샷이 없었을 경우 .snap 파일을 만듦</li>
<li>기존 스냅샷이 있을 경우, 새로운 스냅샷과 비교하여 변경사항이 있으면 테스트는 실패함</li>
<li>toMatchInlineSnapshot()을 호출하면 별도의 스냅샷 파일을 만들지 않음.
이 경우, 어떻게 스냅샷이 쓰였는지를 하나의 파일 안에서 알 수 있게 됨</li>
</ul>
<p>react-testing-library</p>
<ul>
<li>테스트가 소프트웨어가 사용되는 모습을 닮을수록, 테스트를 더욱 신뢰할 수 있게 됨<br></li>
<li>react 컴포넌트의 특정 메서드나 상태를 테스트하는게 아니라, 
실제 유저가 사용하는 방식대로 테스트하는 접근</li>
<li>유저가 페이지에서 어떤 DOM 요소에 접근하는 방법을 흉내냄</li>
<li>이 방식으로 테스트 코드를 작성하면, 내부 구현이 바껴도 테스트가 깨지지 않음</li>
<li>react 컴포넌트가 렌더링한 결과에 대한 접근만 가능함</li>
<li>쿼리는 내부 상태나 내부 메서드에 접근할 수 없게 설계됨</li>
</ul>
<p>react-testing-library의 쿼리 -get</p>
<ul>
<li>getBy 관련 쿼리는 원하는 요소를 찾지 못할 경우나 여러개의 요소를 찾을 경우 에러를 던짐</li>
<li>getAllBy 관련 쿼리는 여러 요소를 찾아 배열을 반환한다. 원하는 요소를 찾지 못할 경우 에러를 던짐</li>
<li>원소가 반드시 페이지에 존재해야만 하는 경우 활용함</li>
</ul>
<p>react-testing-library의 쿼리 -find</p>
<ul>
<li>findBy 관련 쿼리는 원하는 원소가 없더라도 비동기적으로 기다림</li>
<li>여러 원소를 찾거나, 정해진 timeout동안 찾지 못하면 에러를 던짐</li>
<li>findAllBy 관련 쿼리는 여러 원소를 검색해 배열을 반환한다. 정해진 timeout 동안 찾지 못하면 에러를 던짐</li>
<li>Promise를 리턴하며, 실패시 reject, 성공시 resolve</li>
<li>어떤 유저의 동작 후에 등장하는 원소 등을 테스트하고자할 때 활용함</li>
</ul>
<p>react-testing-library의 쿼리 -query</p>
<ul>
<li>queryBy 관련 쿼리는 getBy와 비슷하게 원소를 찾아 반환하나, 못 찾을 경우 에러를 던지지 않고 nulldmf qksghksgka. dufj dnjsthfmf ckwdmaus 에러를 던짐</li>
<li>queryAllBy 관련 쿼리는 getAllBy와 비슷하게 여러개의 원소를 찾아 배열로 반환하나, 하나도 찾지 못하면 에러 대신 빈 배열을 반환함</li>
<li>특정 요소를 찾을 수 없음을 assertion의 기준으로 둘 때 활용됨</li>
</ul>
<p>jest-dom</p>
<ul>
<li>react-testing-library는 jest를 확장하여, 좀더 쓰기 편한 assertion을 제공함</li>
<li>toBeInTheDocument(), toHaveValue(), toBeDisabled(), toBeVisible() 등, DOM 테스팅에 특히 유용한 assertion 메서드를 제공함</li>
</ul>
<p>쿼리의 우선순위</p>
<ul>
<li>유저가 페이지를 이동하는 방식에 가까운 쿼리일수록 우선순위가 높음</li>
<li>접근성 높은 HTML을 작성할수록 테스트가 용이한 코드가 됨</li>
</ul>
<p>쿼리의 우선순위 - ByRole</p>
<ul>
<li>accessibility tree에 있는 요소들을 기준으로 원소를 찾음</li>
<li>유저가 웹페이지를 사용하는 방식을 가장 닮은 쿼리</li>
<li>동일한 role을 가진 경우, accessible name을 이용해 원소를 구별함</li>
<li>임의로 role 혹은 aria-*을 부여하는 것을 지양함<br></li>
<li>자주 사용되는 Role - button, checkbox, listitem, heading, img, form, textbox, link</li>
<li>자주 사용되는 accessible name
button - 텍스트
label - 텍스트
a - 텍스트
img - alt 텍스트</li>
</ul>
<p>쿼리의 우선순위 - Text</p>
<ul>
<li>유저가 볼 수 있는 Text 값을 기준으로 쿼리를 찾음</li>
<li>ByLabelText - label과 연관된 원소를 찾음</li>
<li>ByPlaceholderText - placeholder와 연관된 원소를 찾음</li>
<li>ByText - 주어진 text와 연관된 원소를 찾음</li>
<li>ByDisplayValue - input, textarea, select 등의 value를 기준으로 원소를 찾음</li>
</ul>
<p>쿼리의 우선순위 - semantic queries</p>
<ul>
<li>유저에게 보이지 않지만, 접근성 스펙에 적합한 alt, title을 이용하여 원소를 검색함</li>
<li>ByAltText - img, area, input 등의 alt 속성으로 원소를 검색함</li>
<li>ByTitle - title 속성으로 원소를 검색함</li>
</ul>
<p>쿼리의 우선순위 - Test ID</p>
<ul>
<li>data-testid 속성을 원하는 원소에 지정하고, 쿼리를 이용해 찾음</li>
<li>유저가 해당 속성을 기반으로 화면의 요소를 찾는게 아니므로 우선순위가 낮음</li>
<li>다른 쿼리로 테스트를 작성할 수 없을 때 이 쿼리를 백도어로 활용함</li>
</ul>
<h3 id="유저이벤트">유저이벤트</h3>
<p>user-event</p>
<ul>
<li>내장 이벤트 함수인 fireEvent, createEvent를 좀더 직관적이고 범용적으로 사용할 수 있도록 만든 라이브러리</li>
<li>click, type, keyboard, upload, hover, tab 등 유저가 실제로 웹페이지를 사용하며 만드는 이벤트를 메서드로 제공함</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.14]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.14</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.14</guid>
            <pubDate>Tue, 05 Dec 2023 18:16:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h2 id="redux">Redux</h2>
<h3 id="redux-소개">Redux 소개</h3>
<ul>
<li>앱 전체 상태를 쉽게 관리하기 위한 라이브러리</li>
<li>Redux의 많은 개념들이 Flux pattern에서 차용됨</li>
<li>주로 react 앱과 같이 사용</li>
<li>redux.js.org에서 수많은 문서를 참고할 수 있고, 웹상에 redux를 활용한 앱 구축 사례가 많음</li>
</ul>
<h3 id="언제-redux를-써야-하는가">언제 Redux를 써야 하는가</h3>
<ul>
<li>앱 전체의 상태 관리가 필요할 때</li>
<li>복잡한 비동기 처리가 있는 상태 관리가 필요할 때</li>
<li>앱의 상태가 복잡하고, 이를 체계적으로 관리하고 싶을 때</li>
<li>상태 관리  패턴을 도입하여, 여러 개발자와 협업하고 싶을 때</li>
<li>logger, devtool 등을 활용하여 상태를 관리할 필요가 있을 때</li>
</ul>
<h3 id="핵심-원칙">핵심 원칙</h3>
<ul>
<li>Single source of truth - Store는 단 하나이며, 모든 앱의 상태는 이곳에 보관됨</li>
<li>Immutability - 상태는 오로지 읽을 수만 있다. 변경하려면 모든 상태가 변경되어야 함</li>
<li>Pure function - 상태의 변경은 어떠한 사이드 이펙트도 만들지 않아야 함</li>
</ul>
<h3 id="action">Action</h3>
<pre><code>const action1 = {
    type: &#39;namespace/getMyData&#39;,
    payload : {
        id: 123
    }
 }</code></pre><ul>
<li>Action은 상태의 변경을 나타내는 개념</li>
<li>어떤 형태든지 상관없으나, 주로 type, payload를 포함하는 javascript 객체</li>
</ul>
<h3 id="action-creator">Action Creator</h3>
<pre><code>const addObj = (id) =&gt; ({
    type: &#39;namespace/getMyData&#39;,
    payload: {
        id: String(id).slice(1)
    }
})</code></pre><ul>
<li>Action을 생성하는 함수</li>
<li>직접 Action을 생성하는 것보다 Action Creator 를 활용하면 재사용성이 좋고 하나의 레이어를 추가할 수 있음 </li>
</ul>
<h3 id="store">Store</h3>
<pre><code>const store = 
createStore(reducer,
initialState)</code></pre><ul>
<li>앱 전체의 상태를 보관하는 곳</li>
<li>Action에 따라 reducer에서는 새로운 상태를 만들어내며, Store는 그 상태를 저장</li>
<li>Store의 상태는 불변하며, 매 액션이 발생할 때마다 새로운 객체가 만들어짐</li>
</ul>
<h3 id="redux의-구조">Redux의 구조</h3>
<ul>
<li>redux는 자유롭게 확장하여 사용할 수 있음</li>
<li>내부적으로는 action과 데이터가 어떻게 흐르는지 이해하고,
middleware, enhancer 등을 이용하여 redux를 확장함</li>
</ul>
<h3 id="middleware">middleware</h3>
<ul>
<li>action은 dispatch 이후 모든 middleware를 먼저 통과한 후에 reducer에 도달</li>
<li>redux-thunk, redux-logger 등의 라이브러리를 적용</li>
</ul>
<h3 id="enhancer">enhancer</h3>
<ul>
<li>action은 dispatch 이후 모든 middleware를 먼저 통과한 후에 reducer에 도달</li>
<li>redux devtools 등의 라이브러리를 적용</li>
</ul>
<h3 id="redux-toolkit">redux-toolkit</h3>
<ul>
<li>redux에서 공식적으로 추천하는, helper 라이브러리</li>
<li>기존에 만들어야 하는 수많은 보일러 플레이트를 제거하고, 
유용한 라이브러리를 포함하여 redux 코드를 쉽게 작성하게 함</li>
<li>redux-devtools, immerjs, redux-thunk, reselect 등의 라이브러리가 미리 포함됨</li>
</ul>
<h3 id="react-redux">react-redux</h3>
<ul>
<li>redux를 react 앱에 연결하게 하는 라이브러리</li>
<li>redux에서 관리하는 상태, dispatch 함수 등을 가져올 수 있음</li>
<li>클래스 컴포넌트, 함수형 컴포넌트에 모두 연결할 수 있음</li>
</ul>
<h4 id="react-redux-api---provider">react-redux API - Provider</h4>
<ul>
<li>Redux store를 React와 연결하기 위해서는 반드시 Provider로 컴포넌트를 감싸야만 함</li>
<li>Provider 안에서 렌더링된 컴포넌트들은 state에 접근할 수 있음</li>
</ul>
<h3 id="redux를-이용한-비동기-처리">redux를 이용한 비동기 처리</h3>
<ul>
<li>redux 비동기 처리를 위해서는 비동기를 위한 middleware를 추가하여야 함</li>
<li>redux-thunk는 Promise를 이용한 비동기 Action을 쉽게 처리하도록 하는 middleware</li>
</ul>
<h3 id="createasyncthunk">createAsyncThunk</h3>
<ul>
<li>redux-toolkit에서는 thunk middleware를 디폴트로 추가</li>
<li>redux-toolkit은 createAsyncThunk API를 제공함
fulfilled, rejected, pending 3가지 상태에 대해 각각 reducer를 작성</li>
<li>TypeScript 환경에서 reducer 작성 시, builder callback을 사용하여 작성해야 정확한 타이핑이 가능</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.13]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.13</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.13</guid>
            <pubDate>Mon, 04 Dec 2023 17:44:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h3 id="상태관리">상태관리</h3>
<ul>
<li>상태 관리 기술이란 앱 상에서의 데이터를 메모리 등에 저장하고 하나 이상의 컴포넌트에서 데이터를 공유하는 것</li>
<li>한 컴포넌트 안에서의 상태, 여러 컴포넌트 간의 상태, 전체 앱의 상태 관리를 모두 포함</li>
</ul>
<h3 id="mpa와-spa에서의-상태-관리">MPA와 SPA에서의 상태 관리</h3>
<ul>
<li>MPA에서는 서버의 데이터를 이용해 페이지를 렌더링하므로, 클라이언트의 데이터와 서버의 데이터가 큰 차이를 가지지 않음</li>
<li>SPA에서는 자체적으로 데이터를 갖고, 서버와의 동기화가 필요한 데이터만을 처리.
그 외의 데이터는 client만의 데이터로 유지</li>
</ul>
<h3 id="상태-관리-기술의-도입">상태 관리 기술의 도입</h3>
<ul>
<li>상태가 많지 않거나, 유저와의 인터렉션이 많지 않다면 
매 작업 시 서버와 동기화하더라도 충분함</li>
<li>앱이 사용하는 데이터가 점점 많아지고, 유저와의 인터렉션 시 임시로 저장하는 데이터가 많아지는 경우 상태 관리를 고려</li>
<li>프론트엔드 뿐만 아니라, 백엔드와의 데이터 통신도 충분히 고려해야함
ex) GraphQL</li>
</ul>
<h3 id="상태-관리-기술의-장점">상태 관리 기술의 장점</h3>
<ul>
<li>높은 품질의 코드를 작성하는데 유리</li>
<li>성능 최적화, 네트워크 최적화 등에 유리</li>
<li>데이터 관리의 고도화
ex) localStorage 활용한 persist state</li>
</ul>
<h3 id="상태-관리-기술의-단점">상태 관리 기술의 단점</h3>
<ul>
<li>Boilerplate 문제</li>
<li>파악해야 할 로직과 레이어가 많아짐<ul>
<li>잘못 사용할 경우, 앱의 복잡도만을 높이거나, 성능을 악화
ex) global state의 잘못된 활용 시 앱 전체 리렌더링 발생</li>
</ul>
</li>
</ul>
<h3 id="데이터-캐싱과-재활용">데이터 캐싱과 재활용</h3>
<ul>
<li>SPA에서 페이지 로딩 시마다 모든 데이터를 로딩한다면, 사용자 경험 측면에서 MPA를 크게 넘어서기 힘듦</li>
<li>오히려 네트워크 요청 수가 많아져서 더 느릴 수도 있음</li>
<li>변경이 잦은 데이터가 아니라면, 데이터를 캐싱하고 재활용함</li>
<li>변경이 잦다면, 데이터의 변경 시점을 파악해 최적화
ex) 일정 시간마다 서버에 저장, 타이핑 5초 후 서버에 저장</li>
</ul>
<h3 id="-prop-driling">### Prop Driling</h3>
<ul>
<li>컴포넌트가 복잡해지는 경우, 상위 부모와 자식 컴포넌트 간의 깊이가 커짐</li>
<li>최하단의 자식 컴포넌트가 데이터를 쓰기 위해 최상위 컴포넌트부터 데이터를 보내야하는 상황이 발생</li>
<li>Context API 등을 활용, 필요한 컴포넌트에서 데이터를 가져올 수 있음</li>
<li>컴포넌트 간의 결합성을 낮춤</li>
</ul>
<h3 id="flux-pattern">Flux Pattern</h3>
<ul>
<li>2014년에 Facebook에서 제안한 웹 애플리케이션 아키텍처 패턴</li>
<li>Unidirectional data flow를 활용, 데이터의 업데이트와 ui 반영을 단순화</li>
<li>리액트의 ui 패턴인 합성 컴포넌트와 어울리도록 설계</li>
<li>redux, react-redux 라이브러리의 Prior art</li>
</ul>
<h3 id="flux-pattern-vs-mvc-pattern">Flux Pattern vs MVC Pattern</h3>
<ul>
<li>MVC 패턴에서는, View에서 특정 데이터를 업데이트하면 연쇄적인 업데이트가 일어남</li>
<li>앱이 커지면 업데이트의 흐름을 따라가기 힘듦</li>
<li>Flux는 하나의 Action이 하나의 Update만을 만들도록 함</li>
<li>특정 유저의 인터렉션이 여러 UI 컴포넌트가 사용하는 데이터에 영향을 줄 때, MVC만으로는 앱의 복잡도를 낮추거나 업데이트의 흐름을 따라가기 어려움</li>
<li>data와 업데이트가 한 방향으로 흐르므로 ui의 업데이트를 예측하기 쉬움</li>
</ul>
<p>Flux 구조</p>
<ul>
<li>Action -&gt; Dispatcher -&gt; Store -&gt; View 순으로 데이터가 흐름</li>
<li>Store는 미리 dispatcher에 callback을 등록해, 자신이 처리할 action을 정의</li>
<li>action creator는 action을 생성하여 dispatcher로 보냄</li>
<li>dispatcher는 action을 store로 넘김</li>
<li>store는 action에 따라 데이터를 업데이트 후, 관련 view로 변경 이벤트 발생</li>
<li>View는 그에 따라 데이터를 다시 받아와 새로운 UI를 만듦</li>
<li>유저 인터렉션이 발생하면 View는 action을 발생</li>
</ul>
<h2 id="usestate-useref-usecontext-usereducer">useState, useRef, useContext, useReducer</h2>
<h3 id="상태-관리에-사용되는-훅">상태 관리에 사용되는 훅</h3>
<ul>
<li>외부 라이브러리 없이 React가 제공하는 훅 만으로 상태 관리를 구현하기 위해 사용</li>
<li>함수형 컴포넌트에 상태를 두고, 여러 컴포넌트 간 데이터와 데이터 변경 함수를 공유하는 방시긍로 상태를 관리하게 됨 </li>
</ul>
<h3 id="usestate">useState</h3>
<ul>
<li>단순한 하나의 상태를 관리하기에 적합함</li>
<li>const [ state, setState ] = useState(initState | initFn)</li>
<li>state가 바뀌면, state를 사용하는 컴포넌트를 리렌더함</li>
<li>useEffect와 함께, state에 반응하는 훅을 구축</li>
</ul>
<h3 id="useref">useRef</h3>
<ul>
<li>상태가 바뀌어도 리렌더링하지 않는 상태를 정의함<ul>
<li>즉, 상태가 ui의 변경과 관계없을 때 사용
ex) setTimeout의 timerld 저장</li>
<li>uncontrolled component의 상태를 조작하는 등, 리렌더링을 최소화하는 상태 관리에 사용됨
ex) Dynamic Form 예시</li>
</ul>
</li>
</ul>
<h3 id="usecontext">useContext</h3>
<ul>
<li>컴포넌트와 컴포넌트 간 상태를 공유할 때 사용</li>
<li>부분적인 컴포넌트들의 상태 관리, 전체 앱의 상태 관리를 모두 구현</li>
<li>Context Provider 안에서 렌더링되는 컴포넌트는, useContext를 이용해 깊이 nested 된 컴포넌트라도 바로 context value를 가져옴</li>
<li>context value가 바뀌면 내부 컴포넌트는 모두 리렌더링됨</li>
</ul>
<h3 id="usereducer">useReducer</h3>
<ul>
<li>useState보다 복잡한 상태를 다룰 때 사용</li>
<li>별도의 라이브러리 없이 flux pattern에 기반한 상태 관리를 구현<ul>
<li>const [ state, dispatch ] = useReducer(reducer, initState)</li>
<li>nested state 등 복잡한 여러 개의 상태를 한꺼번에 관리하거나, 
어떤 상태에 여러 가지 처리를 적용할 때 유용</li>
<li>상태 복잡하다면, useState에 관한 callback을 내려주는 것보다 dispatch를 prop으로 내려 리렌더링을 최적화하는 것을 권장</li>
</ul>
</li>
</ul>
<h3 id="usestate를-활용한-상태-관리">useState를 활용한 상태 관리</h3>
<ul>
<li>상위 컴포넌트에서 state와 state 변경 함수를 정의하고,
그 state나 변경 함수를 사용하는 컴포넌트까지 prop으로 내려주는 패턴</li>
<li>state가 변경되면, 중간에 state를 넘기기만 하는 컴포넌트들도 모두 리렌더링됨</li>
<li>상태와 상태에 대한 변화가 단순하거나, 상대적으로 소규모 앱에서 사용하기에 적합</li>
</ul>
<h3 id="usecontext를-활용한-상태-관리">useContext를 활용한 상태 관리</h3>
<ul>
<li>Provider 단에서 상태를 정의하고, 직접 상태와 변경 함수를 사용하는 컴포넌트에서 useContext를 이용해 바로 상태를 가져와 사용하는 패턴</li>
<li>useReducer와 함께, 복잡한 상태와 상태에 대한 변경 로직을 두 개 이상의 컴포넌트에서 활용하도록 구현 가능</li>
<li>state는 필요한 곳에서만 사용하므로, 불필요한 컴포넌트 리렌더링을 방지</li>
<li>Prop Drilling(Plumbing)을 방지하여 컴포넌트 간 결합도를 낮춤</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.12]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.12</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.12</guid>
            <pubDate>Sun, 03 Dec 2023 22:31:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h3 id="자바스크립트-비동기의-등장">자바스크립트 비동기의 등장</h3>
<ul>
<li>초기 웹 환경에서는, 서버에서 모든 데이터를 로드하여 페이지를 빌드했으므로 자바스크립트에서는 별도의 비동기 처리가 필요하지 않음</li>
<li>Ajax 기술의 등장으로 페이지 로드 없이 client-side에서 서버로 요청을 보내 데이터를 처리할 수 있게됨</li>
<li>XMLHttpRequest라는 객체를 이용해 서버로 요청을 보낼 수 있게 됨</li>
</ul>
<h3 id="자바스크립트와-비동기">자바스크립트와 비동기</h3>
<ul>
<li>자바스크립트는 single-threaded language이므로, 만일 서버 요청을 기다려야한다면 유저는 멈춰있는 브라우저를 보게 될 것.</li>
<li>따라서 동기가 아닌 비동기 처리를 이용해 서버로 통신할 필요가 있음</li>
<li>비동기 요청 후, main thread는 유저의 입력을 받거나, 페이지를 그리는 등의 작업을 처리</li>
<li>비동기 응답을 바등면, 응답을 처리하는 callback 함수를 task queue에 넣음</li>
<li>event queue는 main thread에 여유가 있을 때 task queue에서 함수를 꺼내 실행</li>
</ul>
<h3 id="동기-vs-비동기">동기 vs 비동기</h3>
<ul>
<li>동기(synchronous) 코드는, 해당 코드 블록을 실행할 때 thread의 제어권을 넘기지 않고 순서대로 실행하는 것을 의미함</li>
<li>비동기(asynchronous) 코드는, 코드의 순서와 다르게 실행됨.</li>
<li>비동기 처리 코드를 감싼 블록은 task queue에 넣어짐.</li>
<li>main thread가 동기 코드를 실행한 후에 제어권이 돌아왔을 때
event loop가 task queue에 넣어진 비동기 코드를 실행함</li>
</ul>
<h3 id="비동기-처리를-위한-내부-구조">비동기 처리를 위한 내부 구조</h3>
<ul>
<li><p>브라우저에서 실행되는 자바스크르비트 코드는 event driven 시스템으로 작동</p>
</li>
<li><p>웹앱을 로드하면 브라우저는 HTML document를 읽어 문서에 있는 CSS code, JS code를 불러옴</p>
</li>
<li><p>자바스크립트 엔진은 코드를 읽어 실행</p>
</li>
<li><p>브라우저의 main thread는 자바스크립트 코드에서 동기적으로 처리되어야 할 코드 실행 외에도, 웹 페이지를 실시간으로 렌더링하고, 유저의 입력을 감지하고, 네트워크 통신을 처리하는 등 수많은 일을 처리</p>
</li>
<li><p>비동기 작업을 할당하면, 비동기 처리가 끝나고 브라우저는 task queue에 실행 코드를 넣음</p>
</li>
<li><p>main thread는 event loop를 돌려, task queue에 작업이 있는지 체크.</p>
</li>
<li><p>작업이 있으면 task를 실행</p>
</li>
</ul>
<h2 id="promise">Promise</h2>
<h3 id="callback-pattern-vs-promise">Callback pattern vs Promise</h3>
<ul>
<li>비동기 처리 후 실행될 코드를 Callback function으로 보내는 것</li>
<li>비동기 처리가 고도화되면서, callback hell 등이 단점으로 부각됨</li>
<li>Promise를 활용하여 비동기 처리의 순서 조작, 에러 핸들링, 여러 비동기 요청 처리 등을 쉽게 처리할 수 있게 됨</li>
</ul>
<h3 id="promise-1">Promise</h3>
<ul>
<li>Promise 객체는, 객체가 생성 당시에는 알려지지 않은 데이터에 대한 Proxy</li>
<li>비동기 실행이 완료된 후에, &#39;.then&#39;, &#39;.catch&#39;, &#39;finally&#39; 등의 핸들러를 붙여 각각 데이터 처리 로직, 에러 처리 로직, 클린업 로직을 실행</li>
<li>then 체인을 붙여, 비동기 실행을 마치 동기 실행처럼 동작하도록 함</li>
<li>전체 스펙은 <a href="https://promisesaplus.com/">https://promisesaplus.com/</a> 참조<br></li>
<li>Promise 객체는 pending, fulfilled, rejected 3개의 상태를 가짐</li>
<li>fulfilled, rejected 두 상태를 settled 라고 지칭</li>
<li>pending은 비동기 실행이 끝나기를 기다리는 상태</li>
<li>fulfilled는 비동기 실행이 성공한 상태</li>
<li>rejected는 비동기 실행이 실패한 상태</li>
</ul>
<br>
- then, catch는 비동기(Promise), 동기 실행 중 어떤 것이라도 리턴할 수 있음

<h3 id="multiple-promise-handling">Multiple Promise handling</h3>
<ul>
<li>Promise.all()은 모든 프로미스가 fulfilled 되길 기다림
하나라도 에러 발생시, 모든 프로미스 요청이 중단됨</li>
<li>Promise.allSettled()는 모든 프로미스가 settled 되길 기다림</li>
<li>Promise.race()는, 넘겨진 프로미스들 중 하나라도 settled 되길 기다림</li>
<li>Promise.any() - 넘겨진 프로미스 중 하나라도 fulfilled 되길 기다림</li>
</ul>
<h3 id="promise-chaining-nested-promise">Promise chaining, nested promise</h3>
<ul>
<li>promise 객체는, settled되더라도 계속 핸들러를 붙일 수 있음</li>
<li>핸들러를 붙인 순서대로 호출됨</li>
<li>.catch 뒤에 계속 핸들러가 붙어있다면, 에러를 처리한 후에 계속 진행됨
이때는 catch에서 리턴한 값이 then으로 전달됨</li>
</ul>
<h2 id="async--await">async / await</h2>
<h3 id="async--await-1">async / await</h3>
<ul>
<li>Promise 체인을 구축하지 않고도, Promise를 직관적으로 사용할 수 있는 문법</li>
<li>많은 프로그래밍 언어에 있는 try ... catch 문으로 에러를 직관적으로 처리</li>
<li>async function을 만들고, Promise를 기다려야 하는 표현 앞에 await를 붙임</li>
</ul>
<h3 id="async--await---여러개의-await">async / await - 여러개의 await</h3>
<ul>
<li>여러개의 await을 순서대로 나열하여, then chain을 구현할 수 있음</li>
<li>try ... catch 문을 자유롭게 활용하여 에러처리를 적용</li>
</ul>
<h3 id="async--await---promise-와의-조합">async / await - Promise 와의 조합</h3>
<ul>
<li>Promise.all은 특정 비동기 작업이 상대적으로 빠르게 끝나도,
느린 처리를 끝까지 기다려야만 함</li>
<li>이와 달리, async/await을 활용할 경우 parallelism을 구현할 수 있음
즉, 끝난 대로 먼저 처리될 수 있음</li>
</ul>
<h3 id="postman-소개">Postman 소개</h3>
<ul>
<li>서버와의 통신을 위해 api를 활용하는 경우, react 앱으로만 요청하여 api가 잘 동작하는지 알아보는건 비효율적</li>
<li>수많은 api의 endpoint와 실행 조건 등을 관리하는 것도 힘듦.</li>
<li>Postman은 api를 테스트하기 위한 개발 도구<br></li>
<li>Auth, header, payload, query 등 api 요청에 필요한 데이터를 쉽게 세팅</li>
<li>다른 개발자가 쉽게 셋업해 테스트할 수 있도록 api 정보를 공유할 수 있음 </li>
<li>request를 모아 collection으로 만들어 api를 종류별로 관리</li>
<li>환경 변수를 정의하여, 환경별로 테스트 가능
<a href="https://www.postman.com/">https://www.postman.com/</a> 에서 다운로드</li>
</ul>
<h3 id="open-api">Open API</h3>
<ul>
<li><p>RESTful API를 하나의 문서로 정의하기 위한 문서 표준</p>
</li>
<li><p>OpenAPI Specification(OAS)으로 정의됨</p>
</li>
<li><p>Swagger 등의 툴로, Open API로 작성된 문서를 파싱해 테스팅 도구로 만들 수 있음</p>
</li>
<li><p>프론트엔드 개발자, 백엔드 개발자와의 협업 시 주요한 도구로 사용</p>
</li>
<li><p>API의 method, endpoint를 정의</p>
</li>
<li><p>endpoint마다 인증 방식, content type 등 정의</p>
</li>
<li><p>body data, query string, path variable 등 정의</p>
</li>
<li><p>요청, 응답 데이터 형식과 타입 정의 - data model 활용(schema)</p>
</li>
</ul>
<h3 id="cors">CORS</h3>
<ul>
<li>Cross-Origin Resource Sharing</li>
<li>브라우저는 모든 요청 시 origin 헤더를 포함</li>
<li>서버는 origin 헤더를 보고, 해당 요청이 원하는 도메인에서부터 출발한 것인지를 판단</li>
<li>다른 origin에서 온 요청은 서버에서 기본적으로 거부함</li>
<li>그러나 보통 서버의 endpoint와 홈페이지 domain은 다른 경우가 많음</li>
<li>따라서 서버에서는 홈페이지 domain을 허용하여, 다른 domain이라 하더라도 요청을 보낼 수 있게 함</li>
<li>서버는 Access-Control-Allow-Origin 외에 Access-Control-*을 포함하는 헤더에 CORS 관련 정보를 클라이언트로 보냄<br></li>
<li>웹사이트에 악성 script가 로드되어, 수상한 요청을 하는 것을 막기 위함</li>
<li>반대로, 익명 유저로부터 DDos 공격 등을 막기 위함</li>
<li>서버에 직접 CORS 설정을 할 수 없다면, Proxy 서버 등을 만들어 해결</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.11]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.11</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.11</guid>
            <pubDate>Wed, 29 Nov 2023 20:10:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h3 id="spa와-라우팅">SPA와 라우팅</h3>
<h3 id="single-page-application">Single Page Application</h3>
<ul>
<li>SPA(Single Page Application)은 하나의 페이지 요청으로 전체 웹앱을 사용하는 방식</li>
<li>유저는 웹페이지를 사용하며 모바일 앱 같은 경험을 느낌 </li>
</ul>
<h3 id="multi-page-application">Multi Page Application</h3>
<ul>
<li>MPA(Multi Page Application)은 서버에 미리 여러 페이지를 두고, 유저가 네비게이션 시 요청에 적합한 페이지를 전달</li>
<li>미리 서버에서 전체 페이지를 빌드해 브라우저로 전송됨</li>
<li>서버에 라우팅을 처리하는 기능이 있고, 서버에서 여러 페이지를 관리함</li>
<li>페이지 요청마다 모든 리소스를 다시 받아오므로, 페이지 간 데이터를 재활용하기 힘듦</li>
</ul>
<h3 id="spa의-특징">SPA의 특징</h3>
<ul>
<li>Client-side routing 기술을 활용, 페이지 진입 시 리로드 없이 라우팅함</li>
<li>AJAX 기술을 활용, 페이지 이동 시 서버에 데이터만 요청하여 자바스크립트로 페이지를 만듦</li>
<li>MPA와 다르게, 여러 페이지를 하나의 앱의 구성요소로 보고 여러 페이지 간의 스타일, 컴포넌트를 재활용하는 방향으로 구현</li>
<li>자바스크립트 만을 활용해 전체 페이지를 만들기에, 첫 요청시 빈 페이지를 받게 됨.<h3 id="spa의-기술적-장점">SPA의 기술적 장점</h3>
<ul>
<li>서버에서 페이지를 만들 필요가 없으므로 CDN에 캐싱이 가능</li>
<li>매번 페이지 요청을 할 필요가 없어 네트워크 요청이 줄어듦</li>
<li>웹사이트를 개별 페이지보다는 하나의 앱으로 보는 설계로 고도의 소프트웨어 설계와 패턴을 적용할 수 있음</li>
</ul>
</li>
</ul>
<h3 id="spa의-기술적-난관들">SPA의 기술적 난관들</h3>
<ul>
<li>MPA방식 보다는 Search Engine Optimization에 불리함</li>
<li>하나의 자바스크립트 앱이 지속하므로, 메모리 관리와 성능, 데이터 활용 등이 중요</li>
<li>여러 페이지를 전송받는 것 보다, 하나의 거대한 자바스크립트 앱을 전송받아야 하므로 코드가 많아질수록 로드 속돡 느려짐</li>
</ul>
<h3 id="spa에서의-라우팅">SPA에서의 라우팅</h3>
<ul>
<li>주로 History API 혹은 url Hash를 이용해 페이지 리로드 없는 페이지 전환을 구현</li>
<li>history, location 등 HTML5 API를 활용</li>
<li>visibilitychange, popstate, beforeunload 등 window event를 활용하여 페이지 전환 등의 이벤트 시 핸들러를 등록</li>
<li>react-router, reach-router 등의 라이브러리를 활용하면, 라우팅 관련 기능을 쉽게 사용할 수 있음</li>
</ul>
<h2 id="react-router">react-router</h2>
<ul>
<li>Declarative routing for React</li>
<li>React의 JSX를 이용하거나, History API를 사용하여 라우팅을 구현</li>
<li>웹에서는 react-router-dom을 사용</li>
<li>적용 시, 서버의 모든 path에서 같은 앱을 서빙하도록 해야 함</li>
</ul>
<h3 id="react-router의-기능">react-router의 기능</h3>
<ul>
<li>React 컴포넌트를 특정 path와 연결하면, 해당하는 path로 진입 시 컴포넌트를 렌더링하게 함</li>
<li>query, path variable 등 URL parameter를 얻어 활용함</li>
<li>조건에 맞지 않을 경우 redirect 함</li>
<li>페이지 이동 시, 이벤트 핸들러를 등록함</li>
<li>/posts/my-post-1 등의 nested route를 구현함</li>
</ul>
<h3 id="react-router의-사용">react-router의 사용</h3>
<ul>
<li>BrowserRouter 로 감싸 Router Context를 제공해야함</li>
<li>Route로 path를 정의하고, 그 안에 렌더링하고자 하는 컴포넌트를 넣음</li>
<li>Link 로 특정 페이지로 이동 시, 리로드 없이 페이지가 이동함</li>
<li>Switch로, 매칭되는 라우트 하나를 렌더링하게 함</li>
</ul>
<h2 id="react-router-컴포넌트">react-router 컴포넌트</h2>
<h3 id="browserrouter">BrowserRouter</h3>
<ul>
<li>Html5의 history API를 사용하여 UI와 URL의 싱크를 맞추는 역할</li>
<li>모든 URL에 대해 동작하게 하기 위해서는 서버 설정 필요</li>
<li>모든 path 앞의 basename을 지정할 수 있음
ex) basename=&quot;/ko&quot;</li>
<li>forceRefresh로, 페이지 이동 시 리프레시할 것인지 지정할 수 있음</li>
</ul>
<h3 id="switch">Switch</h3>
<ul>
<li>여러 Route 중 매치되는 Route 위에서부터 하나 선택하여 렌더링함</li>
<li>매칭되는 Route가 없으면 아무것도 보여주지 않음
fallback용으로 404 Not Found Page를 추가함</li>
<li>path=&quot;/&quot;의 경우 모든 path에 매칭되므로 exact 키워드를 추가하거나 가장 아래로 내림</li>
</ul>
<h3 id="route">Route</h3>
<ul>
<li>path와 컴포넌트를 매칭함</li>
<li>매칭되는 컴포넌트는 children으로 넣어주거나 component prop으로 넘김</li>
</ul>
<pre><code>&lt;Route path = &quot;/users&quot;&gt;
    &lt;UserPage /&gt;
&lt;/Route&gt;</code></pre><pre><code>&lt;Route component = {UserPage}
    path=&quot;/users&quot; /&gt;</code></pre><ul>
<li>exact 키워드로 정확하게 매칭하는 path를 설정함</li>
<li>Route로 렌더링 되는 최상위 컴포넌트는 match, location, history를 prop으로 받음</li>
<li>render prop으로, 매칭되었을 때 실제 어떤 컴포넌트를 렌더링할지 통제함</li>
</ul>
<h3 id="redirect">Redirect</h3>
<ul>
<li>Link와 비슷하나, 렌더링되면 to prop으로 지정한 path로 이동함</li>
<li>Switch 안에서 쓰일 경우, from, to를 받아 이동하게 만듦
ex) from=&quot;/&quot; to=&quot;/login&quot;</li>
</ul>
<h3 id="link-navlink">Link, NavLink</h3>
<ul>
<li>to prop을 특정 URL로 받아, 클릭 시 네비게이션 함</li>
<li>anchor tag를 래핑함</li>
<li>NavLink의 경우, 매칭 시 어떤 스타일을 가질지 등의 추가 기능이 있음</li>
<li>to에 location object나 함수를 받을 수 있음</li>
</ul>
<h3 id="usehistory-uselocation-useparams-useroutematch">useHistory, useLocation, useParams, useRouteMatch</h3>
<ul>
<li>최상위 컴포넌트가 아니더라도, hook으로 react-router 관련 객체에 접근할 수 있음</li>
<li>history, location, params, match 객체에 접근함 </li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.10]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.10</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.10</guid>
            <pubDate>Tue, 28 Nov 2023 20:09:35 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h2 id="react앱에서의-스타일링-overview">React앱에서의 스타일링 Overview</h2>
<p>좋은 앱을 만들려면</p>
<ul>
<li>번들 사이즈에 대한 고려
Css 코드가 차지하는 사이즈는 무척 중요한 요소</li>
<li>앱 성능에 대한 고려
animation, transition 등 유저와의 상호작용에서 스타일 코드의 성능이 중요 요소</li>
<li>사용자에게 유리한 ui/ux를 고려
스타일링에 대한 지식으로, 고급 테크닉을 적용하여 더 나은 ui/ux를 반영</li>
<li>자바스크립트를 이용한 다양한 스타일 기법
ui 토클링, 애니메이션, 다크모드, 복잡한 ui 컴포넌트 등은 자바스크립트에 대한 지식만으로 구현하기 힘듦</li>
<li>유지보수가 용이하고 확장 가능한 코드를 작성 (장기적으로 좋다)
스타일에 관련된 코드를 어떻게 작성하고 관리하는 가에 대한 지식이 필요</li>
</ul>
<h3 id="스타일-적용-방법">스타일 적용 방법</h3>
<h4 id="css-import">CSS import</h4>
<ul>
<li>CSS(혹은 SCSS, Sass) 파일을 import해서 사용</li>
<li>필요한 모든 CSS 스타일을 하나의 파일에 작성하며, 자바스크립트 파일과 코드 분리 가능<pre><code>import &#39;button.css&#39;</code></pre><blockquote>
</blockquote>
장단점</li>
<li>단순히 css 파일만을 import하여 사용할 수 있어 편리</li>
<li>컴포넌트가 많지 않을 겨우, 하나의 css 파일에 코드를 관리하는 것도 가능함</li>
<li>css 파일을 분리할 수 있으나, namespace를 나눌 수 없음</li>
<li>만일 스타일이 겹칠 경우 cascading rule에 따라, 마지막에 나온 룰이 덮어씌워짐</li>
</ul>
<h4 id="css-module">CSS module</h4>
<ul>
<li>하나의 CSS module 파일 안에 작성한 스타일은 하나의 파일 namespace로 관리</li>
<li>class name 뒤에 겹치지 않는 hash를 붙임</li>
<li>스타일이 겹치는 상황을 해결</li>
<li>두단어 이상의 경우, class 명을 camelCase로 이름을 지금</li>
</ul>
<h4 id="css-in-js">CSS-in-js</h4>
<ul>
<li>별도의 CSS 파아ㅣㄹ을 만들지 않고 하나의 컴포넌트 파일 안에서 스타일을 작성</li>
<li>자바스크립트 문법을 그대로 활용하여 코드를 작성</li>
<li>리액트 컴포넌트를 사용하는 것처럼 사용</li>
<li>Sass 문법 활용 가능</li>
</ul>
<pre><code>import styled from &quot;styled-components&quot;;

const Container = styled.div`
    background: rgba(0, 0, 0, 0);
    margin: 10px;
    padding: 5px;
    `;</code></pre><h3 id="css-box-model">CSS box model</h3>
<ul>
<li>CSS layout의 기본이 되는 모델</li>
<li>content-box, padding-box, border-box, margin-box 순으로 하나의 element를 감싸고 있음</li>
<li>box의 타입은 inline, block 두 가지</li>
<li>display:inline, display:inline-block, display:block으로 서로 다른 box type을 적용함</li>
</ul>
<h3 id="sass">Sass</h3>
<ul>
<li>Syntactically Awesome style Sheets. CSS Preprocessor.</li>
<li>SCSS, Sass 문법을 지원함</li>
<li>모듈, 믹스인, nested style, 변수, 조건문, 반복문 등의 기능으로 CSS를 프로그래밍 언어적으로 활용하도록 확장</li>
<li>styled-components는 Sass를 기본적으로 지원함</li>
</ul>
<h3 id="sass-1">Sass &amp;</h3>
<ul>
<li>&amp;는 자기 자신을 나타내는 placeholder</li>
<li>기존 css의 selector 문법을 응용하여 복잡한 스타일을 적용</li>
<li>반복된 코드를 제거할 수 있음<pre><code>.reset-button {
  &amp;.active {}
  &amp;.disabled {}
  &amp; + &amp; {}
  &amp; ~ &amp; {}
  &amp; &gt; button {}
}</code></pre></li>
</ul>
<h3 id="css-flexbox">CSS Flexbox</h3>
<ul>
<li>HTml element를 하나의 상자로 간주하고, 그 안에서 어떻게 내부 item을 배열할 것인가를 스타일하는 모델</li>
<li>1차원의 레이아웃을 디자인하는데 사용</li>
<li>responsive design에 유리</li>
<li>가운데 정렬, 비율로 정렬 등을 처리할 때 유리</li>
</ul>
<h3 id="css-flexbox-기본개념">CSS Flexbox 기본개념</h3>
<ul>
<li>flex container - Flexbox 아이템을 담는 컨테이너</li>
<li>flex item - 컨테이너 안에 담긴 아이템</li>
<li>flex axis - flex 아이템의 방향을 결정하는 촉</li>
</ul>
<p>flex-direction : row, column 등의 방향을 결정
justify-content : main axis에서의 정렬을 결정
align-items : cross axis에서의 정렬을 결정
flex-wrap : flex container가 내부 item의 width를 합친 것보다 작아질 때, 어떻게 정렬할 것인지를 결정</p>
<h3 id="styled-components">styled-components</h3>
<ul>
<li><p>자바스크립트 파일 안에 스타일을 정의하고, 리액트 컴포넌트처럼 활용</p>
</li>
<li><p>자바스크립트 코드와 긴밀히 연계하여 다양한 코드를 작성할 수 있음</p>
</li>
<li><p>별도의 CSS 파일을 만들지 않고 하나의 파일 안에 스타일을 관리하고 싶을 때 유리</p>
</li>
<li><p>스타일 코드와 컴포넌트 코드 간의 결합을 나누고 싶을 때 유리</p>
</li>
<li><p>tagged template literal이라는 문법을 활용</p>
</li>
<li><p>css 코드에 post-css, minification, Sass 적용</p>
</li>
<li><p>css 코드를 겹치지 않게 처리. 클래스 이름 자체가 hash.</p>
</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.9]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.9</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.9</guid>
            <pubDate>Mon, 20 Nov 2023 17:57:24 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h2 id="hook">Hook</h2>
<h3 id="hook이란">Hook이란?</h3>
<p>컴포넌트에서 데이터를 관리(State)하고 데이터가 변경될 때 상호작용(Effect)을 하기 위해 사용한다.
앞선 강의에서 사용해본 useState가 바로 State Hook이다.</p>
<p>기존에는 컴포넌트 내에서 State와 생명주기를 관리하기 위해서 반드시 클래스 컴포넌트를 사용하여야했다.
그러나 개발자가 느끼기에 다소 복잡한 클래스 컴포넌트(Class Componenet)를 보완하고 함수 컴포넌트에서 클래스 컴포넌트의 기능을 구현하기 위해 React 16.8 버전에 추가된 것이 바로 Hook이다.</p>
<h3 id="유의사항">유의사항</h3>
<ul>
<li>Hook은 React 함수(컴포넌트, Hook) 내에서만 사용이 가능하다.</li>
<li>Hook의 이름은 반드시 &#39;use&#39;로 시작해야 한다.</li>
<li>최상위 Level에서만 Hook을 호출할 수 있다. (if문, for문 안 쪽 또는 콜백함수 내에서 호출하지 마세요.) </li>
</ul>
<h3 id="state-hook">State Hook</h3>
<pre><code>const App = () =&gt; {
    //일반적인 useState 사용법
    const [state이름, setState이름] = useState(초기값)
    }</code></pre><ul>
<li>useState는 컴포넌트 내 동적인 데이터를 관리할 수 있는 hook입니다.</li>
<li>최초에 useState가 호출될 때 초기값으로 설정되며 이후 재 렌더링이 될 경우 무시됩니다.</li>
<li>state는 읽기 전용이므로 직접 수정하지 마세요</li>
<li>state를 변경하기 위해서는 setState를 이용한다.</li>
<li>state가 변경되면 자동으로 컴포넌트가 재 렌더링된다.</li>
</ul>
<h3 id="effect-hook">Effect Hook</h3>
<pre><code>const App = () =&gt; {
    useEffect(EffectCallback, Deps?)
    }</code></pre><ul>
<li>Effect Hook을 사용하면 함수 컴포넌트에서 side effect를 수행할 수 있다.</li>
<li>컴포넌트가 최초로 렌더링될 때, 지정한 State나 Prop가 변경될 때마다 이펙트 콜백 함수가 호출된다.</li>
<li>Deps : 변경을 감지할 변수들의 집합(배열)</li>
<li>EffectCallback : Deps에 지정된 변수가 변경될 때 실행할 함수</li>
</ul>
<h3 id="이외의-hooks">이외의 Hooks</h3>
<ul>
<li>useMemo
지정한 State나 Props가 변경될 경우 해당 값을 활용해 계산된 값을 메모이제이션하여 재렌더링 시 불필요한 연산을 줄인다.
useMemo의 연산은 렌더링 단계에서 이루어지기 때문에 시간이 오래 걸리는 로직을 작성하지 않는 것이 권장된다.</li>
<li>useCallback
함수를 메모이제이션하기 위해 사용하는 Hook이다. 컴포넌트가 재렌더링될 때 불필요하게 함수가 다시 생성되는 것을 방지한다.
useMemo(() =&gt; fn,deps)와
useCallback(fn,deps)는 같다</li>
<li>useRef
컴포넌트 생애 주기 내에서 유지할 ref 객체를 반환한다.
ref 객체는 .current라는 프로퍼티를 가지며 이 값을 자유롭게 변경할 수 있다.
일반적으로 리액트에서 DOM Element에 접근할 때 사용한다. 
useRef에 의해 반환된 ref 객체가 변경되어도 컴포넌트가 재렌더링되지 않는다.</li>
</ul>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.8]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.8</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.8</guid>
            <pubDate>Mon, 20 Nov 2023 00:46:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<h2 id="props와-state">Props와 State</h2>
<h3 id="props">Props</h3>
<p><code>컴포넌트 생성</code></p>
<pre><code>const Welcom = (props) =&gt; {
    return &lt;h1&gt;Hello, {props.name}&lt;/h1&gt;;
    }</code></pre><p><code>컴포넌트 사용</code></p>
<pre><code>const App = () =&gt; {
    return &lt;div&gt;
    &lt;Welcome name=&quot;수영&quot; /&gt;
    &lt;Welcome name=&quot;민수&quot; /&gt;
    &lt;Welcome name=&quot;영희&quot; /&gt;
    &lt;/div&gt;;
 }</code></pre><p>사용되는 값들을 바꿔가며 출력할 수 있다</p>
<p>기본적으로 component에 원하는 값을 넘겨줄 때 사용하며 넘겨줄 수 있는 값은 변수, 함수, 객체, 배열 등 Javascript의 요소라면 제한이 없다.
주로 component의 &#39;재사용&#39;을 위하여 사용한다.</p>
<p>props는 읽기 전용이다.</p>
<h3 id="state">State</h3>
<p>state는 component 내에서 유동적으로 변할 수 있는 값을 저장한다.
개발자가 의도한 동작에 의해 변할 수도 있고 사용자의 입력에 따라 새로운 값으로 변경될 수도 있다.
state 값이 변경되고 재렌더링이 필요한 경우에 react가 자동으로 계산하여 변경된 부분을 렌더링한다</p>
<pre><code>import { useState } from &#39;react&#39;;

function Example() {
    const [count, setCount] = useState(0);
    return (
    &lt;div&gt;
    &lt;p&gt;버튼을 {count}번 눌렀습니다.&lt;/p&gt;
    &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
    클릭
    &lt;/button&gt;
    &lt;/div&gt;
    );
    }</code></pre><ul>
<li><p>state 값을 직접 변경하게 되면 리액트가 component를 다시 렌더링할 타이밍을 알아차리지 못한다.
반드시 setState 함수를 이용해 값을 변경한다.
setState 함수를 호출할 때 리액트에게 &quot;다시 렌더링 해달라&quot;라는 명령이 내려진다.</p>
</li>
<li><p>setState 함수에는 변경할 값을 직접 넣는 방법이 있고, 함수를 넣는 방법이 있다.
함수를 넣는 경우 함수가 반환(return)하는 값으로 state가 변경된다.
<code>현재 값을 기반으로 state를 변경하고자 하는 경우</code> 함수를 넣는 방법을 권장한다.</p>
<br>
<br>

</li>
</ul>
<h2 id="이벤트-처리">이벤트 처리</h2>
<p>이벤트(event)란 웹 브라우저가 알려주는 HTML 요소에 대한 사건의 발생을 의미한다.
유저의 행동에 의해 발생할 수도 있으며 개발자가 의도한 로직에 의해 발생할 수도 있다.
이렇게 발생된 이벤트를 자바스크립트를 이용해 대응할 수 있다.
Element가 로딩되었을 때, 사용자가 Element를 클릭했을 때, 마우스를 올렸을 때, 더블 클릭했을 때, 키보드 입력을 주었을 때 등 다양한 이벤트가 존재한다.
이벤트 핸들러 함수에서는 다양한 로직을 처리하고 그 결과를 사용자에 출력하여 알릴 수도 있다.</p>
<p>리액트에서 이벤트를 처리하는 방법은 크게 두가지 방법이 있다.
별도의 핸들링 함수로 선언하고 Element에 넘겨주는 방법과 이벤트를 할당하는 부분에서 익명 함수를 작성하는 방법으로 나뉜다.</p>
<ul>
<li><p>onClick : Element를 클릭했을 때</p>
</li>
<li><p>onChange : Element의 내용이 변경되었을 때 (input의 텍스트를 변경, 파일 선택 등)</p>
</li>
<li><p>onKeyDown, onKeyUp, onKeyPress : 키보드 입력이 일어났을 때</p>
</li>
<li><p>onDooubleClick :Element를 더블 클릭했을 때</p>
</li>
<li><p>onFocus : Element에 Focus되었을 때</p>
</li>
<li><p>onBlur : Element가 Focus를 잃었을 때</p>
</li>
<li><p>onSubmit : Form Element에서 submit 했을 때</p>
</li>
<li><p>DOM Input 값을 State에 저장하기
event object의 target은 이벤트의 원인이 되는 Element를 가리킨다.
현재 event의 target은 input element이므로 입력된 value를 가져와 setState를 하는 모습이다.</p>
</li>
<li><p>여러 input 동시에 처리하기
State를 여러 개 선언할 수도 있지만 object를 활용하여 여러 개의 Input을 state로 관리하는 방법이 있다.
target으로부터 name을 받아와 해당 name의 key에 해당하는 value를 변경하여 state에 반영한다.</p>
</li>
</ul>
<h3 id="props-vs-state">Props vs State</h3>
<p>Props와 State의 가장 큰 차이로 Props는 부모 컴포넌트에서 자식 컴포넌트로 전달하는 값으로 자식 컴포넌트에서는 Props를 직접 수정할 수 없지만 State는 컴포넌트 내부에서 선언하며 내부에서 관리되는 값으로 값을 변경할 수 있다는 점이 있다.</p>
<p>따라서 값이 변경되어야하는 상황, 예를 들면 매초 변하는 시간을 출력해야 하거나 버튼 클릭시 값이 변하는 것을 출력해야 한다면 State를 사용해야 한다. 정리하자면 Props는 읽기 전용으로 수정이 불가능하고, State는 원하는 경우 수정이 가능하기 때문에 상황에 따라 알맞은 것을 사용하면 된다.</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.7]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.7</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.7</guid>
            <pubDate>Fri, 17 Nov 2023 19:33:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/e89c65d1-a50c-41f5-96df-9f61a476896d/image.PNG" alt=""></p>
<h2 id="react가-뭔가요">React가 뭔가요?</h2>
<h3 id="spasingle-page-application">SPA(Single Page Application)</h3>
<p>최초에 서버로부터 html을 전달 받고 페이지의 변경이 필요할 때 변경이 필요한 부분을 json으로 전달 받는다.
이때 페이지에서 변경된 부분만 계산하여 다시 그리게 된다.</p>
<p>React
사용자 인터페이스를 만들기 위한 javascript 라이브러리</p>
<p>Component
리액트에서 서비스를 개발하는 데 있어 독립적인 단위로 쪼개어 구현</p>
<p>virtual DOM
가상적인 표현을 메모리에 저장하고 reactDOM과 같은 라이브러리에 의해 실제 DOM과 동기화하는 프로그래밍 개념</p>
<p>JSX
javascript 내에서 ui를 작성하기 위해 개발자에게 익숙한 환경을 제공, html과 유사함</p>
<h4 id="리액트를-쓰는-이유">리액트를 쓰는 이유</h4>
<p>생산성 / 재사용성
풍부한 자료 / 라이브러리
다양한 사용처</p>
<h4 id="리액트-특정-분석하기">리액트 특정 분석하기</h4>
<p>State
컴포넌트 내에서 state를 이용하여 데이터를 유동적으로 관리한다
state가 변경될때마다 컴포넌트가 다시 렌더링 된다.</p>
<p>CRA란</p>
<ul>
<li>react 프로젝트를 손쉽게 생성할 수 있도록 도와주는 보일러플레이트</li>
<li>프로젝트 생성에 필요한 다양한 기능을 command로 제공함</li>
</ul>
<p>장점 1. 개발자가 온전히 리액트 앱 개발에 집중할 수 있도록 함
상대적으로 덜 중요한 코드는 노출되지 ㅇ낳음
강력한 command지원
2. 대부분의 모든 브라우저에서 해석될 수 있또록 transcompile 지원</p>
<h2 id="jsx란">JSX란</h2>
<ul>
<li>JSX는 함ㅁ수 호출과 객체 생성을 위한 문법적 편의를 제공하는 javascript의 확장</li>
<li>html과 비슷하게 생겼으나 javascript이고 html과 다른 부분이 있음<pre><code>const App = () =&gt; {
  return (
  &lt;div&gt;
  &lt;p&gt;안녕&lt;p&gt;
  &lt;MyComponent&gt;반가워&lt;/MyComponent&gt;
  &lt;/div&gt;
  );
}</code></pre><h4 id="jsx의-장점">JSX의 장점</h4>
</li>
</ul>
<ol>
<li>개발자 편의성 향상</li>
<li>협업에 용이 / 생산성 향상</li>
<li>문법 오류와 코드량 감소</li>
</ol>
<h4 id="jsx-특징--html과-차이점">JSX 특징 / HTML과 차이점</h4>
<ol>
<li>HTML 태그 내에 javascript 연산</li>
<li>class -&gt; className</li>
<li>스타일은 object로</li>
<li>닫는 태그 필수</li>
<li>최상단 element는 반드시 하나 </li>
</ol>
<h4 id="component란">Component란</h4>
<ol>
<li>React에서 페이지를 구성하는 최소단위</li>
<li>Component의 이름은 대문자로 시작</li>
<li>Class Component / Function Component로 나뉨</li>
<li>Controlled Component / Uncontrolled Component</li>
</ol>
<h4 id="component의-특징">Component의 특징</h4>
<ol>
<li>컴포넌트끼리 데이터를 주고 받을 땐 Props</li>
<li>컴포넌트 내에서 데이터를 관리할 땐 State</li>
<li>데이터는 부모 -&gt; 자식으로만 전달</li>
</ol>
<p>React를 사용하는 이유들을 정리하면 <code>사용자와의 소통을 UI로 쉽게 구현하고 대규모의 웹페이지를 관리하기 위해 사용한다</code>라고 말할 수 있다.</p>
<h4 id="react의-장점">React의 장점</h4>
<ul>
<li>React의 Virtual DOM은 사용자 경험을 향상하고 개발자의 작업 속도를 높입니다. Virtual DOM이란 가상적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 실제 DOM과 동기화하는 프로그래밍 개념이다.</li>
<li>React 컴포넌트의 재사용은 개발 시간을 크게 절약합니다.</li>
<li>단방향 데이터 흐름을 통해 안정적인 코드를 제공합니다. 단방향 데이터 흐름은 데이터는 항상 일정한 장소에 있고, 그 장소에서만 변경이 가능한 것을 의미합니다.</li>
<li>오픈 소스이며 페이스북 라이브러리이기 때문에 지속해서 개발되고 커뮤니티에 공개됩니다.</li>
<li>Hooks를 이용해 컴포넌트의 상태를 쉽게 관리할 수 있습니다.</li>
<li>여러 개발 도구를 지원합니다. 예를 들어 크롬에서는 React Developer Tools라는 확장 프로그램을 제공합니다</li>
</ul>
<p>React는 앱 작성 방식을 정의하는 라이브러리입니다. 이는 데이터가 앱에 사용되는 방식과 그 데이터가 변화하는 결과에 따른 ui 변경 방법에 대해 명확한 규칙을 설정하여 수행한다. 반면 자바스크립트는 규칙을 설정하지 않은 스크립트 언어라고 할 수 있다. 따라서 이러한 라이브러리 없이 작성된 앱은 더 자유로울 수 있지만, 정해진 것이 없기 때문에 코드를 작성하다가 길을 잃어버리기 쉽다. </p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep 6]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep-6</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep-6</guid>
            <pubDate>Sun, 12 Nov 2023 14:50:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/a635650b-84ff-4b03-9196-100d04016f50/image.PNG" alt=""></p>
<p>1차 프로젝트가 완료 되었다.
많은 아쉬움이 남지만 열심히 이끌어준 팀원들 덕에 더 아쉬움이 남는것 같다.</p>
<h3 id="많은-시간을-할애한-컴포넌트-화면-구현">많은 시간을 할애한 컴포넌트, 화면 구현</h3>
<p>화면 구현에 너무 많은 시간을 소요했다. 
클론 코딩을 하여 디자인 시간을 줄이는 것은 좋았지만 금같은 시간을 결국 만들지 않을 화면에 써버렸다.
버려진 시간은 결국 다른 일을 할 시간을 줄어들고 마무리하는 시간을 확보해두어야 한다. 
디자인이 정해져있다해도 우리의 시간은 2주였고, 모든걸 만들어내기는 불가능이었다.
불가능으로 판정되는 것은 과감히 진행에서 삭제시켜야한다.</p>
<h3 id="안되는건-붙잡지-말고-팀원-코치님께-물어보기">안되는건 붙잡지 말고 팀원, 코치님께 물어보기</h3>
<p>검색을 못하는 사람(..예를 들면 나) 는 빨리 팀원들에게 물어보는게 좋았고, 미리 팀원들도 공지를 했던 사항이지만
막상 당일이 되니 모두 바쁜게 보여서 물어보지를 못했다.
하지만 팀원, 코치님들은 못해도 30분 안에는 무조건 해주시니 꼭 물어봐야 한다.
만약 부담스럽다면 정해진 회의 시간, 오프라인으로 만나는 시간에 질문을 정해가서 물어보는게 좋을 것 같다.
열심히 하려고 물어보는 팀원을 나쁘게 볼 사람은 없다.</p>
<h3 id="사소한-것-하나">사소한 것 하나</h3>
<p>주문내역 테이블을 쿼리셀럭터, fetch 함수를 이용하여 api 호출하였는데, 팀원분의 코드를 따라쓴건데도 오류가 나고, 이유를 알아내기 어려워 코치님께 물어봤는데
class 값을 id 값으로 잘못 적어 난 오류였다.
<img src="https://velog.velcdn.com/images/vision_ing/post/ca79b4d9-cd3d-4d32-af78-950726d7b844/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/vision_ing/post/7ebece1b-2c44-46f8-a816-ea20a26e0f88/image.png" alt=""></p>
<p>문제가 된 그 부분</p>
<p>해결되고 너무 허무하기도 했지만 당연히 지켰을거라고 생각한 곳에서 오류가 나니 반성이 되기도 했다.</p>
<h3 id="막바지에-갈수록-작업현황-공유와-역할-분담은-확실히">막바지에 갈수록 작업현황 공유와 역할 분담은 확실히</h3>
<p>팀원분 중 리더쉽이 있으신 분이 계셔서 다행이었다.
그분 덕에 그나마 중간에 지체되지 않고 끝까지 끌고 나갈 수 있었던거라 생각한다.
막바지에 갈수록 각자의 많은 작업양에 무엇이 제대로 안되고 무엇이 제대로 되어 남은 양은 어떤지, 할 수 있는지, 지체되지 않는지의 공유가 필요하다.
각자 공유를 한 뒤 시간이 여유 있으신 분은 작업이 더딘 분의 남은 작업을 도와주며 팀플을 마무리하여야한다. 이것은 어쨌든 팀프로젝트니까.</p>
<h3 id="git은-확실하게-배울-수-있는-시간-_">git은 확실하게 배울 수 있는 시간 ^_^</h3>
<p>정말 무한(사실 오바임)의 반복으로 깃은 이제 이해하고 다음 프로젝트에서도 무리 없이 활용할 수 있을 것 같다.
역시 반복이 짱이다. </p>
<p>다음 프로젝트에서는 좀 더 발전된 모습으로 팀에 기여를 하고 싶다.</p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.5]]></title>
            <link>https://velog.io/@vision_ing/elice-track-ep.5</link>
            <guid>https://velog.io/@vision_ing/elice-track-ep.5</guid>
            <pubDate>Sun, 12 Nov 2023 12:54:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/f942e1f4-247f-4936-9bbf-63e34548d070/image.PNG" alt=""></p>
<h2 id="javascript-uri-url-querystring-과-인코딩디코딩-정리">Javascript: URI, URL, QueryString 과 인코딩/디코딩 정리</h2>
<p>URI(Uniform Resource Identifier)
: 인터넷에 있는 자원을 나타내는 유일한 주소</p>
<ul>
<li><p>URI, URL(Uniform Reslurce Locator), URN(Uniform REsource Name)의 차이
<img src="https://velog.velcdn.com/images/vision_ing/post/e734bf3a-c2a2-42fd-94b0-fb54f65f5136/image.png" alt=""></p>
</li>
<li><p>연관된 개념인 Scheme(Protocol), Host(Domain), Port, Path, Query String, Search, Fragment
<img src="https://velog.velcdn.com/images/vision_ing/post/5a128bcb-5398-440d-825f-c7958ba7ec5c/image.png" alt=""></p>
</li>
</ul>
<h3 id="uri-인코딩이란">URI 인코딩이란?</h3>
<p>: URI의 문자들을 이스케이프 처리하는 것</p>
<h3 id="이스케이프-처리란">이스케이프 처리란?</h3>
<p>: 어떤 시스템에서도 읽을 수 있는 아스키 문자셋으로 반환하는 것</p>
<h3 id="즉-uri-인코딩이란">즉, URI 인코딩이란?</h3>
<p>: 네트워크 등을 통해 정보를 공유할 때, 어떤 시스템에서도 읽을 수 있도록 URI의 문자들을 ASCII 문자셋으로 변환하는 것이다.
: 예를 들어, UTF-8 한글의 &#39;가&#39;는 3바이트의 아스키 문자셋 %EC %92 등으로 인코딩 된다</p>
<h3 id="uri-디코딩이란">URI 디코딩이란?</h3>
<p>: 디코딩은 반대로 인코딩된 아스키 문자셋을 해석하여 한글 &quot;가&quot;로 되돌리는 것이다.</p>
<h3 id="javascript의-인코딩디코딩-함수">Javascript의 인코딩/디코딩 함수</h3>
<p>: 자바스크립트는 빌트인(내장) 전역 함수로 URI 문자열을 인코딩하고, 다시 디코딩하는 함수를 제공한다.</p>
<ol>
<li><p>encodeURI() / decodeURI()
: 보통 URI에서 의미가 있는 . : / ? = &amp;, 영어 등은 그대로 남겨두고 인코딩한다.
1) encodeURI(&#39;인코딩 이전 URI&#39;) =&gt; 이스케이프 처리된 URI
2) decodeURI(&#39;인코딩 완료 URI&#39;) =&gt; 이스케이프 처리 이전 URI</p>
</li>
<li><p>encodeURIComponent() / decodeURIComponent()
: . : / ? = &amp; 등 조차 모두 인코딩한다. (영어는 남겨둔다.
1) encodeURIComponent(&#39;인코딩 이전 URI&#39;) =&gt; 이스케이프 처리된 URI
2) decodeURIComponent(&#39;인코딩 완료 URI&#39;) =&gt; 이스케이프 처리 이전 URI</p>
</li>
</ol>
<h2 id="콜백함수">콜백함수</h2>
<p>다음과 같이 비동기로 작동되는 함수가 있다.
이 비동기 함수는 2초 뒤에 Elice라는 이름을 인자로 받은 콜백함수의 인자로 넘겨준다.</p>
<pre><code>function getName(cb) {
    setTimeout(() =&gt; {
    cb(&quot;Elice&quot;);
    }, 2000);
}</code></pre><p>앞선 함수를 실행하려면 다음과 같이 getName 함수에 콜백 함수를 넣어서 사용할 수 있다.</p>
<pre><code>getName((name) =&gt; {
    console.log(name);
    })
</code></pre><p>만약 getName 함수를 이용해서 Elice라는 이름을 3번 출력하려면?</p>
<pre><code>getName((name) =&gt; {
    console.log(name);
})

getName((name) =&gt; {
    console.log(name);
})

getName((name) =&gt; {
    console.log(name);
})</code></pre><p>하지만 앞선 방법으로 콜백함수를 호출하면 각 함수에 대한 데이터를 사용할 수 없다. 예를들어 이름, 나이, 주소가 저장된 데이터를 비동기적으로 가져와야 한다고 가정해본다.</p>
<pre><code>function getName(cb) {
    setTimeout(() =&gt; {
        cb(&quot;Elice&quot;);
    }, 2000);
}

function getAge(cb) {
    setTimeout(() =&gt; {
        cb(6);
    }, 2000);
}

function getAddress(cb) {
    setTimeout(() =&gt; {
        cb(&quot;Seoul&quot;);
    }, 2000);
}</code></pre><p>해당 정보를 출력하고자 하지만 console.log를 한번만 사용하려면 어떻게 해야될까?</p>
<pre><code>getName((name) =&gt; {
    getAge((age) =&gt; {
        getAddress((address) =&gt; {
            console.log(name, age, address)
        })
    })
})</code></pre><p>앞선 코드처럼 콜백함수 안에 콜백 함수를 반복하여 호출해야 name, age, address를 한꺼번에 접근할 수 있다. 비동기 함수가 3개 쓰이고, 각 2초씩 걸리기 때문에 6초 뒤에 Elice 6 Seoul이라는 log가 나오게 될 것이다.</p>
<p><img src="https://velog.velcdn.com/images/vision_ing/post/8b811886-266f-490f-9bad-7fef1b5aae3d/image.PNG" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.4]]></title>
            <link>https://velog.io/@vision_ing/%EC%97%98%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%9E%99-%EB%84%A4%EB%B2%88%EC%A7%B8-%EC%9D%B4%EC%95%BC%EA%B8%B0</link>
            <guid>https://velog.io/@vision_ing/%EC%97%98%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%9E%99-%EB%84%A4%EB%B2%88%EC%A7%B8-%EC%9D%B4%EC%95%BC%EA%B8%B0</guid>
            <pubDate>Fri, 10 Nov 2023 14:31:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/99bf0b3b-9e7e-47f5-8814-83822ac387ae/image.PNG" alt=""></p>
<h3 id="createelement-innerhtml">createElement, innerHTML</h3>
<ol>
<li><p>innerHTML이 가독성이 좋다
바닐라 JS에서도 JSX와 비슷하게 코드 스타일을 구성 할 수 있어서 아무래도 유지보수는 훨씬 편하긴하다.</p>
</li>
<li><p>createElement가 성능은 더 좋다
innerHTML을 사용할 경우 기준이 되는 요소의 DOM 내부를 전부 재분석하기 때문에 createElement에 비해서 성능이 떨어진다.</p>
</li>
<li><p>innerHTML이 비교적 불안정하다.
innerHTML의 경우에는 데이터베이스처럼 신뢰할 수 있는 소스에서만 사용되어야만하며 만약 불안정한 소스로 부터 데이터를 받는다면 악성코드가 심어질 수도 있다.</p>
</li>
</ol>
<h2 id="fetch-함수">fetch 함수</h2>
<p>원격 api 호출하면 제일 먼저 떠오르는 것이 request나 axios. jQuery와 같은 라이브러리일 것입니다. 브라우저에서 fetch() 함수를 지원하기 이 전에는 클라이언트 단에서 직접 http 요청하고 응답을 받는 게 상당히 복잡해서 이러한 라이브러리를 사용하는 것이 합리적이었다. 하지만 요즘에는 라이브러리의 도움 없이도 브라우저에서 내장된 fetch() 함수를 이용하면 대부분의 경우 충분하기 때문에 오히려 이러한 라이브러리를 사용하는 것이 자바스크립트 번들(bundle) 파일의 크기만 늘려서 낭비가 될 수 있다.</p>
<h3 id="fetch-사용법">fetch 사용법</h3>
<p>fetch 함수는 첫번째 인자로 url, 두번째 인자로 옵션 객체를 받고, Promise 타입의 객체를 반환한다. 반환된 객체는, api 호출이 성공했을 경우에는 응답(response) 객체를 resolve하고, 실패했을 경우에는 예외(error) 객체를 reject합니다.</p>
<pre><code>fetch(url, options)
    .then((response) =&gt; console.log(&quot;reponse:&quot;, response))
    .catch((error) =&gt; console.log(&quot;error:&quot;, error))</code></pre><p>옵션(options) 객체에는 http 방식(method), http 요청 헤더(headers), http 요청 전문(body) 등을 설정해줄 수 있다. 응답(response) 객체로부터는 http 응답 상태(status), http 응답 헤더(headers), http 응답 전문(body) 등을 읽어올 수 있다.
참고로 fetch() 함수는 엄밀히 말해, 브라우저의 window 객체에 소속되어 있기 때문에 window.fetch() 로 사용되기도 한다.</p>
<h3 id="get-호출">get 호출</h3>
<p>fetch() 함수는 디폴트로 GET 방식으로 작동하고 GET 방식은 요청 전문을 받지 않기 때문에 옵션 인자가 필요가 없다</p>
<pre><code>fetch(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;).then((response) =&gt;
  console.log(response)
);</code></pre><h3 id="post-호출">POST 호출</h3>
<p>원격 API에서 관리하고 있는 데이터를 생성해야 한다면 요청 전문을 포함할 수 있는 POST 방식의 HTTP 통신이 필요할 것이다.</p>
<p>동일한 API를 대상으로 이번에는 새로운 포스팅를 생성하기 위해서 fetch() 함수를 사용해보겠습니다. method 옵션을 POST로 지정해주고, headers 옵션을 통해 JSON 포맷을 사용한다고 알려줘야 하며, 요청 전문을 JSON 포맷으로 직렬화화여 가장 중요한 body 옵션에 설정해준다.</p>
<h3 id="html-제어와-관련된-메소드">HTML 제어와 관련된 메소드</h3>
<p>.affter()
해당 요소 뒤에 내용(html()과 같은 기능)을 추가한다.</p>
<p>.before()
선택된 대상의 전에 html을 삽입한다.
해당 요소 앞에 내용을 추가한다.</p>
<p>.html()
.text() 메소드와 기능은 유사하지만 삽입하는 내용에 html 태그가 있다면 
태그가 적용되며 text가 변경된다.</p>
<p>.prepend()
가리킨 대상의 자식 요소의 맨 앞에 내용을 추가한다.</p>
<p>.append()
선택된 대상의 자식 객체 제일 마지막에 html삽입한다.</p>
<p>.wrap()
wrap의 타겟이 된 요소를 해당 요소로 감싼다. = 선택된 요소의 부모 요소를 생성한다.</p>
<p>.unwrap()
선택한 요소의 부모 요소를 삭제한다 = 선택한 요소의 부모 요소를 삭제한다</p>
<p>.remove()
태그를 포함한 요소 전체를 제거한다.</p>
<p>.empty()
해당 요소의 내용만을 지운다.</p>
<p>.detach()
잘라내기 기능과 같다.
잘라낸 부분을 다른 변수에 저장 가능하다.</p>
<p>.on()
동적으로 html을 생성시 인식되지 않을 경우 사용하며 이벤트 바인딩을 해준다.</p>
<p>.ready()
작성한 html이 웹에 로딩이 완료가 되면 매개 변수로 전달된 함수를 실행하는 메소드이다.
더 추가적으로 말하면 페이지에 모든 외부 리소스가 아닌 DOM 객체만 로드가 되어도 실행이 된다.</p>
<p>.load()
ready()와 다르게, 해당 페이지의 모든 외부 리소스가 포함된 모든 요소가 브라우저에 로드 되어야 실행하는 메소드이다. </p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[elice track ep.3]]></title>
            <link>https://velog.io/@vision_ing/%EC%97%98%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%9E%99-%EC%84%B8%EB%B2%88%EC%A7%B8-%EC%9D%B4%EC%95%BC%EA%B8%B0</link>
            <guid>https://velog.io/@vision_ing/%EC%97%98%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%9E%99-%EC%84%B8%EB%B2%88%EC%A7%B8-%EC%9D%B4%EC%95%BC%EA%B8%B0</guid>
            <pubDate>Mon, 06 Nov 2023 15:52:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/vision_ing/post/9e2baa1a-1016-4c59-b5b5-704236af548b/image.PNG" alt=""></p>
<p>내가 맡았던 부분은 고객 리뷰, 게시판 쪽이었는데 과감히 삭제하기로 결정이 났다.
쇼핑몰을 만들 때 제일 중요한 기능들을 중점으로 두고, 시간이 남으면 후기, 게시판을 만들기로 했다.
이럴 땐 우물쭈물하지않고 과감히 결정을 내려주는 팀원들이 중요하다고 생각한다.</p>
<p>다시 관리자 페이지를 맡기로 하여 html, css를 제작하여야했다.</p>
<p>디자인을 어떻게 짜야하나 막막해하던 찰나
<img src="https://velog.velcdn.com/images/vision_ing/post/a4fa609a-6b28-4306-8b8b-18ae7ab978a1/image.JPG" alt=""><img src="https://velog.velcdn.com/images/vision_ing/post/8b133960-aeb5-4779-a81c-bf0edbb84fd0/image.JPG" alt="">
<img src="https://velog.velcdn.com/images/vision_ing/post/46a81ac5-d03d-45fb-8602-3c59d431fb48/image.JPG" alt=""></p>
<p>대충 그림을 그리고 있자하니 옆에서 충고가 들려온다.</p>
<h2 id="-템플릿을-활용하거라-">~ 템플릿을 활용하거라 ~</h2>
<p><a href="https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/">https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/</a></p>
<p>그렇게 찾아낸 부트스트랩 템플릿인 나이스어드민이다.
<img src="https://velog.velcdn.com/images/vision_ing/post/c9b72dc9-0d41-4670-9f9d-ac8cc609a1e5/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/vision_ing/post/e4693d71-d846-48bb-ad86-063581a41d5c/image.png" alt="">
<img src="https://velog.velcdn.com/images/vision_ing/post/cb63208a-4576-42bb-8e57-c6393121cb29/image.png" alt="">
<img src="https://velog.velcdn.com/images/vision_ing/post/f8c600e3-66df-4d0b-8e16-0903dfa2b147/image.png" alt=""></p>
<p>깔끔한 디자인과 다양한 템플릿으로 시간 절약하며 관리자 페이지를 만들 수 있었다.
남은 것은 js 부분..!
그리고 아직 api명세서가 나오지 않아 어디서부터 손을 대야하는지 감이 안잡히는 부분이다.</p>
<p>일단 내가 해야할 것은 
api 명세서가 나오면 명세서 확인하기
fetch 방법 배우기
다른 사람이 작성한 Js 를 확인하며 어떻게 썼나 확인하고 배우는 것이다.</p>
<p>그리고 놓쳤던 부분인 수정, 추가버튼을 html로 구현했다.
<img src="https://velog.velcdn.com/images/vision_ing/post/5bc734cd-155d-4198-b233-ee50800413d8/image.png" alt="">
<img src="https://velog.velcdn.com/images/vision_ing/post/a5c2a9c1-3f10-4133-bd89-0beb135dc41f/image.png" alt="">
<img src="https://velog.velcdn.com/images/vision_ing/post/e01b9a9f-808e-4109-a52b-af6d2c798efc/image.png" alt=""></p>
<p><a href="https://elice.training/track/sw?utm_source=sw7&amp;utm_medium=blog&amp;utm_campaign=challenge&amp;utm_content=rjfwrl615"><img src="https://velog.velcdn.com/images/vision_ing/post/ac76d4ca-c9b2-405b-a48c-269f0c9c1a9e/image.PNG" alt="링크"></a></p>
]]></description>
        </item>
    </channel>
</rss>