<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hi-yjs.log</title>
        <link>https://velog.io/</link>
        <description>Front-end Developer 👩‍💻</description>
        <lastBuildDate>Sun, 04 Apr 2021 12:02:05 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. hi-yjs.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hi-yjs" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[RoR/React] 쇼핑몰 구현하기]]></title>
            <link>https://velog.io/@hi-yjs/RoRReact-%EC%87%BC%ED%95%91%EB%AA%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hi-yjs/RoRReact-%EC%87%BC%ED%95%91%EB%AA%B0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 04 Apr 2021 12:02:05 GMT</pubDate>
            <description><![CDATA[<h3 id="🌱-프로젝트기간">🌱 프로젝트기간</h3>
<p>2021.03.15 ~ 2021.04.07</p>
<h3 id="🌱-프로젝트-기획">🌱 프로젝트 기획</h3>
<p>프론트앤드는 리액트, 백앤드는 루비온레일즈를 사용하여 상품리스트, 상세페이지, 찜리스트, 장바구니가 있는 쇼핑몰 웹앱 구현하기</p>
<h3 id="🌈-frontend-기술스택">🌈 Frontend 기술스택</h3>
<p>React.js
Framework7
Tailwind CSS</p>
<h3 id="🌈-backend-기술스택">🌈 Backend 기술스택</h3>
<p>RubyOnRails</p>
<h3 id="📕-frontend-기억하고-싶은-코드">📕 Frontend 기억하고 싶은 코드</h3>
<pre><code class="language-jsx">//itemlist.jsx
 useEffect(() =&gt; {
    setCurrentPageNum(1);
    const fetchData = async () =&gt; {
      try {
        const res = await getItems({
          q: {
            category_id_eq: categoryID,
            price_lteq: priceMax,
            price_gteq: priceMin,
          },
          page: 1,
        });
        setItemList(res.data);
      } catch (error) {
        console.log(error);
      }
    };
    fetchData();
  }, [categoryID, priceMin, priceMax]);</code></pre>
<p><code>UseEffect</code>는 categoryID가 바뀔때, 최소 가격, 최대 가격이 바뀔때를 계속 바라보고 있다가 만약 바뀔 경우 (사용자가 카테고리나 가격 range를 바꿀경우) <code>page: 1</code>로 백앤드에 요청한다. 만약 <code>page: 1</code>로 요청하지 않고 현재 페이지 상태로 요청을 보낸다면 1페이지에 해당하는 데이터가 오지 않고 다른페이지에 해당하는 데이터가 오게 되어서 에러가 난다.</p>
<h3 id="📗-backend-기억하고-싶은-코드">📗 Backend 기억하고 싶은 코드</h3>
<p>👍 모든 orders중에서 해당 유저에 해당하는 order만 찾기 </p>
<pre><code class="language-jsx">all_orders = Order.where(user_id: user.id)</code></pre>
<p>👍 찾은 orders중에서 status_id가 1인것을 찾기 (하나 밖에 없음)</p>
<pre><code class="language-jsx"> current_order = all_orders.find_by(status_id: 1)</code></pre>
<p>👍 상품들중에서 프론트에서 보낸 아이템 ID로 상품 찾기</p>
<pre><code class="language-jsx">item = Item.find((line_item_params[:item_id]))</code></pre>
<h3 id="👻-구현한-기능ui">👻 구현한 기능/UI</h3>
<ul>
<li>메인페이지</li>
<li>상품리스트 - 카테고리/가격 필터링, 무한스크롤</li>
<li>상세페이지</li>
<li>찜리스트</li>
<li>장바구니</li>
<li>결제페이지</li>
<li>리뷰페이지</li>
<li>리뷰리스트</li>
</ul>
<h4 id="🍎-메인페이지">🍎 메인페이지</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/9068f3f3-9003-4b2b-8314-7d0234a55e47/Screen%20Shot%202021-04-04%20at%208.24.45%20PM.png" alt=""></p>
<h4 id="🍎-nav-bar">🍎 Nav Bar</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/290162e7-61e7-4f1e-87ff-fa483d1f4fcd/shopnavbar.gif" alt=""></p>
<h4 id="🍎-상품리스트---카테고리가격">🍎 상품리스트 - 카테고리/가격</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/be50db2d-b3a2-40bb-a8d3-d34cf56c1191/categoryprice.gif" alt=""></p>
<h4 id="🍎-상품리스트---무한스크롤">🍎 상품리스트 - 무한스크롤</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/857a400b-aa5d-4f50-9884-0be2053a993c/%E1%84%86%E1%85%AE%E1%84%92%E1%85%A1%E1%86%AB%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%A9%E1%86%AF.gif" alt=""></p>
<h4 id="🍎-상품리스트---장바구니에-담기-찜하기">🍎 상품리스트 - 장바구니에 담기, 찜하기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/399eb331-f3a4-43b0-998b-b515eaf3b112/itemlistcartlike.gif" alt=""></p>
<h4 id="🍎-상품상세페이지">🍎 상품상세페이지</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/3394f0ea-91e7-4ecd-88bb-29a46665f140/itemdetail.gif" alt=""></p>
<h4 id="🍎-찜리스트">🍎 찜리스트</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/f29d79d8-a6ca-43ed-9d1b-b5c32409a7e4/wishlist.gif" alt=""></p>
<h4 id="🍎-장바구니">🍎 장바구니</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/f8bd4000-ec76-4608-9941-79fd4e11a22e/itemlistcart.gif" alt=""></p>
<h4 id="🍎-결제페이지">🍎 결제페이지</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/55815859-f9a4-42ca-a96f-772e5872cd52/payment.gif" alt=""></p>
<h4 id="🍎-마이페이지">🍎 마이페이지</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/a15a3cd7-ed05-4a78-9a21-aded6b509ba6/mypagelist.gif" alt=""></p>
<h4 id="🍎-리뷰-쓰기">🍎 리뷰 쓰기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/36a76b63-d2c5-47b1-ba48-65a8d1ce6064/reviewmodal.gif" alt=""></p>
<h4 id="🍎-리뷰리스트">🍎 리뷰리스트</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/285efea8-60e9-4d5c-90d1-9cee8ba9ea81/reviewlistlist.gif" alt=""></p>
<h3 id="❣️-최종후기">❣️ 최종후기</h3>
<p>처음에는 백앤드를 하나도 모른채로 시작하게 되어서 부담도 많이 되고 과연 내가 이걸 할수있을까...? 라는 생각이 들었었지만 시간이 지나면 지날수록 백앤드를 이렇게 경험하는게 프론트앤드에게는 굉장히 소중한 경험이라는 것을 깨달았다. 백앤드를 공부하면서 프론트앤드에서 어떻게 데이터를 보내야하는지, 어떻게 받아야하는지, 어떻게 UI와 기능을 짜야 백앤드와 더 원활하게 소통하고 협업할수 있는지 알게되었다. 오히려 백앤드를 배우면서 프론트앤드쪽 지식이 더 느는 느낌 😅
비록 짧은 시간에 후다닥 배운 백앤드(...와 프론트앤드)여서 코드가 깔끔하지 못하고 데이터가 너저분하지만 그래도 어떻게 데이터를 정리해서 프론트에게 뿌려줄수 있다는것에 만족한다. 이번 기업협업을 통해 더 좋은 개발자가 되려면 프론트앤드에만 치우치지 않고 백앤드도 꾸준하게 공부해야 한다는것을 알게된 좋은 시간이였다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Recoil] Facebook이 실험중인 상태관리 라이브러리 Part.2 ]]></title>
            <link>https://velog.io/@hi-yjs/Recoil-Facebook%EC%9D%B4-%EC%8B%A4%ED%97%98%EC%A4%91%EC%9D%B8-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Part.2</link>
            <guid>https://velog.io/@hi-yjs/Recoil-Facebook%EC%9D%B4-%EC%8B%A4%ED%97%98%EC%A4%91%EC%9D%B8-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Part.2</guid>
            <pubDate>Sun, 28 Mar 2021 13:26:30 GMT</pubDate>
            <description><![CDATA[<h3 id="code-🎈">Code 🎈</h3>
<p>이번 프로젝트를 하면서 웹앱의 특성상 <code>history.push</code>를 하면서 다른 페이지로 안넘어가고 탭을 이용해서 넘어가기 때문에 상품리스트에서 상품을 담고 장바구니 탭으로 넘어가면 바로 업데이트가 안되어있고 새로고침을 해야 장바구니가 업데이트되는 문제를 경험했다. 물론 f7router를 이용하여 강제 새로고침을 할수 있지만, 이런 경우에는 상태관리 라이브러리를 쓰는게 맞다는 조언에 따라 Recoil을 처음 쓰게 되었다.</p>
<h4 id="👻-아직-공식문서를-더-봐야하지만-아주-간단하게-recoil을-쓸수있는-방법-👻">👻 (아직 공식문서를 더 봐야하지만) 아주 간단하게 Recoil을 쓸수있는 방법! 👻</h4>
<ol>
<li>먼저 src 폴더 밑에 <code>state.js</code> 파일을 만들고 여러 파일에서 상태관리를 해야하는 state를 정해준다. 밑의 경우에는 cartlist의 상태관리가 필요하기때문에 <code>cartlistState</code>를 선언해주었다. default에는 state의 초기값이 들어간다.</li>
</ol>
<pre><code class="language-jsx">// state.js
import { atom } from &quot;recoil&quot;;

export const cartlistState = atom({
  key: &quot;cartlistState&quot;,
  default: [],
});
</code></pre>
<ol start="2">
<li><p>cartlist에 상태 변화가 일어나는 지점인 <code>itemlist.jsx</code>에서 밑과 같이 import 해준다. </p>
<pre><code class="language-jsx">// itemlist.jsx
import { useRecoilState } from &quot;recoil&quot;;
import {
cartlistState,
} from &quot;../../src/state&quot;;</code></pre>
</li>
<li><p><code>useState([])</code>가 아닌 <code>useRecoilState(cartlistState)</code>를 사용한다. <code>cartlistState</code>는 <code>cartlist</code>의 초기값이며 <code>state.js</code>에서 <code>[]</code>로 선언해주었었다.</p>
</li>
</ol>
<pre><code class="language-jsx">// itemlist.jsx
const itemlist = () =&gt; {

  const [cartlist, setCartList] = useRecoilState(cartlistState);

</code></pre>
<ol start="4">
<li>장바구니에 담기 버튼을 누를때마다 백앤드에게 아이템의 ID를 보내주고 새로운 장바구니 리스트를 다시 받을때 <code>setCartList</code>를 통해서 장바구니 리스트를 업데이트 시켜준다.</li>
</ol>
<pre><code class="language-jsx">// itemlist.jsx
  const addToCart = (e) =&gt; {
    const data = {
      item_id: e.target.id,
    };
    axios({
      method: &quot;post&quot;,
      url: &quot;http://localhost:3000/line_items/newitem&quot;,
      headers: { Authorization: localStorage.getItem(&quot;practice_token&quot;) },
      data: data,
    }).then((res) =&gt; {
      setCartList(res.data);
    });
  };

}</code></pre>
<ol start="5">
<li>이제 실제 장바구니 js파일에서 똑같이 import해주고 <code>useRecoilState</code>로 상태관리를 하게 된다면 <code>itemlist.jsx</code>에서 바뀐 장바구니 리스트가 바로 바로 업데이트 되는것을 확인할수 있다!</li>
</ol>
<pre><code class="language-jsx">// cartlist.jsx
import { useRecoilState } from &quot;recoil&quot;;
import { cartlistState } from &quot;../../src/state&quot;;

const cart = () =&gt; {
  const [cartlist, setCartlist] = useRecoilState(cartlistState);

}</code></pre>
<ol start="6">
<li>결과물 🌈</li>
</ol>
<p><img src="https://images.velog.io/images/hi-yjs/post/b70dd5df-f575-46a0-8fc5-bf86d2e45f5e/recoilex.gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Recoil] Facebook이 실험중인 상태관리 라이브러리 Part.1 ]]></title>
            <link>https://velog.io/@hi-yjs/Recoil-Facebook%EC%9D%B4-%EC%8B%A4%ED%97%98%EC%A4%91%EC%9D%B8-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Part.1</link>
            <guid>https://velog.io/@hi-yjs/Recoil-Facebook%EC%9D%B4-%EC%8B%A4%ED%97%98%EC%A4%91%EC%9D%B8-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-Part.1</guid>
            <pubDate>Sun, 28 Mar 2021 13:26:26 GMT</pubDate>
            <description><![CDATA[<h3 id="recoil이란-🎈">Recoil이란? 🎈</h3>
<p>2020년에 소개된 Facebook에서 실험용으로 만든 React 상태 관리 라이브러리</p>
<h3 id="만들어지게-된-배경-🎈">만들어지게 된 배경 🎈</h3>
<p>Recoil은 state를 업데이트할때 공통 부모로 상태를 계속 끌어올리면서 너무 큰 dom tree가 계속해서 re-render 되고 상태가 만들어지고 리덕스를 사용하는 유저들의 불만이 꾸준히 증가하면서 페이스북이 오직 리액트를 위한 API와 동작을 최대한 React스럽게 유지하고 개선하려고 발표한 라이브러리다.</p>
<p>Recoil을 만든 Dave McCabe가 한 말에 의하면 </p>
<blockquote>
<p>&quot;Well, I know that on one tool we saw a 20x or so speedup compared to using Redux. This is because Redux is O(n) in that it has to ask each connected component whether it needs to re-render, whereas we can be O(1).&quot;
&quot;글쎄요, 한 툴에서 Redux를 사용할 때보다 20배 정도 속도가 빨라진 것으로 알고 있습니다. 이는 Redux는 O(n)이기 때문에 연결된 각 구성 요소에 재렌더가 필요한지 물어봐야 하는 반면 우리는 (Recoil은) O(1)이기 때문이다.</p>
</blockquote>
<p>Recoil이 O(1)이라는 말은 데이터가 저장되어 있는 atom을 수정할때 그 atom을 바라보는 컴포넌트들만 </p>
<h3 id="atom이란-🎈">Atom이란 🎈</h3>
<p>Atom은 어떤 컴포넌트에서도 사용하고 수정할수 있는 상태다. 만약 Atom이 업데이트 된다면 그 Atom을 바라보고 있는 컴포넌트들이 re-render 된다. </p>
<pre><code class="language-jsx">// 출처: Recoil 공식문서
const textState = atom({
  key: &#39;textState&#39;, // unique ID (with respect to other atoms/selectors)
  default: &#39;&#39;, // default value (aka initial value)
});</code></pre>
<p>Atom은 위와 같은 형태로 정의한다. <code>key</code>에는 다른 컴포넌트에서 사용할 state의 이름, <code>default</code>에는 state의 초기값을 설정한다.</p>
<h3 id="userecoilstate-🎈">UseRecoilState 🎈</h3>
<p>이렇게 정의한 atom을 컴포넌트에서 사용할때는 설정해놓은 key값과 <code>useRecoilState</code>를 import 해와서 사용한다. </p>
<pre><code class="language-jsx">import { textState } from &#39;/state.js&#39;
import { useRecoilState } from &quot;recoil&quot;;

// 출처: Recoil 공식문서
function TextInput() {
  const [text, setText] = useRecoilState(textState);

  const onChange = (event) =&gt; {
    setText(event.target.value);
  };

  return (
    &lt;div&gt;
      &lt;input type=&quot;text&quot; value={text} onChange={onChange} /&gt;
      &lt;br /&gt;
      Echo: {text}
    &lt;/div&gt;
  );
}</code></pre>
<p>참고:
<a href="https://recoiljs.org/">https://recoiljs.org/</a>
<a href="https://velog.io/@wooder2050/%EB%A6%AC%EC%BD%94%EC%9D%BCRecoil%EB%8A%94-%EC%99%9C-%EB%A7%8C%EB%93%A0-%EA%B1%B4%EB%8D%B0">https://velog.io/@wooder2050/%EB%A6%AC%EC%BD%94%EC%9D%BCRecoil%EB%8A%94-%EC%99%9C-%EB%A7%8C%EB%93%A0-%EA%B1%B4%EB%8D%B0</a>
<a href="https://ui.toast.com/weekly-pick/ko_20200616">https://ui.toast.com/weekly-pick/ko_20200616</a>
<a href="https://www.ridicorp.com/story/how-to-use-redux-in-ridi/">https://www.ridicorp.com/story/how-to-use-redux-in-ridi/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RoR] Class vs Instance]]></title>
            <link>https://velog.io/@hi-yjs/RoR-Class-vs-Instance</link>
            <guid>https://velog.io/@hi-yjs/RoR-Class-vs-Instance</guid>
            <pubDate>Sun, 21 Mar 2021 14:43:22 GMT</pubDate>
            <description><![CDATA[<h4 id="🎈-important">🎈 important!</h4>
<ul>
<li>Class는 객체다</li>
<li>Instance는 객체다</li>
<li>Class는 자신만의 메소드가 있으며 독립적이다. 인스턴스와 이런것들을 나누지 않는다.</li>
<li>함수를 선언할때는 def 함수명으로 선언한다</li>
</ul>
<h3 id="🍎-class-메소드란">🍎 Class 메소드란</h3>
<ul>
<li>클래스에 정의된 메소드</li>
<li>class로 시작하여 end로 끝난다</li>
<li>앞에 self를 붙여줄수 있다</li>
<li>@@으로 시작하는 변수</li>
<li>인스턴스에 속해있는 기능이 아니라면 클래스를 사용한다</li>
</ul>
<h3 id="🍎-instance란">🍎 Instance란</h3>
<ul>
<li>특정 메모리에 할당된 객체</li>
<li>특정 인스턴스에서만 호출된다</li>
<li>@으로 시작하는 변수</li>
<li>@으로 시작하면 인스턴스 안에 있는 모든 함수에서 해당 변수를 호출할수 있다</li>
<li>인스턴스를 사용하려면 객체를 만든후 해당 객체에서 함수를 불러야한다</li>
<li>특정 인스턴스에 속해있는 기능은 인스턴스 메소드로 사용해야한다</li>
</ul>
<p>참고 - <a href="https://medium.com/@lauren.kroner/ruby-class-vs-instance-methods-a5182ce7de49">https://medium.com/@lauren.kroner/ruby-class-vs-instance-methods-a5182ce7de49</a>
<a href="https://culttt.com/2015/06/10/understanding-class-methods-verses-instance-methods-in-ruby/">https://culttt.com/2015/06/10/understanding-class-methods-verses-instance-methods-in-ruby/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RoR] 500? 백앤드 누구야...나네? Part. 2]]></title>
            <link>https://velog.io/@hi-yjs/RoR-500-%EB%B0%B1%EC%95%A4%EB%93%9C-%EB%88%84%EA%B5%AC%EC%95%BC...%EB%82%98%EB%84%A4-Part.-2</link>
            <guid>https://velog.io/@hi-yjs/RoR-500-%EB%B0%B1%EC%95%A4%EB%93%9C-%EB%88%84%EA%B5%AC%EC%95%BC...%EB%82%98%EB%84%A4-Part.-2</guid>
            <pubDate>Sun, 21 Mar 2021 14:12:42 GMT</pubDate>
            <description><![CDATA[<h3 id="🍎-schemarb">🍎 schema.rb</h3>
<p><code>rake db:migrate</code>라는 명령어를 실행하면 schema.rb에 내가 만든 db 테이블들이 다음과 같이 migrate 된다.</p>
<pre><code class="language-ruby">create_table &quot;items&quot;, force: :cascade do |t|
    t.string &quot;name&quot;
    t.text &quot;description&quot;
    t.string &quot;image_url&quot;
    t.integer &quot;price&quot;
    t.decimal &quot;sale&quot;
    t.integer &quot;stock&quot;
    t.bigint &quot;category_id&quot;, null: false
    t.datetime &quot;created_at&quot;, precision: 6, null: false
    t.datetime &quot;updated_at&quot;, precision: 6, null: false
    t.index [&quot;category_id&quot;], name: &quot;index_items_on_category_id&quot;
  end</code></pre>
<p>schema.rb를 확인해보면 현재 어떤 파일들까지 migrate 되었는지 확인할수 있다.  </p>
<h3 id="🍎-seedsrb">🍎 seeds.rb</h3>
<p>이제 테이블들을 다 schema.rb 파일에 옮겼으니 데이터를 집어넣어야한다. 데이터는 seeds.rb로 집어넣을수도 있고 rails console에서 하나씩 넣을수 있지만 한꺼번에 여러 데이터를 넣을수 있는 seeds.rb로 초기 데이터를 집어 넣었다.</p>
<pre><code class="language-ruby">items = Item.create([{name: &quot;Fried Chicken&quot;, description: &quot;It is a fried chicken&quot;, stock:30, image_url: &quot;https://images.unsplash.com/photo-1604422237312-37a96a84a4c6?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1650&amp;q=80&quot;, price:30, sale:0.02, category: category.first} ])</code></pre>
<h3 id="🍎-프론트앤드에게-데이터-뿌리기">🍎 프론트앤드에게 데이터 뿌리기</h3>
<p>먼저 <code>routes.rb</code>에 <code>resources :items</code>를 입력한다.</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/d4534f73-2fef-4bad-a951-c16e3d015522/Screen%20Shot%202021-03-21%20at%2011.05.10%20PM.png" alt=""></p>
<p>-출처 <a href="https://guides.rubyonrails.org/routing.html">https://guides.rubyonrails.org/routing.html</a></p>
<p>입력한다면 저절로 다음과 같은 path가 생성된다. Path가 생성된후 Items컨트롤러에 모든 아이템을 조건없이 뿌려주는 코드를 다음과 같이 작성한다.</p>
<pre><code class="language-ruby">class ItemsController &lt; ApiController
    def index 
        render json: Item.all
    end
end</code></pre>
<p>이제 이 주소를 Postman에 입력한다면</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/98e598f1-175c-48da-a040-5720fd3164d3/Screen%20Shot%202021-03-21%20at%2011.10.41%20PM.png" alt=""></p>
<p>정상적으로 데이터를 보낼수있는게 확인이 되었다. 이제 이 데이터를 프론트에 뿌릴 준비가 다 되었으니 프론트쪽 UI 구현과 기능 구현을 시작한다 ....</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[RoR] 500? 백앤드 누구야...나네? Part. 1]]></title>
            <link>https://velog.io/@hi-yjs/RoR-500-%EB%B0%B1%EC%95%A4%EB%93%9C-%EB%88%84%EA%B5%AC%EC%95%BC....%EB%82%98%EB%84%A4-Part.-1</link>
            <guid>https://velog.io/@hi-yjs/RoR-500-%EB%B0%B1%EC%95%A4%EB%93%9C-%EB%88%84%EA%B5%AC%EC%95%BC....%EB%82%98%EB%84%A4-Part.-1</guid>
            <pubDate>Sat, 20 Mar 2021 16:45:17 GMT</pubDate>
            <description><![CDATA[<h3 id="🤝-기업협업">🤝 기업협업</h3>
<p>이제 3개월차부턴 기업협업이 시작되었다. 나는 <a href="https://insomenia.com/">인썸니아</a>라는 웹서비스 및 모바일앱 개발을 하는 스타트업 회사로 가게되었다. 인썸니아는 풀스택개발자들을 지향하고 개인프로젝트로 진행되기때문에 여기서 한달만 일해도 정말 많은것을 배울수 있을것 같았다.</p>
<h3 id="🌈-프로젝트">🌈 프로젝트</h3>
<p>인썸니아에서 우리에게 주어진 프로젝트는 4주동안 웹앱 쇼핑몰을 만드는것이다. 프로젝트는 개인 프로젝트이며 다음 기술스택을 사용하여 기획부터 백앤드, 프론트앤드부분까지 해야한다.</p>
<h4 id="백앤드📕">백앤드📕</h4>
<ul>
<li>Ruby On Rails</li>
</ul>
<h4 id="프론트앤드📗">프론트앤드📗</h4>
<ul>
<li>React.js</li>
<li>Framework 7</li>
<li>Tailwind CSS</li>
</ul>
<p>백앤드부분 같은 경우에는 사실 너무나도 생소한 Ruby라는 언어를 쓰는 Rails라는 풀스택 framework를 사용하게 되고, 
프론트앤드부분 같은경우에는 이제는 많이 익숙해진 React.js를 사용하지만 Framework7이라는 웹앱을 만들어주는 library를 사용해야하고, 지금까지 SASS, Styled Components를 사용해왔던것과 달리 Tailwind CSS라는 inline styling처럼 생긴 스타일링을 해야해서 같은 React지만 조금 다를것 같았다 ㅋㅋ </p>
<p>또다시 내가 뭘 할수있는지도 모르던 1차 프로젝트 시작전의 마음으로 밤샘 공부를 .. 다짐하며 ... 기업협업 프로젝트를 시작했다. </p>
<h3 id="💔-m1맥북에-rubyrails-설치">💔 M1맥북에 Ruby/Rails 설치</h3>
<p>우리는 기업협업 첫날전에 Ruby 2.6.5버전과 Rails 6버전을 설치해서 오라는 미션?을 받았는데 ... M1 노트북을 가지고 있는 나한테 새로운 프로그램을 설치하는건 진짜 ..... 하 .... 금요일밤부터 설치를 시도하기 시작해서 일요일 오후 3시쯤에 설치를 했다. 정말 stackoverflow에 올라온 모든 M1 설치 관련 포스트와 유튜브 영상을 다 본것 같다 ... 같은 M1인데 왜 저사람들은 되고 나는 안되는건지도 모르겠고 ... 설치가 되었는데 뭐때메 된건지도 모르겠다 ..... Ruby 2.7.2버전 설치를 성공했는데 또 2.6.5버전은 설치가 안되고 ... 멘붕의 연속 ... 🤯</p>
<p>책상에 굴러다니는 LG Gram에 우분투를 설치해서 Ruby와 Rails를 설치하는법을 검색까지 해봤다 .... </p>
<p>결국 일요일에 Ruby 2.6.5버전과 Rails 6버전 설치를 성공했지만 세상은 아직 M1을 받아드릴 준비가 안된것을 주말에 깨달아버렸,,,</p>
<h3 id="🍎-db-모델링">🍎 DB 모델링</h3>
<p>많이 허접하지만 .... 모델링부터 시작해보았다. 일단 한 사이클을 돌리는게 중요하다고 생각했기때문에 가장 기본적인 기능들만 구현했다.</p>
<blockquote>
<p>** 회원가입/로그인 ▷ 상품리스트 ▷ 찜리스트 ▷ 장바구니 ▷ 결제 **</p>
</blockquote>
<p>부수적인 옵션들을 거의 다 제거하고 카테고리와 주문 Status만 더 넣었을뿐인데도 머리가 복잡해졌다 ... 프론트쪽을 구현할때는 다른 요소들이 서로 어떤 연관성이 있는지 생각을 많이 할 필요가 없었는데 백앤드쪽에서는 많은 데이터를 효율적으로 관리를 해야하니 어떤 데이터가 어떤 데이터와 엮여있는지 생각하며 데이터베이스를 짰어야했다.</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/b98aebb6-2753-423a-866c-633c36f307c3/Screen%20Shot%202021-03-20%20at%209.53.27%20PM.png" alt=""></p>
<p>🎈 여기서 중요한 convention</p>
<ul>
<li>테이블은 복수 (ex. items)</li>
<li>Controller도 복수형태 (ex. items_controller.rb) </li>
<li>Model은 단수여야한다. (ex. item.rb)</li>
</ul>
<h3 id="🍎-migration">🍎 Migration</h3>
<p>루비온레일즈에서 마이그레이션 파일을 만드는 방법은 다음과 같다. 만약 items 모델을 추가하려면, </p>
<pre><code class="language-ruby">rails generate model Item name:string description:text image_rl:string price:integer sale:decimal category:references</code></pre>
<p>이런식으로 커맨드에 입력하고 실행한다. 그러면 <code>app &gt; db &gt; migrate</code> 폴더안에 다음과 같은 마이그레이션 파일과 모델 파일이 생성된다. Category 같은 경우에는 아이템과 1:n 관계기때문에 뒤에 데이터타입 대신 <code>:references</code>라고 지정해준다. </p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div><div style="line-height:130%">4</div><div style="line-height:130%">5</div><div style="line-height:130%">6</div><div style="line-height:130%">7</div><div style="line-height:130%">8</div><div style="line-height:130%">9</div><div style="line-height:130%">10</div><div style="line-height:130%">11</div><div style="line-height:130%">12</div><div style="line-height:130%">13</div><div style="line-height:130%">14</div><div style="line-height:130%">15</div><div style="line-height:130%">16</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">class</span>&nbsp;CreateItems&nbsp;<span style="color:#0086b3"></span><span style="color:#a71d5d">&lt;</span>&nbsp;ActiveRecord::Migration[<span style="color:#0099cc">6.</span><span style="color:#0099cc">0</span>]</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;<span style="color:#a71d5d">def</span>&nbsp;change</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;create_table&nbsp;:items&nbsp;<span style="color:#a71d5d">do</span>&nbsp;<span style="color:#0086b3"></span><span style="color:#a71d5d">|</span>t<span style="color:#0086b3"></span><span style="color:#a71d5d">|</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.string&nbsp;:name</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.text&nbsp;:description</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.string&nbsp;:image_url</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.integer&nbsp;:price</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.decimal&nbsp;:sale</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.integer&nbsp;:stock</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.references&nbsp;:category,&nbsp;<span style="color:#a71d5d">null</span>:&nbsp;<span style="color:#0099cc">false</span>,&nbsp;foreign_key:&nbsp;<span style="color:#0099cc">true</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.timestamps</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#a71d5d">end</span></div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;<span style="color:#a71d5d">end</span></div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">end</span></div></div><div style="text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic"><a href="http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px">cs</span></a></td></tr></table></div>


<p>이렇게 모든 테이블들의 마이그레이션 파일과 모델 파일을 생성하고 나면 다음으로 해야할것은 테이블간의 관계들을 define 해주어야한다.</p>
<h3 id="🍎-models">🍎 models</h3>
<p><code>app &gt; models</code> 폴더안에는 <code>rails generate model</code> command를 실행할때 만들어진 모델 파일들이 있다. 만약 <code>:references</code>를 붙였다면 다음과 같이 저절로 <code>belongs_to</code>라는 관계가 정의가 되어 있다. </p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">class</span>&nbsp;Item&nbsp;<span style="color:#0086b3"></span><span style="color:#a71d5d">&lt;</span>&nbsp;ApplicationRecord</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;belongs_to&nbsp;:category</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">end</span></div></div></td><td style="vertical-align:bottom;padding:0 2px 4px 0"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px"></span></td></tr></table></div>

<p>하지만 반대로 <code>has_many</code>에 대한 관계는 정의 되어있지 않기때문에 하나하나 파일을 수정해줘야한다.</p>
<div class="colorscripter-code" style="color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important; position:relative !important;overflow:auto"><table class="colorscripter-code-table" style="margin:0;padding:0;border:none;background-color:#fafafa;border-radius:4px;" cellspacing="0" cellpadding="0"><tr><td style="padding:6px;border-right:2px solid #e5e5e5"><div style="margin:0;padding:0;word-break:normal;text-align:right;color:#666;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="line-height:130%">1</div><div style="line-height:130%">2</div><div style="line-height:130%">3</div><div style="line-height:130%">4</div><div style="line-height:130%">5</div><div style="line-height:130%">6</div></div></td><td style="padding:6px 0;text-align:left"><div style="margin:0;padding:0;color:#010101;font-family:Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;line-height:130%"><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">class</span>&nbsp;Item&nbsp;<span style="color:#0086b3"></span><span style="color:#a71d5d">&lt;</span>&nbsp;ApplicationRecord</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;belongs_to&nbsp;:category</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;has_many&nbsp;:likes,&nbsp;dependent:&nbsp;:destroy</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;has_many&nbsp;:liked_users,&nbsp;through:&nbsp;:likes,&nbsp;source:&nbsp;:user</div><div style="padding:0 6px; white-space:pre; line-height:130%">&nbsp;&nbsp;has_many&nbsp;:line_items</div><div style="padding:0 6px; white-space:pre; line-height:130%"><span style="color:#a71d5d">end</span></div></div><div style="text-align:right;margin-top:-13px;margin-right:5px;font-size:9px;font-style:italic"><a href="http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none"><span style="font-size:9px;word-break:normal;background-color:#e5e5e5;color:white;border-radius:10px;padding:1px">cs</span></a></td></tr></table></div>


<p>이렇게 model 파일들을 하나하나 다 수정해주면 이제 db:migrate를 하면 된다. 여기서부턴 다음 포스트에 ...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ShockX | 2차 프로젝트 Part.2]]></title>
            <link>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.2</link>
            <guid>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.2</guid>
            <pubDate>Sun, 14 Mar 2021 14:48:00 GMT</pubDate>
            <description><![CDATA[<p>이번 프로젝트를 하면서 useParams()와 useLocation()을 활용을 많이했었다.</p>
<p><a href="https://reactrouter.com/web/api/Hooks/">useParams() 와 useLocation() 공식문서</a></p>
<p>클래스형에서는 match, location, history에 접근하려면 withRouter HOC로 감싸줘야했지만 useParams() hooks를 사용한다면 그럴 필요가 없었다.</p>
<p>마찬가지로 useLocation()이라는 hooks를 사용한다면 쉽게 location.search나, location.pathname에 접근할수 있다.</p>
<p>이번 프로젝트때 buy와 sell의 결제페이지를 컴포넌트 재사용을 활용해서 같은 js file로 만들었기때문에 모든 데이터 fetch와 렌더되는 내용들이 한 파일에서 일어났다. 그러므로 useParams와 useLocation을 이용하여 현재 어떤 페이지가 구현이 되야하는지를 함수들과 자식 컴포넌트들에게 전달했다.</p>
<p>예를들어, <code>localhost:3000/order/sell</code> 이라는 페이지에서 밑의 코드를 찍어본다면</p>
<pre><code class="language-jsx">useParam = useParams()
location = useLocation()
console.log(useParam)
console.log(location)</code></pre>
<p>** useParam 🍎**
<img src="https://images.velog.io/images/hi-yjs/post/e8665e7a-20a7-431b-80d0-b746371f4845/Screen%20Shot%202021-03-14%20at%2011.30.31%20PM.png" alt=""></p>
<pre><code class="language-jsx">//Routes.js
  &lt;Route exact path=&quot;/order/:id/&quot; component={Payment} /&gt;</code></pre>
<p>useParam 같은 경우 Routes에서 미리 지정을 해놓았었던 id가 나오고,</p>
<p>** location 🍎**
<img src="https://images.velog.io/images/hi-yjs/post/f7210cc7-bc20-4158-8dcc-649d0dae4511/Screen%20Shot%202021-03-14%20at%2011.27.33%20PM.png" alt=""></p>
<p>이렇게 <code>localhost:3000</code> 뒤에 어떤 pathname을 가지고 있는지가 뜬다.</p>
<p>이렇게 뜨는 정보들을 활용하여 order/뒤에 있는데 &quot;buy&quot;인지, &quot;sell&quot;인지를 감지하여 어떤 데이터를 fetch하고 컴포넌트들을 렌더 시킬지 조건을 걸었다. 또, 실제 데이터를 받아서 렌더할때는 url에 size=10 같은 query가 같이 오는데 location.search로 이 모든 query까지 받을수가 있다. 그렇게 해서 백앤드에게 해당 페이지의, 해당 상품의, 해당 size가 렌더되어야해~ 라고 fetch를 할때 밑의 코드처럼 useLocation()을 적극 활용했다.</p>
<pre><code class="language-jsx"> useEffect(() =&gt; {
    const sizeQuery = location.search;
    const pathnameQuery = location.pathname;
    if (useParam.id === &quot;buy&quot;) {
      setIsBuy(0);
    } else {
      setIsBuy(1);
    }
    fetch(`${ORDERAPI}${pathnameQuery}${sizeQuery}`, {
      method: &quot;GET&quot;,
      headers: {
        Authorization: localStorage.getItem(&quot;Kakao_token&quot;),
      },
    })
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[ShockX | 2차 프로젝트 Part.1]]></title>
            <link>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.1</link>
            <guid>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.1</guid>
            <pubDate>Sun, 14 Mar 2021 13:18:40 GMT</pubDate>
            <description><![CDATA[<h2 id="카카오소셜로그인-🍉">카카오소셜로그인 🍉</h2>
<p>이번 2차 프로젝트때 처음으로 시도해본 카카오 소셜 로그인! 프론트앤드 &lt;-&gt; 백앤드 뿐만 아니라 카카오까지 연결을 시도를 해야하는거여서 낯설었지만 재밌었다 ㅋㅋ</p>
<p>먼저 <a href="https://developers.kakao.com/product/kakaoLogin">카카오 developers</a>을 통해 localhost:3000을 등록하고 JS Key를 발급 받는다. </p>
<p>발급 받은 JS Key를 index.html에 넣는다.</p>
<pre><code class="language-jsx"> &lt;script&gt;
      Kakao.init(&quot;발급받은키&quot;);
      console.log(Kakao.isInitialized());
 &lt;/script&gt;</code></pre>
<p>console.log를 보면 <code>true</code>라고 떠있다.</p>
<p>그런 다음에 해야할일은 로그인이 진행될 버튼에 함수를 작성하는 일이다. </p>
<p>먼저 첫 두줄은 카카오와 통신하는 과정이다. 버튼을 눌러 함수가 실행되면 먼저 카카오 로그인 모달이 뜬다. 모달에 아이디와 비밀번호를 입력하면 authObj라는 카카오에서 발행된 토큰이 포함된 객체가 나에게 다시 전달되는데 여기서 받은 access_token을 method: &quot;POST&quot;로 다시 백앤드에게 전달해줘야한다. 백앤드에게 access_token을 전달해주면 백앤드는 그 토큰을 가지고 카카오에게 authorization을 받고 다시 나에게 백앤드에서 발급하는 토큰을 발급해준다. </p>
<pre><code class="language-jsx">const loginWithKakao = () =&gt; {
    window.Kakao.Auth.login({
      success: function (authObj) {
        fetch(KAKAOAPI, {
          method: &quot;POST&quot;,
          headers: {
            Authorization: authObj.access_token,
          },
        })
          .then((res) =&gt; res.json())
          .then((res) =&gt; {
            console.log(res);
            localStorage.setItem(&quot;username&quot;, res.user_name);
            localStorage.setItem(&quot;Kakao_token&quot;, res.access_token);
            if (res.access_token) {
              alert(&quot;You are Logged In with Kakao!&quot;);
              history.push(&quot;/&quot;);
            } else alert(&quot;Failed to Log In&quot;);
          });
      },
      fail: function (err) {
        console.log(&quot;Error&quot;, err);
      },
    });
  };</code></pre>
<p>사실 이렇게 써놓고 보면 그렇게 복잡한 과정은 아니지만 코드를 작성하기전에 소셜로그인을 할때 어떤식으로 서로 토큰을 주고 받는지 이해하는게 중요한것 같다. 나중에는 구글 로그인도 도전해볼수있기를...!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ShockX | 2차 프로젝트 최종후기]]></title>
            <link>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@hi-yjs/ShockX-2%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sun, 14 Mar 2021 13:04:41 GMT</pubDate>
            <description><![CDATA[<p> <img src="https://images.velog.io/images/hi-yjs/post/4d8ae100-2688-4fea-ab77-82ccfdf642b2/Screen%20Shot%202021-03-14%20at%2010.04.28%20PM.png" alt=""></p>
<p>지난 3월 2일 화요일부터 3월 12일 금요일까지 진행했던 <strong>2차 프로젝트 - StockX 클론코딩</strong>이 무사히 끝났다. 이번에는 1차때 안썼던 함수형 hooks와 styled components를 쓰게 되어서 새로운 기능들로 구현해야하니깐 최대한 현실적으로 목표를 잡자! 라고 첫날부터 얘기를 했었던게 좋았던것 같다. </p>
<h3 id="클론코딩하는-사이트-🌈">클론코딩하는 사이트 🌈</h3>
<p>미국의 온라인 리세일 마켓 플랫폼인 <a href="https://stockx.com/">StockX</a> 가 당첨 되었다! 1차때와 비교해서 더 복잡해진 데이터와 고려해야하는 조건들이 훨씬 많아져서 첫날 이 사이트를 이해하는데도 시간이 오래 걸렸고 사이트를 하나하나 뜯어보면 볼수록 과연 이걸 11일만에 할수있을까? 라는 생각이 들었던것 같다.</p>
<h3 id="shockx-🌈">ShockX 🌈</h3>
<p>백앤드 네명, 프론트 세명으로 구성된 우리팀은 이번에는 최대한 새로운 기능들을 더 도전해보고 2주차때는 기업협업때문에 정신이 없을것 같아서 최대한 가지치기를 해서 필수적인것들만 구현하기로 했다.</p>
<h3 id="프로젝트-기간">프로젝트 기간</h3>
<p>2021.03.02 ~ 2021.03.12 (총 11일)</p>
<h4 id="프론트앤드-기술스택">프론트앤드 기술스택</h4>
<ul>
<li>React</li>
<li>React Router</li>
<li>Styled Components</li>
<li>Styled Reset</li>
<li>Restful API</li>
<li>react-ticker</li>
<li>Highcharts</li>
</ul>
<h4 id="구현한-페이지">구현한 페이지</h4>
<ul>
<li>*<em>회원가입/로그인 페이지 (+카카오소셜 로그인) *</em>🍎 </li>
<li><strong>Navigation Bar</strong> 🍎 </li>
<li>*<em>메인 페이지 (+검색 기능) *</em>🍎</li>
<li>상품 리스트 페이지 (+필터링 기능)</li>
<li>상품 디테일 페이지</li>
<li><strong>Bid/Buy/결제 페이지</strong> 🍎</li>
<li><strong>Ask/Sell/결제 페이지</strong> 🍎</li>
<li><strong>마이페이지 - 메뉴탭</strong> 🍎</li>
<li>마이페이지 - Portfolio</li>
<li>*<em>마이페이지 - Buying *</em>🍎</li>
<li><strong>마이페이지 - Selling</strong>🍎</li>
</ul>
<h4 id="내가-구현한-페이지-결과물">내가 구현한 페이지 결과물</h4>
<ul>
<li><p>*<em>회원가입/로그인 페이지 (+카카오소셜 로그인) *</em>
<img src="https://images.velog.io/images/hi-yjs/post/ef662fc4-78d2-433b-b716-15a159577723/Screen%20Shot%202021-03-14%20at%209.44.01%20PM.png" alt=""></p>
</li>
<li><p>*<em>Navigation Bar &amp;&amp; 메인 페이지 (+검색 기능) *</em> 
<img src="https://images.velog.io/images/hi-yjs/post/9d55a532-92bd-47d7-b284-b27eecbe8757/stockxmain.gif" alt=""></p>
</li>
<li><p><strong>Bid/Buy/결제 페이지</strong>
<img src="https://images.velog.io/images/hi-yjs/post/755fe14b-9ad2-4cfc-8592-4f3cefd2c527/Screen%20Shot%202021-03-14%20at%209.54.40%20PM.png" alt="">
<img src="https://images.velog.io/images/hi-yjs/post/0342e1f9-c75b-489f-a742-e81a39459005/paymentbuy.gif" alt=""></p>
</li>
</ul>
<ul>
<li><p><strong>Ask/Sell/결제 페이지</strong>
<img src="https://images.velog.io/images/hi-yjs/post/1d1ba2a7-24a5-4f74-9057-c3def7a5041f/Screen%20Shot%202021-03-14%20at%209.54.49%20PM.png" alt="">
<img src="https://images.velog.io/images/hi-yjs/post/c28de2cb-0309-4e24-9eb1-eec79c0489d0/sellpayment.gif" alt=""></p>
</li>
<li><p>*<em>마이페이지 - Buying *</em>
<img src="https://images.velog.io/images/hi-yjs/post/eea16ecb-7249-460d-8e79-8b90f01e5e14/Screen%20Shot%202021-03-14%20at%2010.02.10%20PM.png" alt=""></p>
</li>
<li><p>*<em>마이페이지 - Selling *</em>
<img src="https://images.velog.io/images/hi-yjs/post/03c8512f-8261-4239-82b9-17807651f3f4/Screen%20Shot%202021-03-14%20at%2010.02.25%20PM.png" alt=""></p>
</li>
</ul>
<h3 id="기억하고-싶은-코드-🌈">기억하고 싶은 코드 🌈</h3>
<p>어떻게 하다보니 내가 맡은 페이지들은 모두 컴포넌트 재사용을 활용해서 비슷한 구조를 가진 두페이지를 한번에 만들수 있었다. 회원가입/로그인 같은 경우에도 account.js라는 최상위 부모에서 회원가입인지 로그인인지에 따라서 렌더하는 내용이 달라지도록 했고 Bid/Buy와 Ask/Sell하는 페이지들와 마이페이지 - Buying과 마이페이지 - selling도 각각 payment.js와 buyingselling이라는 파일에서 모두 시작된다.</p>
<p>가장 오랜시간 공을들였던 Big/Buy와 Ask/Sell은 현재 url이 /buy인지, /sell인지를 useParams()라는 hooks를 통해 감지하여 해당되는 데이터를 fetch해오고 필요한 데이터를 자식들에게 props로 넘겨주는 방식을 사용했다. </p>
<pre><code class="language-jsx"> let useParam = useParams();
 const history = useHistory();
 const location = useLocation();

  useEffect(() =&gt; {
    const sizeQuery = location.search;
    const pathnameQuery = location.pathname;
    if (useParam.id === &quot;buy&quot;) {
      setIsBuy(0);
    } else {
      setIsBuy(1);
    }
    fetch(`${ORDERAPI}${pathnameQuery}${sizeQuery}`, {
      method: &quot;GET&quot;,
      headers: {
        Authorization: localStorage.getItem(&quot;Kakao_token&quot;),
      },
    })
      .then((res) =&gt; res.json())
      .then((data) =&gt; {
        setDetailData(data.data.product);
      });
  }, [useParam.id]);</code></pre>
<p>또한 StockX 사이트의 경우 사고 파는것만 할수있는게 아니라 사기위해서 가격을 부르고 (bid), 팔기 위해서 가격을 부를수 있기 때문에 (ask) 현재 사용자가 bid을 하려고 하는지, buy를 하려고 하는지, ask를 하려고하는지, sell을 할려고하는지에 대해서 따로따로 렌더가 되었어야했기 때문에 확실히 1차때보다 구조가 더 복잡하다는걸 깨달았다. 
결국 이 많은 정보들을 담기위해서 생성된 자식 components 파일들.... Payment 하나를 위해 14개의 자식 components 파일들이 필요했다.
<img src="https://images.velog.io/images/hi-yjs/post/b21e159b-b529-448f-8fda-d3468d31d28a/Screen%20Shot%202021-03-14%20at%209.12.54%20PM.png" alt=""></p>
<p>한페이지에서 컴포넌트만 바꿔가며 데이터를 관리하기 때문에 수많은 자식들에게 props를 전달해야되기 때문에 최상위부모인 Payment.js는 props 파티가 열렸다....</p>
<pre><code class="language-jsx">&lt;&gt;
      &lt;PaymentNav /&gt;
      &lt;PaymentPage&gt;
        &lt;PaymentImage data={detailData} /&gt;
        &lt;PaymentRight&gt;
          {currentIdx === 0 &amp;&amp; (
            &lt;&gt;
              &lt;SizeContainer&gt;
                &lt;SizeText&gt;U.S. Men&#39;s Size {detailData.size}&lt;/SizeText&gt;
                &lt;PenIcon
                  alt=&quot;Pen&quot;
                  src={process.env.PUBLIC_URL + `/images/Payment/pen.svg`}
                /&gt;
              &lt;/SizeContainer&gt;
              &lt;PaymentDetail
                data={detailData}
                format={isBuy === 0 ? buyProps : sellProps}
                isBuy={isBuy}
                isPlace={isPlace}
                changeTabHandler={changeTabHandler}
                handleInputNum={handleInputNum}
                messageHandler={messageHandler}
                messageText={messageText}
                isShowAddFeeList={isShowAddFeeList}
                buyInput={buyInput}
                sellInput={sellInput}
                buyTotal={buyTotal}
                sellTotal={sellTotal}
                notAvailableProps={notAvailableProps}
              /&gt;
              {isPlace === 0 &amp;&amp; (
                &lt;Expiration
                  isBuy={isBuy}
                  expirationNum={expirationNum}
                  expirationHandler={expirationHandler}
                /&gt;
              )}
            &lt;/&gt;
          )}
          {currentIdx === 1 &amp;&amp; (
            &lt;ShippingInfoPage
              data={billingProps}
              handleInputInfo={handleInputInfo}
              inputs={inputs}
            /&gt;
          )}
          {currentIdx === 2 &amp;&amp; (
            &lt;ReviewBilling
              data={detailData}
              buyTotalPrice={buyTotalPrice}
              sellTotalPrice={sellTotalPrice}
              expirationNum={expirationNum}
              buyInput={buyInput}
              sellInput={sellInput}
              isBuy={isBuy}
              isPlace={isPlace}
              name={name}
              phoneNumber={phoneNumber}
              address={address}
              city={city}
              state={state}
              country={country}
              zipCode={zipCode}
            /&gt;
          )}
        &lt;/PaymentRight&gt;
      &lt;/PaymentPage&gt;
      &lt;PaymentFooter
        isBuy={isBuy}
        changeIdxHanlder={changeIdxHanlder}
        currentIdx={currentIdx}
        sumbitPaymentInfo={sumbitPaymentInfo}
      /&gt;
    &lt;/&gt;</code></pre>
<h3 id="개인적인-프로젝트-후기-🌈">개인적인 프로젝트 후기 🌈</h3>
<h4 id="아쉬웠던점-👻">아쉬웠던점 👻</h4>
<p>주말에 미리 예습을 해놨어서 그런지 styled components와 react hooks에 생각보다 빠르게 적응해서 계획했던것보다 훨씬 더 빠르게 페이지들이 완성되었다. 굳이 아쉬웠던점을 꼽자면 페이스조절을 못한탓에 2주차때는 너무 여유가 넘쳤었다 ...  또, 1차때 많은것들을 이미 만들어봐서 그런지 2차때는 뭔가 새로운걸 배운다라는 느낌을 카카오소셜로그인을 구현할때 빼고는 못느꼈던것 같다. 1차때도 메인, Nav bar, 결제페이지, 마이페이지를 만들어봤기 때문에 데이터가 조금 더 많고 구조가 조금 더 복잡했지만 결국은 똑같은걸 만드는 느낌이 들었다. 데이터 시각화나 query쪽으로 파고들었으면 더 유익했을것 같다.</p>
<h4 id="좋았던점-👍">좋았던점 👍</h4>
<p>확실히 1차 프로젝트를 다들 경험해봐서 그런지 2차 프로젝트때는 어떤식으로 서로 소통하는게 효율적인지를 다 깨닫고 프론트앤드 vs 백앤드간의 소통이나 프론트앤드 vs 프론트앤드의 소통도 훨씬 잘되었던것 같다. 2차때도 좋은 팀원들을 만나서 정말 conflict 하나 없이 무난하게 잘 지나간것 같다.</p>
<h4 id="최종-후기-🤖">최종 후기 🤖</h4>
<p>첫 한달에 개념을 많이 배웠다면 두번째달에는 배운 개념을 응용하여 적용하는 훈련을 많이 한것 같다. 그냥 notion의 개념들을 달달 외우는것 보다 직접 코드를 쓰니깐 왜 이런 개념훈련들이 필요한지, 왜 코드카타를 꾸준히 해야하는지ㅋㅋ를 많이 깨달았던 1차,2차 프로젝트였다. 이제 기업협업을 나가서 지금까지 배운 개념들과 연습해온 코드들이 실무에선 어떻게 쓰일지 배우게 될텐데 많이 기대된다. 🙌</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CodeKata | Week 4 Day 2]]></title>
            <link>https://velog.io/@hi-yjs/CodeKata-Week-4-Day-2</link>
            <guid>https://velog.io/@hi-yjs/CodeKata-Week-4-Day-2</guid>
            <pubDate>Mon, 01 Mar 2021 03:49:50 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>prices는 배열이며, 각 요소는 매일의 주식 가격입니다.
만약 한 번만 거래할 수 있다면 = 사고 팔 수 있다면,
제일 큰 이익은 얼마일까요?</p>
<pre><code>Input: [7,1,5,3,6,4]
Output: 5</code></pre><p>설명: 
2일(가격=1)에 샀다가 5일(가격=6)에 사는 것이 6-1이라 제일 큰 수익
7-1=6 은 안 되는거 아시죠? 먼저 사야 팔 수 있습니다.</p>
<pre><code>Input: [7,6,4,3,1]
Output: 0</code></pre><p>설명: 
여기서는 매일 가격이 낮아지기 때문에 거래가 없습니다. 그래서 0</p>
<h3 id="첫접근">첫접근</h3>
<pre><code class="language-javascript">const maxProfit = prices =&gt; {
let profit = []
for(let i=0; i&lt;prices.length;i++){
  for(let j=i+1; j&lt;prices.length;j++){
    if(prices[j]&gt;prices[i]){
      profit.push(prices[j]-prices[i])
    } else {profit.push(0)}
  }
} return profit.reduce(function(a,b){return Math.max(a,b)})
}</code></pre>
<p>결과는 통과~~ 👻
먼저 profit이라는 빈배열을 만들고 for-loop을 두번 돌린다. i는 0부터 시작하지만 j는 i와 비교를 해야하기때문에 i+1부터 시작한다. 이렇게 돌아가는 for-loop에서 만약 <code>prices[j]</code>가 <code>prices[i]</code>보다 클 경우 <code>prices[j]</code>에서 <code>prices[i]</code>를 뺀후 그 숫자를 profit이라는 배열에 집어넣는다. 그렇지 않을 경우는 0을 profit에 넣는다. 그러고 나서 마지막에 profit이라는 배열안에 가장 큰 숫자를 반환한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CodeKata | Week 4 Day 1]]></title>
            <link>https://velog.io/@hi-yjs/CodeKata-Week-4-Day-1</link>
            <guid>https://velog.io/@hi-yjs/CodeKata-Week-4-Day-1</guid>
            <pubDate>Mon, 01 Mar 2021 03:34:58 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>양수 N을 이진법으로 바꿨을 때, 연속으로 이어지는 0 중에서 가장 큰 값을 return해 주세요.</p>
<ul>
<li>이어지는 0은 1과 1사이에 있는 것을 의미합니다.</li>
<li>1과 1사이에 있는 0을 binary gap 이라고 하겠습니다.</li>
</ul>
<pre><code>input: 9
output: 2</code></pre><p>설명: 9의 이진수는 1001 입니다. 
1과 1사이에 있는 0은 2 이므로, 2를 return</p>
<h3 id="첫-접근">첫 접근</h3>
<pre><code class="language-javascript">const solution1 = N =&gt; {
  const arr = N.toString(2).split(&#39;1&#39;)
  const length = arr.map(str =&gt; str.length)
  return length.reduce(function(a,b){return Math.max(a,b)})
} </code></pre>
<p>결과: 응~ fail~ ㅋㅋㅋ 테스트문제 9개중에 7개 통과하고 2개를 fail 했다. 이유는 &#39;32&#39;, &#39;20&#39;이라는 숫자가 들어갔을때</p>
<pre><code class="language-javascript">n.toString(2).split(&#39;1&#39;) // [ &#39;&#39;, &#39;&#39;, &#39;&#39;, &#39;&#39;, &#39;0&#39; ]
s.toString(2).split(&#39;1&#39;) // [ &#39;&#39;, &#39;0&#39;, &#39;00&#39; ]</code></pre>
<p>여기서 다시보는 문제: <strong>이어지는 0은 1과 1사이에 있는것을 의미합니다</strong>
조건을 걸어주지않았기 때문에 1과 1사이에 없는 0들의 숫자도 고려해버렸다,,, 
다시 조건을 걸어주고 시도한다면</p>
<h3 id="두번째-접근">두번째 접근</h3>
<pre><code class="language-javascript">const solution = N =&gt; {
  const arr = N.toString(2).split(&#39;1&#39;)
  arr.pop()
  arr.shift()
  if (arr.length &gt; 0){
  const length = arr.map(str =&gt; str.length)
  return length.reduce(function(a,b){return Math.max(a,b)})
} else {return 0}}</code></pre>
<p>통과!🙌
먼저 arr이라는 이진법으로 바꾸고 &#39;1&#39;로 split한 배열을 만들고, 맨앞과 맨뒤의 index에 있는 string을 없애고 만약 그래도 arr이라는 배열이 0보다 크다면 그 안에 있는 string중에 가장 큰 string의 숫자를 반환한다. 만약 arr이라는 배열이 0이라면, 0을 반환한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민문방구 | 1차 프로젝트 최종 후기]]></title>
            <link>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B5%9C%EC%A2%85-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sun, 28 Feb 2021 12:27:06 GMT</pubDate>
            <description><![CDATA[<p>지난 2월 15일 월요일부터 2월 26일 금요일까지 진행했던 <strong>1차 프로젝트 - 배민문방구 클론코딩</strong>이 무사히 끝났다. 위코드에 다니기전에는 정말 코딩에 대해서 1도.. 단 1도 모르던 내가 6주만에 한 사이트를 통째로 클론코딩하는 프로젝트를 할수있을것이라고 생각치도 못했는데 내가 그래도 많이 성장했구나,,,를 알수 있었던 프로젝트였던것 같다.</p>
<h3 id="클론코딩하는-사이트-🌈">클론코딩하는 사이트 🌈</h3>
<p>배달의민족에서 운영하는 <a href="https://store.baemin.com/">배민문방구</a>가 당첨 되었다! 깔끔한 UI와 심플한 기능이 돋보인는 배민문방구는 1차프로젝트로 하기 딱 적합한것 같다는 생각을 했다. 지금까지 배웠던것을 복습하고, 내가 원하는대로 더 응용해서 적용할수 있는 요소들이 많았던것이 좋았다.</p>
<h3 id="200문방구-🌈">200문방구 🌈</h3>
<p>백앤드 세명, 프론트 세명으로 구성된 우리팀은 일주일차에 필수구현을 최대한 끝내고, 이주차에는 추가구현 및 필수구현 리팩토링을 위주로 진행하기로 결정했다. 프론트에서 구현한 UI와 기능들은 다음과 같다. (내가 구현한 페이지들은 🍎 표시를 해놨다)</p>
<h3 id="프로젝트-기간">프로젝트 기간</h3>
<p>2021.02.15 ~ 2021.02.26 (총 12일)</p>
<h4 id="프론트앤드-기술스택">프론트앤드 기술스택</h4>
<ul>
<li>React</li>
<li>React Router</li>
<li>SASS</li>
<li>Restful API</li>
<li>React-slick / React-slick-Carousel</li>
<li>React-datepicker</li>
<li>React-daum-postcode</li>
</ul>
<h4 id="구현한-페이지">구현한 페이지</h4>
<ul>
<li>회원가입 페이지</li>
<li>로그인 페이지</li>
<li><strong>Navigation Bar</strong>🍎 (+동적 라우팅 기능)</li>
<li><strong>Footer</strong>🍎</li>
<li><strong>메인 페이지</strong>🍎</li>
<li>상품 리스트 페이지 (+필터링 기능)</li>
<li>상품 디테일 페이지</li>
<li><strong>장바구니 페이지</strong>🍎</li>
<li><strong>결제 페이지</strong>🍎</li>
<li>마이페이지 - Nav Bar, 메뉴탭</li>
<li><strong>마이페이지 - 메인</strong>🍎</li>
<li><strong>마이페이지 - 주문목록</strong>🍎</li>
<li>마이페이지 - 리뷰 모달창 </li>
</ul>
<h4 id="내가-구현한-페이지-결과물">내가 구현한 페이지 결과물</h4>
<p>(각 중요 페이지에 대해 쓴 후기를 제목에 링크 걸어둠!)</p>
<p><a href="https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-2">*<em>- Navigation Bar *</em></a>🍎
<img src="https://images.velog.io/images/hi-yjs/post/27f8a1d0-8311-41de-8af1-c075847abee0/finalNav.gif" alt=""></p>
<p><a href="https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-1"><strong>- 메인페이지</strong></a>🍎
<img src="https://images.velog.io/images/hi-yjs/post/e417f244-c140-48d3-af67-e74bd01dc52c/finalmain.gif" alt=""></p>
<p><a href="https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-3">*<em>- 장바구니 *</em></a> 🍎
<img src="https://images.velog.io/images/hi-yjs/post/928431f3-202b-4896-b988-12f96dad079d/finalcart.gif" alt=""></p>
<p>*<em>- 결제페이지 *</em> 🍎
<img src="https://images.velog.io/images/hi-yjs/post/12fe29f8-f004-49fb-944f-367c5e1ee41e/finalpayment.gif" alt=""></p>
<p><a href="https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-4">*<em>- 마이페이지 *</em> </a>🍎
<img src="https://images.velog.io/images/hi-yjs/post/02485260-47ad-4f53-97ff-92d1bd9b45f3/finalmypage.gif" alt=""></p>
<h3 id="기억하고-싶은-코드-🌈">기억하고 싶은 코드 🌈</h3>
<p>가장 기억하고 싶은 코드는 무조건 <a href="https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-3">장바구니</a>의 체크박스 코드다. 진짜 가장 많은 시간을 투자했고 가장 많은 기능들이 들어가 있다고 생각한다. 장바구니 페이지를 구현하면서 내가 레벨업하는게 느껴졌다 🤩 내가 원하는 기능을 구현하기위해 구글링하고, 또 구글링하고, 다른 사람들에게 자문도 구하고, 또 구글링하고, 이것저것 다 시도해보고 결국 해내었을때 기분은 정말 너무 좋았다. </p>
<h3 id="개인적인-프로젝트-후기-🌈">개인적인 프로젝트 후기 🌈</h3>
<p>여러가지 복합적인 감정들이 들었던 프로젝트였던것 같다. 내가 무엇을 구현할수 있는지 전혀 모르는 상태에서 시작했고 어떤 conflict를 마주하게 될지 몰랐기때문에 초기 목표를 최대한 현실적이게 잡으려고 노력했다. 팀원 모두에게 첫 프로젝트이기 때문에 굳이 목표를 100으로 잡고 하나하나 제대로 짚지 않고 90까지 후다닥 성공 시키는것보다 목표를 50까지 잡고 80까지 깊이있게 성공시키는게 더 맞다고 생각했던것 같다. 결과적으로 말하자면 개인적인 목표를 80까지 잡았고 90정도까지 성공 시킨것 같아서 꽤 성공적인 프로젝트였다고 할수 있는것 같다.</p>
<p>이번 1차프로젝트를 통해 하나의 웹사이트가 구축이 될때 어떤 기능들이 어떤식으로 구현되는지 더 알게되었고 백앤드와 프론트앤드가 어떤식으로 조율하고 어떤식으로 소통해야하는지 알게되었다. 우리팀 같은경우에는 개인적으로 소통이 굉장히 잘된팀이라고 생각한다. 처음 팀이 만들어졌을때는 거의 대부분 인사말고는 말을 해볼 기회가 없었던,,,,분들이랑 팀을 하게되었지만 진짜 거의 2주동안 가족보다 더 많이 보고 그 누구보다도 같이 밥을 많이 먹어서 그런지 한 배를 탄 기분이 들었다 ㅋㅋ 그냥 이분들과 같이 팀을 하게 되면서 2021년 운을 다 쓴건가..?! 싶을 정도로 운이 좋았다 + 좋다 ~ 🥳 라는 생각을 더 했던것 같다. 2주동안 다 같이 배우는 입장이기때문에 정말 많은 얘기를 서로 거리낌없이 했던것 같고 그러면서 서로 배우는점이 많았을꺼라고 믿는다...!  </p>
<h4 id="아쉬웠던점-👻">아쉬웠던점 👻</h4>
<p>개인적인 모토가 <code>후회하지말자!</code>여서 과거를 뒤돌아보면서 후회하며 스트레스받진 않지만 굳이 아쉬웠던점을 꼽고 나중에 이렇게하지 말아야지!라고 생각한것이 있다면 <code>초기세팅</code>을 꼼꼼히하지 않은것이 아쉬웠다. 우리팀은 초기세팅에서 <code>eslintrc</code>와 <code>package-lock.json</code>때문에 고생한 몇몇팀들중 하나였고, 결국 마지막까지 merge를 할때마다 문제가 발생했다 ... 다음번에 프로젝트를 할때는 팀원들과 함께 초기세팅을 더 꼼꼼히해서 <code>.scss</code> 같은 경우에도 SASS의 기능들을 더 많이 사용하면서 코드가 더 가독성이 좋고 간결하게 만들려고한다.</p>
<h4 id="좋았던점-👍">좋았던점 👍</h4>
<p>우리팀 포함, 모든 팀의 프론트분들이 진짜 많이 힘들어했었다 ... 백앤드에 비해 숫자가 적은만큼 백앤드 팀원들이 구현해내는 데이터에 맞출려면 정말 각자 최소 1.5인분은 했어야해서 3시가 넘어가는 모각코에는 프론트분들만 남은날이 정말정말 많았고 날이 가면 갈수록 프론트분들이 너무 피곤해보였다 ... 그런데도 불구하고 각자 본인 프로젝트가 바쁜 와중에 내가 이팀 저팀 이것저것 물어보러 다니면 진짜 열심히 가르쳐주셔서 너무 고마웠다. 정말 내가 구현한 모든페이지에 각 팀의 프론트분들의 도움이 다 깃들어져있다 🙌 다 함께 배우러온 입장이니만큼 경쟁자로써 서로를 견제하는게 아니라 다른분들과 얘기하면서 하나라도 더 배우고 하나라도 더 지식을 나눔하려고 하는 동료들이 있다는게 너무 좋았던것 같다. 🙏</p>
<h4 id="최종-후기-🤖">최종 후기 🤖</h4>
<p>6주전에 위코드에 다니기전에는 진짜 코딩에 대해서 1도 ... 단 1도... 진짜 1도 모르던 내가 한사이트의 UI와 기능들을 구현할정도로 많이 성장했구나~를 체크할수 있었던 프로젝트였던것 같다. 마지막날전까지는 새벽 4시전에 잔적이 없었을정도로 과몰입,,을 하면서 미친듯이 달렸던것 같다... 지금까지 대학이나 회사의 많은 그룹 프로젝트들을 진행해왔지만 끝나고 이렇게 후련하고 아쉬움이 하나도 안남았던 프로젝트는 처음인것 같다 ㅋㅋ 프로젝트를 시작하기전에 같이 일하고 싶은 팀원, 같이 일하면 편한 팀원, 다가가기 편한 팀원이 되고싶어서 정말 많이 노력했는데 내 노력이 팀원분들에게 닿았길 바란다..ㅋㅋ 🙏 매일매일 열심히 해준 팀원들에게 너무 고맙고 다들 2차프로젝트때는 본인이 더더욱 만족할만한 결과물을 내길 바란다 ❣️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민문방구 | 1차 프로젝트 Part. 4]]></title>
            <link>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-4</link>
            <guid>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-4</guid>
            <pubDate>Sun, 28 Feb 2021 11:00:54 GMT</pubDate>
            <description><![CDATA[<h2 id="마이페이지-🍉">마이페이지 🍉</h2>
<p>솔직히 마이페이지... 처음에는 정말 추가구현 of 추가구현이라고 생각했는데 하다보니 욕심나고 왠지 할수 있을것 같은 생각이 들고, 생각보다 필수구현이 일찍 끝나서 더 욕심내서 구현해보았다. </p>
<p>이백문방구의 마이페이지의 주문목록 페이지다. 위에 header와 옆에 메뉴탭 같은 경우에는 다른분이 UI와 기능을 구현해주시고 내가 한 부분은 저 주문목록/배송조회의 날짜를 고르는 부분부터 밑에 주문목록/배송조회 테이블이다. </p>
<p><img src="https://images.velog.io/images/hi-yjs/post/52b2fa6a-e3d0-4e7f-8a86-fd3bbebf4563/Screen%20Shot%202021-02-28%20at%207.26.49%20PM.png" alt=""></p>
<p>장바구니에선 기능을 구현하는 함수를 짜는데 머리를 썼다면 여기서는 어떤 버튼과 텍스트에 어떤 조건을 줘야하는지를 정리를 했어야했다. 
백앤드에서 넘어오는 각 상품의 현 상황 (status)는 다음과 같다.</p>
<p>주문상태 : <code>[
  &#39;입금대기&#39;,
  &#39;결제완료&#39;,
  &#39;상품준비중&#39;,
  &#39;배송중&#39;,
  &#39;배송완료&#39;,
]</code></p>
<p>상품상태 : <code>[&#39;대기&#39;, &#39;취소&#39;, &#39;환불&#39;, &#39;구매확정&#39;]</code></p>
<p>여기서 생각해야할 조건들은,</p>
<ul>
<li>만약 상품이 구매확정이 안되어있다면 &#39;취소&#39;, &#39;환불&#39;이 가능하다.</li>
<li>만약 상품이 구매확정이 안되어있다면 구매확정 버튼이 필요하다.</li>
<li>만약 구매확정 버튼을 누른다면 해당 상품에 대한 리뷰를 쓸수 있어야한다.</li>
<li>만약 구매확정 버튼을 누른다면 백앤드에게 해당 상품이 구매확정이 되었다고 알려줘야한다.</li>
<li>&#39;리뷰쓰기&#39; 버튼을 누른다면 리뷰 모달창이 떠야하고, 리뷰를 등록을 한다면 백앤드에게 해당 상품의 리뷰가 등록 되었다고 내용을 함께 보내줘야한다.</li>
<li>만약 리뷰를 썼다면 &#39;리뷰보기&#39; 버튼이 생겨야한다. </li>
</ul>
<p>이 모든것들을 정리해놓고 우리팀의 백앤드분들과 얘기해본 결과, 다음과 같이 데이터를 주고 받기로했다.</p>
<ul>
<li>백앤드에서 초기에 넘어오는 데이터에는 <code>isReview = false</code>라는 값이 있다. (아직 리뷰가 안써졌다는 뜻) </li>
<li>구매확정이 된다면 해당 상품이 구매확정이 되었다고 productId와 orderId를 <code>method: &#39;PATCH&#39;</code>로 body에 담아서 보내준다. 그러면 백앤드는 SUCCESS라는 메세지와 함께 구매확정으로 수정된 주문목록 배열을 다시 보내준다. </li>
<li>백앤드로부터 구매확정 status를 받는다면 프론트는 리뷰쓰기 버튼이 뜨게 한다.</li>
<li>리뷰쓰기 버튼을 누르면 모달창이 뜨고 리뷰쓰기 완료를 누른다면 별점, 제목, 내용, 해당 상품번호와 주문번호를 <code>method:&#39;POST&#39;</code>의 body에 담아서 보낸다. 내용을 받은 백앤드는 해당상품의 데이터를 <code>isReview = true</code>로 수정해서 다시 프론트에게 보내준다. </li>
<li>리뷰가 달린 상품들 (<code>isReview = true</code> 라면) 리뷰보기 버튼이 뜬다. </li>
</ul>
<p>그렇게 모든 버튼과 텍스트에 조건부를 건 결과,</p>
<ul>
<li>배송완료가 되었고, 구매확정은 안된 상태
<img src="https://images.velog.io/images/hi-yjs/post/4fe72ed4-fddc-411a-9cf9-3396eca26b96/Screen%20Shot%202021-02-28%20at%207.54.13%20PM.png" alt=""></li>
<li>배송완료가 되었고, 구매확정도 되었지만 리뷰는 안쓴 상태,
<img src="https://images.velog.io/images/hi-yjs/post/436e4c72-644f-4d70-a9b0-ad2369324951/Screen%20Shot%202021-02-28%20at%207.55.10%20PM.png" alt=""></li>
<li>배송 완료, 구매확정 완료, 리뷰쓰기 클릭! (모달창 on! 모달창은 같은 프론트를 맡은 미경님이 만드셨다~!)
<img src="https://images.velog.io/images/hi-yjs/post/645a1c5a-faad-4099-a7bd-9f6e114e504b/Screen%20Shot%202021-02-28%20at%207.56.05%20PM.png" alt=""></li>
<li>배송 완료, 구매확정 완료, 리뷰쓰기 완료라면
<img src="https://images.velog.io/images/hi-yjs/post/855eb236-3d4a-4658-a531-cc70dc3c85e5/Screen%20Shot%202021-02-28%20at%207.57.01%20PM.png" alt=""></li>
</ul>
<h3 id="마이페이지-구현-후기-🐤">마이페이지 구현 후기 🐤</h3>
<p>가장 백앤드와 소통이 많이 필요했던 페이지였다. 어떤걸 넘겨야할지, 어떻게 넘어올지에 대한 데이터의 구조에 대해서 많이 얘기하고 조율했던것 같다. 장바구니 페이지를 통해 기능에 대해서 많이 배웠다면 마이페이지를 통해 협업에 대해서 많이 배웠다. 🙉</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민문방구 | 1차 프로젝트 Part. 3 ]]></title>
            <link>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-3</link>
            <guid>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-3</guid>
            <pubDate>Sun, 28 Feb 2021 10:04:14 GMT</pubDate>
            <description><![CDATA[<h2 id="장바구니-🍒">장바구니 🍒</h2>
<p>개인적으로 이번 프로젝트를 진행하면서 가장 힘들었던 파트를 고르라면 장바구니였다. 생각보다 생각해야할게 너무 많았고 체크박스 구현을 얕봤다가 큰코 다쳤다...😭 이거 구현 안해본 사람은 모른다.. 체크박스가 진짜 생각보다 너무 복잡하다... 분명 내가 구현한게 가장 ideal한 방법은 아닌게 알지만 여기까지 오는것도 정말 어려웠다....</p>
<p>200문방구에서 만든 장바구니는 이렇게 생겼다.</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/a0fb7bfa-2516-4b22-99f8-a6bbee99bf89/Screen%20Shot%202021-02-28%20at%205.07.32%20PM.png" alt=""></p>
<p>장바구니를 만들때 구현하고 싶었던 기능들은 :</p>
<p>1) 장바구니에서 상품들의 수량을 바꿀수 있어야한다.
2) 몇개의, 혹은 전체 상품을 삭제 할수있어야한다
3) 선택된 상품만 주문 가능해야한다.
4) 전체 상품을 주문할수 있어야한다.</p>
<p>결국 모든 기능들을 구현했다 🙌 나중에 분명히 또 쓸 코드들이 많지만 이번 프로젝트를 하면서 가장 많은 시간을 할애했던 체크박스에 대해서 정리해보려고한다.</p>
<h3 id="장바구니-체크박스에-onchange-이벤트-주기-🙌">장바구니 체크박스에 onChange 이벤트 주기 🙌</h3>
<p>각 장바구니 상품에는 하나의 체크박스가 있다. 이 체크박스에 중요한것은 지정된 id, onChange가 일어났을때 실행되는 함수, 그리고 checked라는 boolean값이다.</p>
<p>처음에는 이 boolean값을 state로 관리했다. 그리고 <code>onChange</code> 이벤트가 발동되면 <code>setState</code>를 통해 <code>false</code> -&gt; <code>true</code> 로 바꾸려고 했다. 그랬더니 발생한일... 모든 체크박스가 같이 동기화 되어버린다. 물론 각각의 checkbox에 각자 다른 state를 지정해줘서 따로 관리한다면 상관없다. 하지만 누군가가 말씀하신대로 항상 1000개의 데이터가 넘어올수도 있다는 가정하에 각각의 state로 관리하지 못하기 때문에 state로 관리하는것은 적합하지 않다고 판단했다.</p>
<pre><code class="language-jsx">//CartItem.js 장바구니 아이템 한줄의 Component
&lt;input
className=&quot;checkBoxinCartItem&quot;
type=&quot;checkbox&quot;
id={id}
onChange={this.props.onChecked}
checked={this.props.cartItem.value}
/&gt;</code></pre>
<p>처음에 백앤드에서 넘어오는 데이터에는 상품이름, 상품가격, 상품수량은 있지만 상품의 checked에 대한 값은 없다. 그러므로 <code>onChange</code>이벤트가 일어날때마다 <code>handleChange</code> (props는 <code>onChecked</code>)라는 함수를 통하여 <code>checked</code>에<code>boolean</code>값을 준다.</p>
<pre><code class="language-jsx">//Cart.js 장바구니의 최상위 부모 Component
  handleChange = e =&gt; {
    const id = e.target.id;
    this.setState(prevState =&gt; ({
      cartList: prevState.cartList.map(item =&gt;
        item.productId === +id ? { ...item, value: e.target.checked } : item
      ),
    }));
  };</code></pre>
<p>체크박스를 클릭할때마다 (<code>onChange</code> 이벤트가 일어날때마다) <code>handleChange</code>라는 함수는 <code>checked</code>의 값을 하나씩 준다. 이게 말로 하면 이해가 잘 안되지만 콘솔을 찍어보면 이해가 된다.</p>
<p><code>this.props.cartItem.value</code>를 처음 페이지가 렌더 되었을때 콘솔에 찍어보면
<img src="https://images.velog.io/images/hi-yjs/post/32136fa7-4026-4b65-9e5f-c1f32719b28a/Screen%20Shot%202021-02-28%20at%205.41.15%20PM.png" alt="">
<code>undefined</code>가 뜬다. 세번 뜨는 이유는 장바구니 아이템이 3개라서!
즉 처음에 <code>checked = {this.props.cartItem.value}</code>는 <code>undefined</code>라는 뜻이다. 허나 만약 <code>onChange</code> 이벤트, 즉 체크박스를 한번 클릭을 해보면, </p>
<p><img src="https://images.velog.io/images/hi-yjs/post/337c0ff2-31a9-41b3-8ad9-4b52feee3867/Screen%20Shot%202021-02-28%20at%205.43.34%20PM.png" alt=""></p>
<p>상품 하나를 눌렀기때문에 하나만 <code>true</code>고 아직 <code>onChange</code>가 일어나지않은 나머지 상품 두개는 <code>undefined</code>가 뜬다. 만약 이 상품을 재클릭을 하여 체크를 없앤다면,
<img src="https://images.velog.io/images/hi-yjs/post/e70ea8ad-c42e-40d3-9e4f-f003108088d2/Screen%20Shot%202021-02-28%20at%205.47.05%20PM.png" alt=""></p>
<p>두둥! <code>false</code> 하나, <code>undefined</code> 둘!
<code>onChange</code>가 일어나야만 <code>handleChange</code>라는 함수가 실행되면서 boolean 값을 할당 받는다. </p>
<p>체크박스에 대한 모든것들을 구현하기전에 먼저 이 <code>handleChange</code>라는 함수를 통해 value에 <code>true</code> or <code>false</code>를 주는게 먼저다.</p>
<h3 id="전체선택-전체해제--전체선택-후-하나를-해제했을때-전체선택-해제하기-구현하기-🙌">전체선택, 전체해제 &amp; 전체선택 후 하나를 해제했을때 전체선택 해제하기 구현하기 🙌</h3>
<p>200문방구의 장바구니 같은 경우 전체선택, 전체해제가 가능한 체크박스가 테이블의 header에 있다. </p>
<p><img src="https://images.velog.io/images/hi-yjs/post/5b7d856b-4a5e-4830-a6b8-b700b7930169/Screen%20Shot%202021-02-28%20at%206.38.36%20PM.png" alt=""></p>
<p>이 테이블의 header에 해당하는 부분은 <code>CartList.js</code>라는 컴포넌트에 있다. 코드는 다음과 같다.</p>
<pre><code class="language-jsx">// CartList.js
 &lt;input
 className=&quot;checkBoxInputInCartList&quot;
type=&quot;checkbox&quot;
onClick={handleAllChecked}
checked={cartList.every(item =&gt; item.value === true)}
/&gt;</code></pre>
<p><code>onClick</code>이 일어날경우 <code>handleAllChecked</code>라는 함수가 발동된다. 이 함수는 다음과 같다.</p>
<pre><code class="language-jsx">//Cart.js
handleAllChecked = e =&gt; {
    let cartList = this.state.cartList;
    cartList.forEach(item =&gt; (item.value = e.target.checked));
    this.setState({ cartList });
  };</code></pre>
<p>함수가 발동될경우, <code>this.state.cartList</code>에 있는 모든 아이템의 value에게 <code>checked = true</code>값을 준다.</p>
<p>그러므로 만약 전체선택이 되었을경우,</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/5620f6e0-2c7f-46bb-b003-2b0cc24efece/Screen%20Shot%202021-02-28%20at%206.43.00%20PM.png" alt=""></p>
<p>전체해제가 될 경우,</p>
<p><img src="https://images.velog.io/images/hi-yjs/post/401a1996-29ba-4bbb-8b35-9a3d783a9311/Screen%20Shot%202021-02-28%20at%206.43.05%20PM.png" alt=""></p>
<p>여기서 추가적으로 더 구현하고 싶었던 기능이 만약 전체 선택이 되었는데 하나가 해제되었을경우 전체 선택이 해제가 되게! 하고 싶어서 구글을 더 찾아봤다 ㅋㅋ 🧐 여러 고민과 멘토님들께 자문을 구한 결과,</p>
<pre><code class="language-jsx">//CartList.js 전체선택 체크박스
checked={cartList.every(item =&gt; item.value === true)</code></pre>
<p>전체선택 체크박스의 checked의 값을 만약 모든 아이템이 true일경우만 true가 뜨게 하면 된다는 아주 간단한 코드로 구현할수있었다~ 🥳</p>
<h3 id="선택된-상품만-삭제하기-🙌">선택된 상품만 삭제하기 🙌</h3>
<pre><code class="language-jsx">//Cart.js
handleDelete = () =&gt; {
    const cartDelete = this.state.cartList.filter(item =&gt; item.value);
    const cartMap = cartDelete.map(item =&gt; item.cartId);
    const deleteUrl = cartMap
      .map(e =&gt; {
        return [&#39;cartId&#39;, e];
      })
      .map(e =&gt; e.join(&#39;=&#39;))
      .join(&#39;&amp;&#39;);

    fetch(`CARTAPI?${deleteUrl}`, {
      method: &#39;DELETE&#39;,
      headers: {
        Authorization: localStorage.getItem(&#39;accessToken&#39;),
      },
    })
      .then(response =&gt; response.json())
      .then(res =&gt; {
        if (res.message === &#39;SUCCESS&#39;) {
          alert(&#39;선택 상품을 삭제 완료 하였습니다.&#39;);
        } else alert(&#39;선택 상품 삭제를 실패 하였습니다&#39;);
      });
    this.setState(prevState =&gt; ({
      cartList: prevState.cartList.filter(item =&gt; !item.value),
    }));
  };</code></pre>
<p>처음에는 백앤드에게 body에 어떤 상품들이 삭제되는지 아이디를 담아서 보내주려고 했다. 심지어 이렇게 성공했다! 그러나 백앤드 멘토님의 리뷰에서 이렇게 하는것보다 delete 메소드를 통해 query string에 어떤 아이디가 지워지는지 알려주는게 맞다라고 하셔서 코드를 수정했다.</p>
<p>위의 코드를 설명하자면, 먼저 cartDelete라는 변수를 만들어서 장바구니에 있는 아이템들중에 선택된것만 필터를 한다. 그러고 cartMap이라는 변수로 선택된 아이템들의 아이디값만 뽑아낸다. <code>[4, 5]</code> 라는 숫자로만 이루어진 배열이 나온다. 이제 여기서 해야할것 ! 이 4와 5라는 숫자를 <code>&#39;cartId=4&amp;cartId=5&#39;</code>라는 스트링으로 만들어서 fetch하는 API뒤에 붙여준다. 여기서 정말 코트카타를 해서 이걸 구현했어야했는데 팀에 코드카타의 신이 계셔서 한번에 해결해주셨다...! 아멘 🙏</p>
<p>이런식으로 백앤드에게 어떤 id를 가진 상품이 삭제되는지 알려주고 만약 SUCCESS가 뜬다면 선택상품을 삭제 완료했다는 알림이 뜨고 setState를 통해 프론트에서 알아서 그 선택 상품들을 지워버렸다. 백앤드에게 SUCCESS메세지와 함께 수정된 cartList를 받아와서 뿌리는 방법도 있었지만 이미 구현해놓은 코드들이 있어서 불필요 했다.</p>
<h3 id="장바구니-구현-🙌">장바구니 구현 🙌</h3>
<h4 id="상품-수량-바꾸기">상품 수량 바꾸기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/c44e093d-c0be-424c-a391-305b279aa253/cartqty.gif" alt=""></p>
<h4 id="선택된-상품만-계산하기">선택된 상품만 계산하기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/0fef6cec-9248-43ce-b19f-866cffc39fbb/%E1%84%89%E1%85%A5%E1%86%AB%E1%84%90%E1%85%A2%E1%86%A8%E1%84%89%E1%85%A1%E1%86%BC%E1%84%91%E1%85%AE%E1%86%B7%E1%84%80%E1%85%A8%E1%84%89%E1%85%A1%E1%86%AB.gif" alt=""></p>
<h4 id="선택된-상품-삭제하기">선택된 상품 삭제하기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/0f50fe31-3af2-42cd-affb-e8eedd39262e/%E1%84%89%E1%85%A5%E1%86%AB%E1%84%90%E1%85%A2%E1%86%A8%E1%84%89%E1%85%A1%E1%86%BC%E1%84%91%E1%85%AE%E1%86%B7%E1%84%89%E1%85%A1%E1%86%A8%E1%84%8C%E1%85%A6.gif" alt=""></p>
<h4 id="전체선택-및-전체선택해제-하기">전체선택 및 전체선택해제 하기</h4>
<p><img src="https://images.velog.io/images/hi-yjs/post/e4cd2b8f-6700-423c-a1b5-8b3a30872daa/%E1%84%8C%E1%85%A5%E1%86%AB%E1%84%8E%E1%85%A6%E1%84%89%E1%85%A5%E1%86%AB%E1%84%90%E1%85%A2%E1%86%A8.gif" alt=""></p>
<h3 id="장바구니-구현-후기-🙌">장바구니 구현 후기 🙌</h3>
<p>솔직히 메인을 구현할때는 뭔가를 배웠다 라는 느낌을 전혀 못받았는데 장바구니를 구현하면서 백앤드와 어떤식으로 소통을 해야하는지, 어떤식으로 코드를 짜야하는지, 그리고 체크박스를 어떻게 활용하는지에 대해서 너무 많이 배웠다. 특히, 체크박스에 대해서 알아보기 시작한게 금요일밤이였는데 그 다음주 화요일 새벽에 기나긴 투쟁 끝에 체크박스를 정복했다 ..... 구글에 있는 모든 관련 문서는 다 읽은것 같다... 가장 시간을 많이 투자한 페이지인만큼 가장 뿌듯한 페이지다 🥰 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CodeKata | Week 3 Day 5]]></title>
            <link>https://velog.io/@hi-yjs/CodeKata-Week-3-Day-5</link>
            <guid>https://velog.io/@hi-yjs/CodeKata-Week-3-Day-5</guid>
            <pubDate>Sun, 21 Feb 2021 10:50:10 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>재귀를 사용하여 팩토리얼(factorial)을 구하는 함수를 구현해주세요.
팩토리얼이란 1에서부터 n까지의 정수를 모두 곱한것을 말합니다.</p>
<pre><code>1! = 1
2! = 1 * 2
5! = 1 * 2 * 3 * 4 * 5</code></pre><h3 id="첫번째-접근">첫번째 접근</h3>
<pre><code class="language-javascript">const factorial = n =&gt; {
  return n * factorial(n-1)
}</code></pre>
<p>...로딩이 안된다...왜냐..! n이 끝나는 지점을 안정해줘서!</p>
<h3 id="두번째-접근">두번째 접근</h3>
<pre><code class="language-javascript">const factorial = n =&gt; {
    if (n===0) return 1
  return n * factorial(n-1)
}</code></pre>
<p><code>n=0</code>이면 끝나~~ 라고 지정해줬더니 👍 성공 👍 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CodeKata | Week 3 Day 4]]></title>
            <link>https://velog.io/@hi-yjs/CodeKata-Week-3-Day-4</link>
            <guid>https://velog.io/@hi-yjs/CodeKata-Week-3-Day-4</guid>
            <pubDate>Sun, 21 Feb 2021 10:38:58 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>주어진 숫자 배열에서, 0을 배열의 마지막쪽으로 이동시켜주세요.
원래 있던 숫자의 순서는 바꾸지 말아주세요.</p>
<p>(새로운 배열을 생성해서는 안 됩니다.)</p>
<pre><code>Input: [0,1,0,3,12]
Output: [1,3,12,0,0]</code></pre><h3 id="첫-접근">첫 접근</h3>
<pre><code class="language-javascript">const moveZeroes = nums =&gt; {
for (i=0; i&lt;nums.length; i++) {
  if(nums[i]===0){
    nums.push(nums.splice(i, 1)[0])
  }
}
return nums}</code></pre>
<p>응 안돼 ,,,, 돌아가,,,, 
배열안에 0이 하나인경우는 가능하지만 0이 뜨는 순간 끝나버려서 0이 두개이상일 경우 for-loop이 안돈다......</p>
<h3 id="두번째-접근">두번째 접근</h3>
<pre><code class="language-javascript">const moveZeroes = nums =&gt; {
newArr =[]
trashArr =[]
for(i=0; i&lt;nums.length;i++) {
  if(nums[i] !== 0) {
    newArr.push(nums[i])
  } else (trashArr.push(nums[i]))
} 
for(i=0; i&lt;trashArr.length;i++){
  newArr.push(0)
} 
return newArr
};</code></pre>
<p>ㅎㅎ..누가봐도 메모리낭비 시간낭비 쓸데없이 긴 코드 ... 분명 더 짧게 할수 있는 방법이 있을텐데 일단 해봤다 ... 배열을 쭉 돌면서 0이면 trashArr에 넣고, 0이 아니면 newArr에 넣고 나중에 newArr에 trashArr.length만큼 0을 집어넣어버렸다..결과는 🙌 통과 🙌 </p>
<p>암튼 통과하긴했는데 이건 아니다 싶어서 구글선생님에게 도움을 요청하여 다른 사람들의 접근 방식을 찾아보았다.</p>
<h3 id="세번째-접근">세번째 접근</h3>
<pre><code class="language-javascript">const moveZeroes = nums =&gt; {
  for(i = nums.length-1; i &gt;= 0; i--){
    if(nums[i]===0){
      nums.push(nums.splice(i, 1)[0]);
    }
  }
  return nums
};</code></pre>
<p>하...뒤에서 부터 돌리면 되는구나.....i=0부터 돌려야한다는 편견을 아직도 버리지 못해서 여기까지 생각을 못했다....😭😭</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민문방구 | 1차 프로젝트 Part. 2]]></title>
            <link>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-2</link>
            <guid>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-2</guid>
            <pubDate>Sun, 21 Feb 2021 09:55:03 GMT</pubDate>
            <description><![CDATA[<h2 id="nav-bar와-footer-🍒">Nav Bar와 Footer 🍒</h2>
<p>메인을 맡으면서 자연스럽게 Nav Bar와 Footer까지 만들게 되었다. 
사실 Nav Bar 같은 경우 아직 링크를 건게 아니기 때문에 기능 구현을 지금 당장 할수있는건 없었지만 도전해보고 싶었던 &#39;스크롤을 내리면 위로 쭉 올라가는 nav bar&#39;를 만들수있었다.</p>
<h3 id="1-nav-bar">1) Nav Bar</h3>
<p>🔎 실제 배민문방구 Nav Bar
<img src="https://images.velog.io/images/hi-yjs/post/7f5933dc-49ed-4a41-8a32-820e2c3c29ae/%E1%84%82%E1%85%A6%E1%84%87%E1%85%B3%E1%84%87%E1%85%A1.gif" alt=""></p>
<p>처음에는 실제 저 로고를 감싸고 있는 div box를 줄여야하나 고민하던 찰나에 또 생각난 조건부렌더링...ㅋㅋㅋㅋ</p>
<pre><code class="language-javascript">this.state = {
      navScrolled: false
    };
</code></pre>
<p>일단 현재 navScrolled를 false로 지정해 놓았다.</p>
<pre><code class="language-javascript">componentDidMount() {
    window.addEventListener(&#39;scroll&#39;, this.handleScroll);
  }

  handleScroll = () =&gt; {
    this.setState({ navScrolled: window.pageYOffset &gt; 200 });
  };</code></pre>
<p>componentDidMount를 통해 윈도우에서 스크롤이 된다면~ <code>handleScroll</code>이라는 함수를 실행해! 라고 지정해 주었다. <code>handleScroll</code>은 만약 Y의 offset이 200이 넘는다면 <code>navScrolled</code>의 값을 <code>true</code>로 바꿔준다. </p>
<p>🌈 두개의 nav bar에 대한 코드 🌈</p>
<pre><code class="language-javascript">{!navScrolled &amp;&amp; (
          &lt;main className=&quot;mainNav&quot;&gt;
        ///처음에 보여지는 큰 main Nav
          &lt;/main&gt;
        )}
{navScrolled &amp;&amp; (
          &lt;div className=&quot;subNav&quot;&gt;
          ///스크롤이 내려지면 보이는 sub Nav
          &lt;/div&gt;
        )}
</code></pre>
<p>또건부 렌더링..을 통해 만약에 <code>navScrolled = true</code>일때 보여주는 nav bar와 <code>navScrolled = false</code> 일때 보여주는 nav bar를 다르게 했다.</p>
<p>그렇게해서 구현된 이백문방구의 nav bar ~~
<img src="https://images.velog.io/images/hi-yjs/post/5a57473c-3588-4366-9a81-d0eaab16a720/Screen%20Shot%202021-03-02%20at%2012.31.11%20AM.png" alt=""></p>
<p><img src="https://images.velog.io/images/hi-yjs/post/1611343b-57d8-4c94-b6ba-39e5d3c32e8f/nav%20bar%202.gif" alt=""></p>
<p>hover효과가 없으면 아쉽기에... 원래 사이트에는 없는 hover 효과들을 추가해서 구현했다.</p>
<h3 id="2-footer">2) Footer</h3>
<p><img src="https://images.velog.io/images/hi-yjs/post/2681f44a-4588-4ed0-a5f2-730d5e8e09a4/Screen%20Shot%202021-02-21%20at%206.51.59%20PM.png" alt=""></p>
<p>Footer에는 딱히 기능 구현을 하지 않았다. 링크는 걸어놨지만 굳이 따로 뭘 해야할 기능을 찾지 못했다.</p>
<p>*<em>참고로 Nav와 Footer에 들어간 사진들은 갓성준님이 만들어주신 로고들을 사용했다👍 *</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민문방구 | 1차 프로젝트 Part. 1]]></title>
            <link>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-1</link>
            <guid>https://velog.io/@hi-yjs/%EB%B0%B0%EB%AF%BC%EB%AC%B8%EB%B0%A9%EA%B5%AC-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-Part.-1</guid>
            <pubDate>Sun, 21 Feb 2021 09:32:18 GMT</pubDate>
            <description><![CDATA[<p>2월 15일 월요일부터 시작된 1차 프로젝트 배민문방구~ 
지금까지 기능 및 UI 구현한것들을 정리해보았다.</p>
<h2 id="메인페이지-🍒">메인페이지 🍒</h2>
<p>🔎 실제 메인페이지
<img src="https://images.velog.io/images/hi-yjs/post/e9a22aed-1220-4553-b26d-16a9d25a9d8b/Screen%20Shot%202021-02-21%20at%206.06.00%20PM.png" alt=""></p>
<p>배민문방구의 UI는 심플하고 화려한 hover효과 같은게 없었다. </p>
<h3 id="1-메인-슬라이더">1) 메인 슬라이더</h3>
<p>항상 설치해서 쓰고 싶었던 react-slick을 이용하여 슬라이드를 구현했다. </p>
<p><img src="https://images.velog.io/images/hi-yjs/post/cbfc4d9a-aa8a-4255-9792-381e2888a3aa/mainslide.gif" alt=""></p>
<p>많은 사람들이 이용하는 라이브러리인만큼 딱히 이해하기 어려운 부분은 없었다. 밑의 초기 세팅도 잘 정리되어 있어서 구현하기 편했던것 같다.</p>
<p>슬라이더 코드 </p>
<pre><code class="language-javascript">render() {
    const settings = {
      dots: true,
      infinite: true,
      speed: 500,
      slidesToShow: 1,
      slidesToScroll: 1,
      autoplay: true,
      autoplaySpeed: 1000,
    };
    return (
      &lt;div className=&quot;Slider&quot;&gt;
        &lt;Slider {...settings}&gt;
          {this.state.sliderList.map((data, idx) =&gt; {
            return (
              &lt;div className=&quot;sliderItem&quot; key={idx}&gt;
                &lt;img alt={data.name} src={data.src} /&gt;
              &lt;/div&gt;
            );
          })}
        &lt;/Slider&gt;
      &lt;/div&gt;
    );
  }</code></pre>
<p>  슬라이더에 있는 사진 같은 경우, 백엔드에서 굳이 보내줄 필요가 없는 데이터이기 때문에 직접 data.js파일을 만들어서 import해왔다.</p>
<h3 id="2-베스트상품-신상품-세일상품-리스트">2) 베스트상품, 신상품, 세일상품 리스트</h3>
<p>배민문방구의 메인 페이지에는 크게 3개의 상품리스트를 보여주고 있다: 베스트, 신상, 세일. 심플하게 4개 혹은 8개씩 보여주는 상품리스트 3개가 구현해야 했다. Display: Grid를 사용하여 4개씩 정렬했다.</p>
<p>일단 처음에는 Best.js, Sale.js, New.js로 따로따로 파일 만들어서 import해왔다...그런데, 아무래도 헤더와 4개(혹은 8개) 상품리스트라는 형식이 반복되다보니 코드가 똑같았다..! 🤯 여기서 다시 짚고 넘어가는 컴포넌트의 뜻: 재사용 가능한 UI 단위. 즉 세개의 다른 파일들을 한파일로 합쳐서 재사용이 가능했다. 그래서 나온 코드:</p>
<p>🌈 각 상품 박스 하나에 대한 코드 🌈</p>
<pre><code class="language-javascript">render() {
    return (
      &lt;div className=&quot;ProductBox&quot;&gt;
        &lt;div
          className=&quot;productImage&quot;
          style={{
            backgroundImage: `url(${imgSrc})`,
          }}
        &gt;
          &lt;div className=&quot;labelContainer&quot;&gt;
            {isBest &amp;&amp; &lt;span className=&quot;isBest&quot;&gt; BEST &lt;/span&gt;}
            {isNew &amp;&amp; &lt;span className=&quot;isNew&quot;&gt;NEW&lt;/span&gt;}
            {isSale &amp;&amp; &lt;span className=&quot;isSale&quot;&gt; SALE &lt;/span&gt;}
          &lt;/div&gt;
          &lt;div className=&quot;hoverContainer&quot;&gt;
            &lt;div onClick={this.goToMyPage} className=&quot;hoverHeart&quot;&gt;
              &lt;i className=&quot;far fa-heart&quot; /&gt;
            &lt;/div&gt;
            &lt;div onClick={this.goToCart} className=&quot;hoverCart&quot;&gt;
              &lt;i className=&quot;fas fa-shopping-cart&quot; /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        {sale &gt; 0 &amp;&amp; &lt;span className=&quot;sale&quot;&gt; {saleNumber}%&lt;/span&gt;}
        &lt;p&gt;{name}&lt;/p&gt;
        {saleNumToInt === 0 &amp;&amp; &lt;p className=&quot;price&quot;&gt;{originalPrice}원&lt;/p&gt;}
        {sale &gt; 0 &amp;&amp; (
          &lt;div className=&quot;priceContainer&quot;&gt;
            &lt;p className=&quot;oldPrice&quot;&gt; {originalPrice}원 &lt;/p&gt;
            &lt;p className=&quot;salePrice&quot;&gt;{finalPrice}원&lt;/p&gt;
          &lt;/div&gt;
        )}
      &lt;/div&gt;
    );
  }
}</code></pre>
<p>조건부렌더링을 통해서 넘어노는 세일을 하는 상품일 경우 (세일 숫자가 0이 아닌게 넘어올경우) Sale이라는 라벨을 붙여주고, Best일경우 베스트를 붙여주고 신상품일 경우 New라는 라벨을 붙여줬다.
여기서는 기억하고 싶은 코드라기보단...계산식들을 구현하는게 재밌었다. 처음에는 백앤드에서 만약 10%세일 상품이라면 세일 숫자 10과 원래 가격을 넘겨주고 10과 원래 가격으로 세일가격을 찾는 수학계산을 프론트에서 해서 화면에 보여줘야했는데 멘토님들과의 리뷰후, 10을 넘겨주지 않고 0.10 이라는 숫자를 넘겨준다고해서 다시 바꿨다. 이래서 끊임없는 소통이 중요해... </p>
<p>🌈 각 상품의 할인율, 원래가격, 세일가격 계산식 🌈</p>
<pre><code class="language-javascript">    const saleNumber = this.props.sale * 100;
    const originalPrice = Math.ceil(this.props.price).toLocaleString();
    const finalPrice = (
      Math.round((this.props.price * (1 - this.props.sale)) / 100) * 100
    ).toLocaleString();</code></pre>
<p>프론트에서 보여줘야하는 숫자들은 10 이라는 숫자와 원래가격, 세일가격이다. 그래서 모든 숫자들을 형식에 맞게 수식을 돌리고 백단위로 반올림을 하여 toLocaleString()을 통해서 천단위로 콤마를 찍어줬다. </p>
<p>그렇게 구현된 메인의 상품리스트~
<img src="https://images.velog.io/images/hi-yjs/post/2af5ac71-5d0e-4763-b398-dff28f099857/Screen%20Shot%202021-02-21%20at%206.25.34%20PM.png" alt=""></p>
<p>하나씩 살펴본다면,
<img src="https://images.velog.io/images/hi-yjs/post/d710027a-7e56-4c2e-9790-566bb2e1f12d/Screen%20Shot%202021-02-21%20at%206.25.44%20PM.png" alt=""></p>
<p>만약 할인율이 있다면 상품이름 위에 할인율을 보여주는 조건부렌더링을 통해서 구현했다. 메인페이지를 만들었는데 상품리스트 페이지 연습까지 된것 같아서 좋았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA["미래의 나" 보라고 쓰는 기록]]></title>
            <link>https://velog.io/@hi-yjs/%EB%AF%B8%EB%9E%98%EC%9D%98-%EB%82%98-%EB%B3%B4%EB%9D%BC%EA%B3%A0-%EC%93%B0%EB%8A%94-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@hi-yjs/%EB%AF%B8%EB%9E%98%EC%9D%98-%EB%82%98-%EB%B3%B4%EB%9D%BC%EA%B3%A0-%EC%93%B0%EB%8A%94-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Sat, 20 Feb 2021 03:52:13 GMT</pubDate>
            <description><![CDATA[<h4 id="1년전-나의-상황🎈">1년전 나의 상황🎈</h4>
<ul>
<li>2020년 2월에 나는 몇년간 미루던 이직준비를 열심히해서 다른주! 다른회사!로부터 인터뷰 제의를 받고 열심히 인터뷰 준비중이였다. </li>
<li>그러다가 3월에 미국내 코로나가 아주 심각해지면서 모든 회사의 채용절차가 STOP⛔ 인터뷰 3번 해놓고 마지막 현장 인터뷰만 남았는데 그건 보게 해주지,,,</li>
<li>끝나가는 20대 ... 점점 굳어지는게 느껴지는 뇌 (기억이 안나...암산이 안돼...) 이대로 가다간 도태각이다! 싶었고 지금 코로나 상황이 심각해서 가족과 떨어져 혼자 미국에 있는게 너무 불안하여 길고 길었던 미국생활을 정리하고 2020년 8월에 귀국했다.</li>
</ul>
<h4 id="코딩을-왜--👩💻">코딩을 왜 ...? 👩‍💻</h4>
<ul>
<li>사실 처음에 배우려고했던 제일 큰 이유는 워라밸 ... 그리고 연봉 ...</li>
<li>분명 나랑 같은 연차인 친구들이 나의 2배이상을 벌고 나보다 워라밸이 좋다..? 한달에 한번 당일통보로 오대양을 건너갈수도 있는 장거리 출장도 없고 몇년동안 일하면서 아시아계나 여자를 본적이 한손에 꼽고 (여자화장실도 없던 축구장 몇백갠지 몇천개 크기라고 자랑하던 네덜란드에 있는 그 회사ㅋ 평생 기억한다,,) 학교 다닐때 미식축구 했을것만 같은 덩치 산만한 백인 남자들이 주도하는 직종도 아니고. 코로나가 터지기전에도 재택근무를 하다니 ... 너무 부러웠다 ... </li>
</ul>
<h4 id="왜-프론트엔드-🤖">왜 프론트엔드..? 🤖</h4>
<ul>
<li>솔직히 백엔드하면 대학원 옵션도 넓어지고 비싼 내 기계공학 학위도, 꾸역꾸역 쌓아온 몇년간의 경력도 인정 받는쪽으로 어떻게든 취직도 해볼수있을것 같은데 아무리 생각해도 나는 프론트엔드가 적성에 맞다. 정말 몇달동안 고민을 많이 했는데 지금은 내가 배우고 싶은것을 배우는게 맞다고 생각해서 프론트로 정해버렸다. </li>
<li>확실히 눈에 보이는게 너무 좋다. 바로바로 확인할수 있으니깐 답답하지도 않고 디테일에 민감하게 반응하는 내 뇌를 보니 이거다 싶다. 👀</li>
</ul>
<h4 id="현재-나의-상황-🙉">현재 나의 상황 🙉</h4>
<ul>
<li>처음엔 걱정이 되면서도 기대가 되었다. </li>
<li>답은 있지만 여러갈래의 길이 존재하고 어떻게 구현할껀지 전체적으로 기획하고 실행하는게 내 적성에 딱 맞다. 거기에 논리력까지 필요하다니. &quot;아 대학때 이거 전공할껄 ....🤦‍♀️&quot;
<img src="https://images.velog.io/images/hi-yjs/post/4af79b6a-7c9d-4fc0-859d-90f6b93263a7/image.png" alt=""></li>
<li>ㅇㅈ. 나는 다른 전공자들에 비해서 8년 늦었다. 그래서 그냥 그 사람들이 지금까지 해왔던것을 단기간내에 발끝정도라도 따라잡기 위해선 그 사람들 몇배의 노력을 해야한다고 생각한다. </li>
<li>고등학교입시, 대학교입시때도 이렇게 공부 안했는데 ... 지금이랑 그때랑 다른건 내 돈으로! 내가 하고싶어서! 배우는거라 그런가? 진짜 하루종일 매일 매일 공부중이다. 부트캠프를 시작한후에 밤에 잠잘때 &#39;오늘 하루 허투루 보냈구나,,,&#39;라는 생각을 한적이 단 한번도 없는것 같다.</li>
<li>나는 몇년간 일하면서 &quot;빡세게(?)&quot; 머리를 쓰면서 살았던적이 없으니 (맨날 캐드로 그림만 그리고 기계만 만졌어 ...) 공부머리도 한동안 쉬어서 컨디션이 좋은건지 머리가 나름 20대 초반처럼 돌아가는것 같다 😁</li>
</ul>
<h4 id="앞으로-두달-남았는데--🏃♀️🏃♀️🏃♀️">앞으로 두달 남았는데 ... 🏃‍♀️🏃‍♀️🏃‍♀️</h4>
<ul>
<li>지금까지 달려온것처럼 남은 두달도 달릴 예정... 진짜 고등학교때 이렇게 공부했으면 하버드 갔다 🤪</li>
</ul>
<p>🤐원래 이런거 진짜 안쓰는데 ... 건망증이 심해지는 요즘... 미래의 내가 이걸 보고 웃으라고 씀.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programmers | #13]]></title>
            <link>https://velog.io/@hi-yjs/Programmers-13</link>
            <guid>https://velog.io/@hi-yjs/Programmers-13</guid>
            <pubDate>Sun, 14 Feb 2021 11:53:41 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-설명">문제 설명</h3>
<p>자연수 N이 주어지면, N의 각 자릿수의 합을 구해서 return 하는 solution 함수를 만들어 주세요.
예를들어 N = 123이면 1 + 2 + 3 = 6을 return 하면 됩니다.</p>
<h3 id="제한사항">제한사항</h3>
<p>N의 범위 : 100,000,000 이하의 자연수</p>
<h3 id="입출력-예">입출력 예</h3>
<p><img src="https://images.velog.io/images/hi-yjs/post/24ca306a-6a56-45bd-b242-be7b0fa215fe/Screen%20Shot%202021-02-14%20at%208.47.57%20PM.png" alt=""></p>
<h3 id="나의-풀이">나의 풀이</h3>
<pre><code class="language-javascript">function solution(n){

return n.toString().split(&quot;&quot;).reduce((prev, curr) =&gt; prev+parseInt(curr),0)

}</code></pre>
<p>와~ 한줄만에 끝냈다~~🥳</p>
<h3 id="다른-사람의-풀이를-보고-리뷰">다른 사람의 풀이를 보고 리뷰</h3>
<pre><code class="language-javascript">n=123
n.toString().split(&quot;&quot;) // [ &#39;1&#39;, &#39;2&#39;, &#39;3&#39; ]
a = (n + &quot;&quot;).split(&quot;&quot;) // [ &#39;1&#39;, &#39;2&#39;, &#39;3&#39; ]</code></pre>
<p>처음 받은 n을 배열안에 각각의 string으로 만드는 두가지 방법! 두번째 방법 같은 경우는 꼭 변수 선언을 해줘야한다.</p>
]]></description>
        </item>
    </channel>
</rss>