<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>개발새발 개발중</title>
        <link>https://velog.io/</link>
        <description>프론트엔드 개발 지망</description>
        <lastBuildDate>Thu, 18 Jan 2024 14:45:37 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>개발새발 개발중</title>
            <url>https://images.velog.io/images/ecof_/profile/4d4eacac-b758-4983-a140-4f4f96c4b65c/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 개발새발 개발중. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ecof_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[프론트엔드 개발 2023 회고록]]></title>
            <link>https://velog.io/@ecof_/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-2023-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@ecof_/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-2023-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Thu, 18 Jan 2024 14:45:37 GMT</pubDate>
            <description><![CDATA[<p>22년도 말에 프론트엔드 개발자로 취업에 성공하여 해가 바뀌며 딱 1년을 맞이하게 되어 새해이자 1주년 기념의 회고록이다.</p>
<h1 id="회사가-작아요-사수가-없어요">회사가 작아요 사수가 없어요</h1>
<p>작은 회사에 취업하게 되었다. 사원의 수가 웬만한 IT 회사의 개발팀 보다 작은 곳에 취업을 하게 되면서 프론트엔드 직군의 사수 없이, 연차가 많으신 백엔드 1명, 나와같은 신입 백엔드 1명, 프론트엔드 1명(나) 단 세명의 오합지졸 같은 개발팀을 꾸리게 되었다.
어디선가 사수가 없으면 도망가라는 말을 들었던것 같지만 몇번의 면접탈락으로 멘탈이 흔들리고 있던 나는 우선 지켜보기로 결정했다.</p>
<h3 id="서류작성-그게-뭐죠">서류작성? 그게 뭐죠?</h3>
<p>보통 신입은 코드작성보다 서류작성을 더 많이 한다고 들었었다. 또 그보다 많은 서류를 읽어야 한다고 들었다. 웹 기획서, 사이트 맵, API DOC, 와이어프레임, 스타일 가이드, 기존 프로젝트의 설계서들 여러가지 서류를 읽고 접하고 쓰게될줄 알았지만 자리를 안내받고 몇가지 컴퓨터 세팅을 하고는 바로 전임자가 만들었던 앱의 코드 수정을 요청받았다.
문서는 쓸것도 없었고 읽을것도 없었기에 코드를 읽고 쓰기 시작했다.</p>
<h3 id="typescript-귀찮아요">Typescript 귀찮아요</h3>
<p>에러를 위해 타입스크립트에 대한 이야기를 꺼내고 들은 이야기다. 이 회사의 개발문화는 두사람이 신입인 만큼 연차가 오래되신 백엔드 개발자분이 최종 결정권자 라고 봐도 무방한데, 그분께서 타입스크립트는 귀찮다 라고 일축하신 덕분에 타입스크립트는 강의로만 보고 묻어두게 되었다.
물론 내가 그 분을 설득할정도로 타입스크립트에 대한 장점을 논리있게 정리하지 못한 탓도 있기 때문에 꾸준히 기회를 노리고 있다. 타입스크립트의 필요성에 대한 어필을.</p>
<h3 id="리펙토링할-시간에-프로덕트-개발">리펙토링할 시간에 프로덕트 개발</h3>
<p>기획자가 없다. 웹디자이너가 없다. 퍼블리셔가 없다. 보통 프로덕트에 대한 아이디어는 대표님이 내신다. 회사안에 개발자로만 되어있는 또다른 회사가 있고 대표님이 클라이언트인 격이다. 대표님은 야망이 크시다. 아이디어도 수시로 떠오르시고 추진력도 좋으시다. 문제는 아이디어를 말하고 나면 이미 개발이 완료된 취급을 하고 개발이 완료되었다 말해드리면 테스트 과정없이 프로덕트 취급을 한다는 것이다. 기존 코드의 리펙토링에 눈이 돌아갈 시간이 없다.
그저 앞으로 앞으로.</p>
<h1 id="근데-왜-이직-안함">근데 왜 이직 안함?</h1>
<p>처음엔 경력을 위해 1년만 버티자 하는 마음이었다. 물론 1년을 오롯이 버티는게 아닌 조금만 수틀려도 나와버려야지 하는 위태로움 버팀이었다. 위에 내가 느낀 저 단점들은 이 회사에서 오랫동안 일하다가 회사를 나와 다른 회사로 가게 되었을때 개발팀에 어울리지 못하는 안하무인 개발자가 되어있을까봐 하는 두려움을 주는 단점들이었기 때문이었다.
1년째가 되어간 지금 연봉협상또한 협상이 아닌 통보를 받은 이 시점에서 나는 이직을 선택하지 않았다. 많은 개발자 커뮤니티 등에서 이직 타이밍에 대해 임금, 개발문화, 사람 등등 여러가지를 꼽았지만 그중 제일 중요하다고 생각하고 와닿았던것이 내가 더 성장할 수 없을때 였기 때문이다.
난 아직 여기서 줏어먹을게 남아있다고 생각한다.</p>
<h3 id="내가만든-내-세상이야">내가만든 내 세상이야</h3>
<p>위에서 설명하듯 초소규모 개발팀 (3명이라 했지만 사실 신입 백엔드분 내가 4개월차 쯤에 나가셔서 두명임), 잦은 이직으로 인해 팀내에 약속이 정해지기 어려운 환경, 시간 부족등으로 개발문화및 규칙이 거의 없다시피 한 조직이다.
이것은 신입 개발자에게 안좋은 환경이면서도 좋은 환경이 될 수 있다고 생각한다. 백지는 아무것도 없지만 그만큼 마음대로 그려갈수 있기 때문이다.
이곳에 일하는 1년간 API DOC, 디자인 패턴 (중간 중간 찌그러진), 웹 앱 운영자와 디자이너등 타 팀원들을 위한 공유용 노션 페이지 등을 도입해보았다. 중간중간 이건 기능이 별로라서, 이건 일이 더 늘어나서, 이건 더 귀찮고 번거로워서 여러번 교체를 해온 탓에 정석에서, 잘한것에서 거리가 꽤나 있어 보이는 엉성한 형태지만 조금씩이나마 형성되어가는 무언가를 보며 다음엔 좀더 좋게, 쓰기 편하게, 공유할맛 나게 라는 욕심과 의욕이 생겨난다.
그리고 이 경험은 개발문화가 잘 자리잡은 팀에 들어간 신입은 잘 하지 못할 경험이라고 생각한다.</p>
<h3 id="여러가지-경험">여러가지 경험</h3>
<p>우리회사는 IT 회사가 아니라 자체 서비스와 파는 물품을 보유하고 있디. 때문에 개발팀은 회사의 자체 서비스 운영 및 그를 위한 웹앱 및 하이브리드앱 개발이 주된 업무라고 볼수 있다. 만, SI 가 하듯 하이브리드앱의 외주를 받기도 하고 백엔드 분 하는일을 보면 IT 솔루션도 진행하는 듯 했다.
덕분에 단순히 소개를 위한 웹페이지 부터 웹 기반의 하이브리드앱, 동영상 및 사운드 플레이가 가능한 데스크탑 웹앱, 클라이언트가 외국인이며 전략시장이 세계라 다국어가 들어간 하이브리드앱 까지 다양한 서비스 빌딩 경험을 해볼 수 있었다.
또한 클라이언트라 할 수 있는 대표님이 아이디어와 추진력이 뛰어나셔서 앱에 여러가지 기능을 추가하시길 좋아하시니 점점 무겁고 다양해지는 앱과 비례하여 내 경험도 쌓을 수 있었다. 앱에 점점 다양한 기능이 추가되는것은 중구난방이 되는것이 아닌가하는 걱정과, 뭘 자꾸 추가하는거지 하는 짜증과, 묘한 재미가 있는 일이었다.</p>
<h1 id="2024에는">2024에는</h1>
<h3 id="사이드프로젝트">사이드프로젝트</h3>
<p>혼자서 하는 사이드프로젝트 보다 개발문화를 잘 경험하지 못한 날 위해 여러사람과 협업을 하는 사이드프로젝트를 이번년도에도 꾸준히 시도했지만 아무것도 하지 못했다. 시작해볼까 하면 디자인 단계에서 펑, 기획단계에서 도주, 이제는 한이 되고 오기가 되었다. 이번년도에는 반드시 할 것이다. 사이드프로젝트.
혼자서 할 사이드 프로젝트도 구상을 해보아야 할 것 같다.</p>
<h3 id="문서화-문서화-그리고-문서화">문서화 문서화 그리고 문서화</h3>
<p>아직 프론트엔드가 필수로 적어야할, 잘 적어야 할 문서들이 뭔지 모른다. 대강 인터넷에서 눈대중으로 가져와서 작성해보고 필요없다 싶으면 버리고를 반복하고 있다.
진짜로 실무에서 필요한 문서화가 무엇인지, 회사내에서 같이 일하는 사람들이 서로 편하게 해줄 문서화가 무엇인지 제대로 알고 작성하고 싶다.</p>
<h3 id="컨퍼런스-모임-스터디-공부">컨퍼런스, 모임, 스터디, 공부</h3>
<p>어떻게든 이번년도 알차게 했다. 라고 말하고 싶지만 사실 나태했다. 여러 사람들의 개발방법을 듣고 보고싶다. 수도권이 아니라 많이 있을지 모르지만 컨퍼런스, 모임 등에 참석해보고 싶다.
2년간 사용해가며 이제 익숙해졌다고 생각한 자바스크립트도 최근에 기본적인걸 모르고 있었다는걸 알게 되었다. truthy falsy 에 대해 반만 알고 있었던 것..! if문에 잘못 써놓고 아니 이게 왜 안되냐고 혼자 승질을 승질을 내다가 스스로에게 부끄러워졌다. 다시해야지 계속해야지 공부.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Fixed 의 위치를 부모 요소의 영향을 받도록 만들기]]></title>
            <link>https://velog.io/@ecof_/Fixed-%EC%9D%98-%EC%9C%84%EC%B9%98%EB%A5%BC-%EB%B6%80%EB%AA%A8-%EC%9A%94%EC%86%8C%EC%9D%98-%EC%98%81%ED%96%A5%EC%9D%84-%EB%B0%9B%EB%8F%84%EB%A1%9D-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@ecof_/Fixed-%EC%9D%98-%EC%9C%84%EC%B9%98%EB%A5%BC-%EB%B6%80%EB%AA%A8-%EC%9A%94%EC%86%8C%EC%9D%98-%EC%98%81%ED%96%A5%EC%9D%84-%EB%B0%9B%EB%8F%84%EB%A1%9D-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 17 May 2023 14:39:10 GMT</pubDate>
            <description><![CDATA[<p>tag 의 position 을 결정하는 여러 요소중 scroll 을 따라오는 Fixed는 그 위치의 기준이 Viewport 를 기준으로 한다. 때문에 아무리 부모요소로 감싸고 부모요소에 relative 를 준다고 해도 Fixed 의 위치를 한 요소의 가운데로 설정하는 등 마음대로 정할수 없어서 그런 필요가 생길때 마다 직접 px 를 한땀한땀 계산해서 넣어줘야 하나 고민을 할 때도 있었다.</p>
<p><img src="https://velog.velcdn.com/images/ecof_/post/76dba59d-4697-4ea1-aed8-29b9dc8ce71a/image.png" alt=""></p>
<blockquote>
<p>header 와 nav를 제외한 영역의 가운데에 맞추고 싶음</p>
</blockquote>
<p>보통 fixed 또는 absolute 를 가운데에 맞출때는 left 나 right를 50% 로 주고 transform translate 로 반대쪽을 -50% 주는 방식으로 맞췄지만 fixed를 사용할때 위의 경우 위치를 영역의 가운데에 맞추기가 쉽지 않다.</p>
<h3 id="해결법">해결법</h3>
<p>특별한 경우가 아니면 보통 X 좌표가 부모의 영향을 받는 경우를 원한다. 때문에 본 해결법은 X위치를 기준으로 한다.
fixed 를 사용할 요소를 만들고 fixed 를 달고보면 이 요소의 위치가 별로 다른게 없다고 느낄때가 종종 있다. scroll을 움직이면 따라오긴 하지만 이 요소가 갑자기 화면 저 구석에 가서 붙는다거나 뜬금없는 위치로 가거나 하지 않는다. 다른 위치를 조정해주는 무언가의 영향을 받지 않는 이상 fixed를 달기 전 위치에서 고대로 fixed가 된채 scroll을 따라온다.
해결법은 fixed 를 달기 전에 원하는 위치를 잡아주고 fixed를 선언한뒤 Y 위치만 top 및 bottom 으로 조절해주는 것이다.
손쉽게 가운데로 위치하는법은 부모 요소에 flex 를 주고 justify-content : center 및 align-items: center 로 맞추면 쉽게 가운데를 맞출 수 있다.</p>
<p>코드</p>
<pre><code class="language-html">&lt;div className=&quot;App&quot;&gt;
    &lt;div className=&quot;box1&quot; /&gt;
    &lt;div className=&quot;box2&quot;&gt;
        &lt;div className=&quot;position&quot;&gt;
          &lt;div className=&quot;item&quot; /&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>
<pre><code class="language-css">.App {
  font-family: sans-serif;
  text-align: center;
  display: flex;
  height: 3000px;
}

.box1 {
  background-color: lightcoral;
  height: 100%;
  flex: 1;
}

.box2 {
  background-color: skyblue;
  height: 100%;
  flex: 1;
}

.position {
  display: flex;
  justify-content: center;
  align-items: center;
}

.item {
  width: 50px;
  height: 50px;
  background-color: greenyellow;
  position: fixed;
  bottom: 50px;
}</code></pre>
<p>Demo : <a href="https://j9yis4.csb.app/">https://j9yis4.csb.app/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모바일 환경에서 react를 이용해 touch dnd를 만들때 신경써야 하는 것]]></title>
            <link>https://velog.io/@ecof_/%EB%AA%A8%EB%B0%94%EC%9D%BC-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-react%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-touch-dnd%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%95%8C-%EC%8B%A0%EA%B2%BD%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EA%B2%83</link>
            <guid>https://velog.io/@ecof_/%EB%AA%A8%EB%B0%94%EC%9D%BC-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-react%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-touch-dnd%EB%A5%BC-%EB%A7%8C%EB%93%A4%EB%95%8C-%EC%8B%A0%EA%B2%BD%EC%8D%A8%EC%95%BC-%ED%95%98%EB%8A%94-%EA%B2%83</guid>
            <pubDate>Sun, 05 Feb 2023 09:11:16 GMT</pubDate>
            <description><![CDATA[<p>현재 진행하고 있는 프로젝트에서 dnd기능(drag and drop) 으로 리스트의 순서를 바꾸는 인터렉션이 필요했다. 이전 토이프로젝트에서 적은 기능을 가진 레이어를 구현해봤던 경험을 가지고 있어, 그것을 토대로 구현하면 되겠다라고 생각했지만 생각하지 못한 차이점이 존재했다.</p>
<p>이전 토이프로젝트에서 구현했던 dnd 기능은 html의 기본속성인 draggable 과 drag event 를 이용해 만들었었다. dragstart, dragend 를 이용해 drag 중인 item 을 제어하고 dragover 를 이용해서 drag 중 마우스가 가르키는 위치를 측정하여 뒤바꿀 리스트의 순서를 정하고 바꾸는 로직이었다.</p>
<p align="center">
  <img src="https://velog.velcdn.com/images/ecof_/post/b9ca3704-f98c-4d7e-b077-ee3c7d82a054/image.png" align="right">
  <img src="https://velog.velcdn.com/images/ecof_/post/29148412-8c9f-4c12-8382-6cd5b5225e3c/image.png" align="left">
</p>

<hr>
<h5 align="center">draggable 의 특징은 마치 영혼을 잡은 듯 반투명한 복사체를 잡고 움직일수 있다. <br/> dragover로 drag 도중 마우스의 위치에 따라 해당 요소의 위나 아래에 놓을 것 인지 그 요소와 바꿀 것 인지 판단한다.
</h5>

<hr>
<p>문제는 현 프로젝트는 React를 이용해 제작하는 Web 기반 모바일 app이란 것이다.
매우 슬프게도 모바일에서 draggable 은 지원되지 않는다.</p>
<h2 id="dnd-구현-로직">dnd 구현 로직</h2>
<p>mouse event 를 이용해 dom의 위치를 마우스 좌표를 따라 움직이는, 조금 더 바닥부터 코딩을 해야하는 dnd 를 구현해야 했다. 모바일이니 mouse event 가 아닌 touch event를 사용하기로 하고 보통 mouse event 로 dnd 를 만들듯 사용자가 요소를 터치를 했을때 와 터치 상태에서 움직일때, 터치를 그만 두었을때로 나누어 event 를 사용했다.</p>
<blockquote>
<p>Touch Start - grap</p>
</blockquote>
<p>사용자가 터치를 시작하면 그 터치한 요소를 감지하여 실질적으로 움직일 요소를 target 으로 ref 에 저장했다. 구현하던 기능은 반드시 햄버거 버튼을 잡고 움직여야 하는 기능이기 때문에 단순히 event 의 target 으로 설정하기에는 image 태그만 가져오게 돼, 그 부모노드를 탐색해 실질적으로 움직일 target 을 선별해내 그 정보를 ref 에 저장했다.
target 을 정하고 나면 그 요소를 position absolute 와 z-index 로 다른 요소들 위로 겹칠수 있도록 만들고 top 에 마우스의 좌표를 계산한 값을 넣어주었다. (x, y 로 움직이는 기능이 아닌 y 로만 움직이는 기능이었기 때문)
또한 target 의 사이즈와 같고 내용물은 보이지 않는 clone node 를 만들어 기존 요소의 위치에 삽입하여 다른 list 의 요소들이 target 이 list 에서 빠져나온 것 때문에 위치가 변하지 않도록 하면서 요소를 움직일때 현재 target 이 삽입될 위치를 표시해주는 용도로 사용되도록 구현했다.</p>
<blockquote>
<p>Touch Move - drag</p>
</blockquote>
<p>사용자가 target 을 grap 한 상태에서 drag 를 하면 absoulte 된 target 요소의 top 으로 touch 좌표값을 계산한 y 값을 넣어주어 drag 를 위 아래로 움직일때 마다 따라오도록 만들고 그 상태로 다른 list 의 요소들과 겹쳐지게 되면 그 요소의 사이즈와 drag 하는 중인 좌표값을 계산하여 그 요소 안에서 50% 보다 위에 있느냐 아래에 있느냐를 계산해 clone node 와 겹쳐진 요소의 자리를 뒤바꿔 주면서 target 이 들어갈 위치를 표시하도록 구현했다.</p>
<blockquote>
<p>Touch End - drop</p>
</blockquote>
<p>drag 로 target 이 들어갈 위치를 설정하고 touch 를 끝마치게 되면 clone node 의 위치에 target 을 다시 삽입해주고 absolute 나 z-index 등 grap 단계에서 추가된 style 등을 삭제하여 본래의 상태로 돌려주며 clone node를 삭제 한다.
또한 grap 단계에서 설정된 ref 나 state 등도 초기 상태로 리셋해준다면 한번의 dnd 작업이 끝나도록 구현했다.</p>
<h2 id="문제점">문제점</h2>
<p>mouse envet 를 사용한 dnd 는 라이브러리 사용없이 몇번 구현해보았던 기능이었기에 이 설계 대로만 한다면 쉽게 구현이 될 것이라고 생각했으나 touch event 는 mouse event 와 아주 큰 차이점이 하나 있었다.
모바일에서는 손가락으로 잡아 드래그로 화면을 움직여야 하기 때문에 touch move 이벤트에 scroll 기능이 default로 들어가 있다는 점이었다. 나는 사용자가 요소를 drag 하는 동안에 화면이 touch 를 따라 움직이는걸 원하지 않았다.</p>
<p>몇번의 검색후 drag 하는 동안은 event.preventDefault 를 이용해 dgag scroll을 막아주는 기능을 넣었다.
그리고 마주한 오류.</p>
<blockquote>
<p>Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.</p>
</blockquote>
<p>스크롤이 되고 있는 도중에는 event속성중 cancleable 속성이 false가 되어 있고 그 상태에서 prevent 로 default 속성을 정지하는건 불가능하다는 이야기 같았다. 기능또한 멈춰져 있는 상태에서는 drag를 하게 되면 touch scroll 이 작동을 멈추는걸 보여주지만 touch scroll 을 작동시켜 화면이 움직이는 중간에 drag를 하기 시작하면 콘솔에 저 문장과 함께 drag 와 touch scroll 이 동시에 작동되는걸 볼 수 있었다.
해답은 console 에 나온 저 cancleable 을 이용하는 것 이었다.
tag에 onEvent props 로 event 를 주는것이 아닌 useEffect 로 drag event 를 부여하면서 passive 속성을 false 로 줘 default 이벤트를 멈출수 있도록 하고 drag 등의 기능들이 작동할 수 있는 상태를 가르키는 state 를 만들어 cancelable 이 ture 일때만 작동하도록 해주었다.</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
    dontScroll.current = (e) =&gt; {
      if (e.cancelable) {
        e.preventDefault();
        setScrollOff(false);
      } else {
        setScrollOff(true);
      }
    };
    if (dragMode) {
      document.addEventListener(&quot;touchmove&quot;, dontScroll.current, {
        passive: false
      });
    }
    return () =&gt; {
      document.removeEventListener(&quot;touchmove&quot;, dontScroll.current);
    };
  }, [dragMode, scrollOff]);</code></pre>
<hr>
<h5 align="center">scrollOff 와 dragMode state가 변화될때 마다 실행이 되어 내부 변수가 아닌 ref에 담았다.</h5>

<hr>
<p>또한 백엔드와 통신을 하거나 할 경우 cancelable 이 false 로 고정되는 현상이 나와 실질적인 drag 로직이 담긴 함수를 useCallback 으로 담아 event를 선언했다.</p>
<pre><code class="language-javascript">const dragHandler = useCallback(
    (e) =&gt; {
      drag(e);
    },
    [scrollOff, dragMode, List]
  );
  useEffect(() =&gt; {
    document.addEventListener(&quot;touchmove&quot;, dragHandler, { passive: false });
    return () =&gt; {
      document.removeEventListener(&quot;touchmove&quot;, dragHandler);
    };
  }, [dragHandler, scrollOff, dragMode]);</code></pre>
<p>현재 잘 돌아가기는 하지만 내가 맞는 코드를 적절하게 짠건지는 알수가 없어 추후 재검토를 해볼 예정이다.
모든 코드와 Demo는 이곳에서 볼 수 있다.</p>
<center><a href="https://b41ezy.csb.app/">Demo</a></center>
<center>(개발자 도구에서 모바일 환경으로 테스트 해야 함)</center>]]></description>
        </item>
        <item>
            <title><![CDATA[AWS lambda를 이용한 Proxy 서버 만들고 nodemodule을 추가하고 euc-kr 인코딩 xml 받아오기]]></title>
            <link>https://velog.io/@ecof_/AWS-lambda%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Proxy-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B3%A0-nodemodule%EC%9D%84-%EC%B6%94%EA%B0%80%ED%95%98%EA%B3%A0-euc-kr-%EC%9D%B8%EC%BD%94%EB%94%A9-xml-%EB%B0%9B%EC%95%84%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@ecof_/AWS-lambda%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Proxy-%EC%84%9C%EB%B2%84-%EB%A7%8C%EB%93%A4%EA%B3%A0-nodemodule%EC%9D%84-%EC%B6%94%EA%B0%80%ED%95%98%EA%B3%A0-euc-kr-%EC%9D%B8%EC%BD%94%EB%94%A9-xml-%EB%B0%9B%EC%95%84%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Fri, 04 Nov 2022 11:06:58 GMT</pubDate>
            <description><![CDATA[<p>Vue를 이용해 쇼핑몰의 껍데기 만들기 프로젝트를 진행중에 API를 받아오는 과정에서 CORS 오류를 만나 Vue 의 devserver 에서 제공하는 proxy를 이용해서 우회를 했었다.
당연히 임시방편으로 해놓은 것 이기 때문에 build를 한 후에는 사용 할 수 없는 방법이었다.
github page 를 이용해서 build 를 했기 때문에 github에 proxy를 적용 하는 방법이나 proxy가 적용 된 채로 github에 올리는 (기막힌 발상) 방법등을 강구했으나 찾을 수 없었다. 그 중 건진건 github page가 얼마전부터 업데이트가 되어 access-control-allow-headers 가 * 이 되었고 cors를 신경 쓸 필요 없다는 소식 이었지만 난 여전히 안된다는 사실이었다.
번역기를 돌려 github 형님들께 요청을 해보았지만 api를 주는 곳의 문제이고 내가 할 수 있는건 서버를 만드는거 말고는 없다는 답변을 들었고 proxy를 만들기로 결심하게 되었다.</p>
<p>-올렸던 질문 글
<a href="https://github.com/orgs/community/discussions/37317">https://github.com/orgs/community/discussions/37317</a></p>
<p><img src="https://velog.velcdn.com/images/ecof_/post/63db5f53-5329-40e5-a925-cefeea4e63d2/image.png" alt="">
aws 콘솔에 가입하고 lambda 에서 함수를 생성해준다.
aws 는 가입하고 하루 정도 뒤에 이용가능하다 해서 덕분에 하루 놀았다.
<img src="https://velog.velcdn.com/images/ecof_/post/05d86936-4eef-4e79-b31c-70da6df8a144/image.png" alt="">
건드리는거 없이 함수이름을 정해준뒤 함수생성을 누른다. 여러가지 언어로 가능하지만 node.js 를 선택했다.
<img src="https://velog.velcdn.com/images/ecof_/post/82969e06-9563-447e-89fc-28624e17d598/image.png" alt="">
함수가 만들어지면 개요에서 트리거 추가를 누르고 API Gateway를 선택해준다.
<img src="https://velog.velcdn.com/images/ecof_/post/fbe9e753-7422-423f-9961-52abc7ea66ad/image.png" alt="">
create a new API를 선택하고 REST API, 보안은 Open 을 선택해준다.</p>
<p>이렇게 되면 API Gateway 가 생성되고 함수 개요에 생긴 API Gateway 를 눌러 보면 API endpoint를 확인 할 수 있는데
<img src="https://velog.velcdn.com/images/ecof_/post/ed5fb933-ae28-4a56-a116-6e2fe0d5d73a/image.png" alt="">
저 endpoint 를 이용해서 정보를 받아올수 있으며 뒤에 쿼리 방식을 이용하여 데이터를 전해줄 수 있다.
이제 lambda 에 내가 원하는 open API 에서 데이터를 받아오는 코드를 작성한다.</p>
<pre><code class="language-javascript">const https = require(&quot;https&quot;);

exports.handler = async (event) =&gt; {
    let key = &#39;비밀이얌&#39;;
    let apiCode = encodeURI(event.queryStringParameters.apiCode);
    let searchTarget = apiCode === &#39;ProductSearch&#39; ? &#39;keyword=&#39;+encodeURI(event.queryStringParameters.keyword) : &#39;productCode=&#39;+encodeURI(event.queryStringParameters.productCode)
    let etc = apiCode === &#39;ProductSearch&#39; ? &#39;targetSearchPrd=KOR&amp;pageSize=12&amp;sortCd=A&#39; : &#39;option=QAs,PostScripts,PdOption&#39;;

    const option = {
        protocol: &quot;https:&quot;,
        hostname: &quot;openapi.11st.co.kr&quot;,
        path: `/openapi/OpenApiService.tmall?key=${key}&amp;apiCode=${apiCode}&amp;${searchTarget}&amp;${etc}`,
        encoding: null,
    }

    const resultObj = await new Promise((res, reject) =&gt; {
        https.get(option, (response)=&gt;{
            var result = &quot;&quot;;

            response.on(&#39;data&#39;, function (chunk) {
                result += chunk
            })

            response.on(&#39;end&#39;, function () {
                const body = {
                    headers: {
                        &quot;Access-Control-Allow-Headers&quot; : &quot;Content-Type&quot;,
                        &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,
                        &quot;Access-Control-Allow-Methods&quot;: &quot;OPTIONS,POST,GET&quot;,
                        &quot;Content-Type&quot; : &quot;text/xml;charset=utf8&quot;
                    },
                    statusCode: 200,
                    body: result,
                }
                res(body)
            })
        })
    })
    return resultObj;
};</code></pre>
<p>https를 받아온뒤 그것을 이용하여 API에게 요청한다.
encodeURI(event.queryStringParameters.apiCode) 를 이용해서 endpoint 뒤에 붙는 &#39;?쿼리이름=쿼리내용&amp;두번째꺼=두번째&#39; 형태의 쿼리를 받아 올 수 있다.
아마 다른 형태로도 요청을 할 수 있겠지만 참고할 만한 곳이 얼마 없었어서 그 중 되는걸 했기 때문에 코드의 작성 이유등을 정확히 정의하지 못했다.
설상가상으로 요즘 티스토리 블로그들이 터져서 글들을 참고하지 못해 더욱 정보가 한정되었다.
option 에 담긴 정보를 이용해 https.get 을 이용해 정보를 요청하고 end 부분에서 Access-Control-Allow-Origin 이나 인코딩 및 형태를 전해주어 xml을 받아 올 수 있게 했다.
여기서 생긴 문제는 내가 받아오는 11번가의 api 정보는 euc-kr 형태의 인코딩을 제공하는데 node가 그런건지 lambda 가 그런건지 euc-kr 인코딩이 안된다는 것이다.
버퍼에 넣은 뒤에 인코딩을 하든 받아온걸 utf-8로 바꾸는 binary로 바꾸든 무엇을 해도 한글은 깨졌다.
역발상으로 인코딩 자체를 안하고 proxy에서 vue로 전해준뒤 vue 에서 인코딩을 하려고 했지만 받아올때 아무리 encoding 이 null 이라도 lambda 에서 출력할때 utf-8로 바뀌는건지 (뇌피셜) 그것 또한 불가능 했다.</p>
<p>이틀간 삽질끝에 lambda 에 nodemodule을 넣어 iconv-lite를 lambda 에서 사용하는 형태를 사용했다.
lambda 에서 nodemodule 을 사용하기 위해서는 layer 를 사용해야 한다.</p>
<p><img src="https://velog.velcdn.com/images/ecof_/post/d8457b67-e179-4cb1-aa00-cda8831bad87/image.png" alt="">
추가 리소스에 계층을 눌러 layer 로 들어간다.
<img src="https://velog.velcdn.com/images/ecof_/post/cecd79b7-7cbd-4c26-b2f8-12a1edaec45f/image.png" alt="">
계층 생성을 누르고
<img src="https://velog.velcdn.com/images/ecof_/post/e79336d9-3162-45d4-aa64-17814123a6ff/image.png" alt="">
이름 을 정한뒤 호환런타임에서 node.js 를 선택하고 nodemodule 을 압축하여 업로드해주면 되는데 중요한 점은 nodemoule 을 그대로 압축해서 넣으면 안된다는 점이다.
<img src="https://velog.velcdn.com/images/ecof_/post/91c5a245-739b-4d6d-85bb-502006857e37/image.png" alt="">
aws 에서 제공하는 가이드 대로 nodejs 폴더 안에 nodemodule 이 있는 형태로 압축을 해서 넣어주어야만 한다.
<img src="https://velog.velcdn.com/images/ecof_/post/850c00a8-6780-4ccc-bc20-0947e8577fd6/image.png" alt="">
그 뒤 코드를 작성 할 수 있는 페이지에서 가장 아래로 내리면 계층 부분이 있다. Add a layer 를 눌러 준다.
<img src="https://velog.velcdn.com/images/ecof_/post/63b0ae3f-e144-4b26-8f54-1f8645f34125/image.png" alt="">
사용자 지정 계층을 선택하고 내가 추가했던 계층을 골라준다. 수정사항이 있을시 같은 이름의 계층으로 업로드 하면 버전이 쌓이게 된다. 사용하고픈 버전으로 골라 주면 된다.
이렇게 nodemodule 안에 iconv-lite 를 넣고 layer에 추가 했다면 코드 내에서 사용해주면 된다.</p>
<pre><code class="language-javascript">const https = require(&quot;https&quot;);
const iconv = require(&#39;iconv-lite&#39;)

exports.handler = async (event) =&gt; {
    let key = &#39;비밀이얌&#39;;
    let apiCode = encodeURI(event.queryStringParameters.apiCode);
    let searchTarget = apiCode === &#39;ProductSearch&#39; ? &#39;keyword=&#39;+encodeURI(event.queryStringParameters.keyword) : &#39;productCode=&#39;+encodeURI(event.queryStringParameters.productCode)
    let etc = apiCode === &#39;ProductSearch&#39; ? &#39;targetSearchPrd=KOR&amp;pageSize=12&amp;sortCd=A&#39; : &#39;option=QAs,PostScripts,PdOption&#39;;

    const option = {
        protocol: &quot;https:&quot;,
        hostname: &quot;openapi.11st.co.kr&quot;,
        path: `/openapi/OpenApiService.tmall?key=${key}&amp;apiCode=${apiCode}&amp;${searchTarget}&amp;${etc}`,
        encoding: null,
    }

    const resultObj = await new Promise((res, reject) =&gt; {
        https.get(option, (response)=&gt;{
            var result = &quot;&quot;;

            response.on(&#39;data&#39;, function (chunk) {
                result += iconv.decode(chunk, &#39;euc-kr&#39;)
            })

            response.on(&#39;end&#39;, function () {
                const body = {
                    headers: {
                        &quot;Access-Control-Allow-Headers&quot; : &quot;Content-Type&quot;,
                        &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,
                        &quot;Access-Control-Allow-Methods&quot;: &quot;OPTIONS,POST,GET&quot;,
                        &quot;Content-Type&quot; : &quot;text/xml;charset=utf8&quot;
                    },
                    statusCode: 200,
                    body: result,
                }
                res(body)
            })
        })
    })
    return resultObj;
};</code></pre>
<p>response 에서 data를 result 에 추가하는 부분에서 iconv를 이용해 euc-kr로 디코드하는 부분을 추가했다.
이렇게 build 된 프로젝트에서도 proxy를 이용해 api를 받아올 수 있게 되었다.</p>
<p>++참고한 글
<a href="https://nookpi.tistory.com/99">https://nookpi.tistory.com/99</a>
(근데 티스토리 터져서 언제 보일지는 모름)</p>
<p>추가로 내 lambda 함수를 아무나 사용하지 못하도록 api 키를 추가하거나 Access-Control-Allow-Origin 설정을 따로 해 줄 수 있는데 현재 티스토리가 터져 보이지도 않고 지금은 잘 돌아가는 상황이라 나중에 추가할 예정이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 에서 Class 형태 Canvas 사용하기]]></title>
            <link>https://velog.io/@ecof_/React-%EC%97%90%EC%84%9C-Class-%ED%98%95%ED%83%9C-Canvas-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ecof_/React-%EC%97%90%EC%84%9C-Class-%ED%98%95%ED%83%9C-Canvas-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 19 Jul 2022 01:20:07 GMT</pubDate>
            <description><![CDATA[<p>국비지원 학원에서 팀프로젝트를 진행하면서 커스텀 쇼핑몰을 주제로 삼게 되었는데, 커스텀 기능을 구현하면서 canvas를 사용하게 되었다. 이전에 Interactive Developer (<a href="https://www.youtube.com/c/cmiscm">https://www.youtube.com/c/cmiscm</a>) 님의 강의를 보면서 조금 따라해본게 전부인 canvas를 바닐라 JS도 아닌 React에 적용하려니 심히 삐걱거렸다.</p>
<p>게다가 강의에서 사용하는건 class를 이용해 canvas를 구성하고 조작하는 방법으로 react + canvas 를 검색했을때 나오는 여러 참고자료들과 달라 곤혹은 더해졌지만, 어떻게든 적용에 성공했다. (사실 맞는 방법인지 모름)
<br></p>
<blockquote>
<p>검색하면 나오는 React + Canvas 형태</p>
</blockquote>
<pre><code class="language-javascript">import {createRef, useEffect} from &quot;react&quot;;
&gt;
const CanvasComp = () =&gt; {
      const canvasRef = createRef(null);
  &gt;
    const 이벤트함수 = () =&gt; {
       ...
    };
      &gt;
    useEffect(()=&gt;{
        canvas = canvasRef.current;
        ctx = canvas.getContext(&quot;2d&quot;);
          canvas.addEventListener(&#39;원하는 이벤트&#39;, 이벤트함수, false);
        return(()=&gt;{
            canvas.removeEventListener(&#39;위에 썼던 이벤트&#39;, 이벤트함수);
        })
    }, [])
     &gt;
    return (
        &lt;canvas ref={canvasRef} /&gt;
    )
}
&gt;
export default CanvasComp;</code></pre>
<p>canvas 태그에 ref 를 걸어 참고할 수 있도록 만들고 useEffect 에서 canvas의 ctx나 event를 사용해 canvas를 초기화 하여 사용하는 형태이다. 또한 useEffect 에 return으로 페이지가 언마운트 될때 이벤트가 제거 되도록 만들어 리렌더링 될때 중첩되지 않도록 하는 형태다. useEffect 에서 빈 배열을 전해주어 최초 렌더링시에 실행 되도록 만들었으며 canvas 내부에서 props 나 변화하는 state를 사용하려면 배열 안에 해당 이름을 넣어주면 된다. 아마도. 이 형태는 사용해보지 않아 정확하진 않음.
<br></p>
<blockquote>
<p>사용한 React + Class형 Canvas 형태</p>
</blockquote>
<pre><code class="language-javascript">import {createRef, useEffect} from &quot;react&quot;;
&gt;
const CanvasComp = () =&gt; {
      const canvasRef = createRef(null);
  &gt;
    class App {
        constructor() {
            this.canvas = canvasRef.current;
              this.ctx = this.canvas.getContext(&quot;2d&quot;);
&gt;
              this.이벤트헨들러 = this.이벤트함수.bind(this);
              this.canvas.addEventListener(&quot;원하는 이벤트&quot;, this.이벤트헨들러, false);
&gt;
              this.animateHandler = window.requestAnimationFrame(this.animate.bind(this));
        }
        &gt;
          this.animate () {
              this.ctx.clearRect(0, 0, 캔바스넓이, 캔바스높이);
              // 캔바스 애니메이션 작동할 것들
              this.animateHandler2 = window.requestAnimationFrame(this.animate.bind(this));
        }
  &gt;
        this.remove () {
            cancelAnimationFrame(this.animateHandler);
              cancelAnimationFrame(this.animateHandler2);
              this.canvas.removeEventListener(&quot;원하는 이벤트&quot;, this.이벤트헨들러);
          }
    }
      &gt;
    useEffect(()=&gt;{
        const Canvas = new App()
        return () =&gt; {
              Canvas.remove();
        };
    }, [])
     &gt;
    return (
        &lt;canvas ref={canvasRef} /&gt;
    )
}
&gt;
export default CanvasComp;</code></pre>
<p>canvas에 ref를 걸어 참고하는건 동일하지만 ctx나 event를 제어하는 부분은 class의 constructor 내부에서 작성한다. 기존 Interactive Developer님의 강의에서는 class내부함수를 addEventListener에 직접 전해주는 형태였지만 remove를 위해 따로 this로 할당해주고 this 로 작성된 부분을 동일하게 사용하기 위해 bind를 걸어줬다.
requestAnimationFrame 으로 인해 계속 실행이 되는 animate 함수에서는 clearRect 로 캔버스를 지워주면서 그 밑에 작성될 캔버스 내용들을 작동시켜 애니메이션 처럼 보여준다.
이벤트의 중첩방지는 class 내에 remove 함수로 작성하고 useEffect 에서 사용하기 위해 class 선언과 함께 변수에 할당하고 return 내에서 할당된 변수로 class에서 접근하여 remove 함수를 실행해 이벤트를 제거하는 형태다.
위와 마찬가지로 최초 렌더링시에 실행되도록 빈 배열을 전해주었고 변화하는 props나 state를 class 내부에서 사용하고 싶을 경우 배열내에 props 나 state를 전해주어 변화시에 재 렌더링 되도록 해주면 된다. 그렇게 할 경우 한가지 문제점은 canvas 내부에서 작동하는 요소가, 생성되는 갯수든 크기든 위치좌표든 초기 상태로 리셋되는것인데 그건 canvas 내부 요소들의 상태를 저장하는 state를 작성해 요소의 변화가 끝나면 setState로 저장하는 형식을 사용하면 방지할 수 있다.</p>
<br>

<p>프로젝트를 진행하며 기존 방식과 class 방식을 두고 여러번 고민하고 또 사용해보고 여러번을 뒤엎으며 사실상 기존 방식은 찍어먹어본 수준에 지나지 않아 제대로된 비교가 진행되었다고 할 수는 없지만 배운게 도둑질이라고 canvas를 사용해본 일이 class 형태밖에 없어 함수로 처리하는 기존방식 보다 class 형태를 적용한 형태가 나에겐 훨씬 쓰기 편했다.
이벤트나 requestAnimationFrame을 useEffect 내에서 처리하는것이 cavas의 작동 순서를 파악하는데 어려웠고 직관적으로 보이지가 않았기 때문에 canvas 에서 처리해야 하는 요소가 많아질 경우 어떤식으로 대응을 해야 하는지 감이 오지 않았기 때문이라고 생각한다. 그 때문인지 기존 방식에 requestAnimationFrame를 적용하지 못했다.
또한 canvas 에서 제어해야 하는 요소가 많아지게 된다면 각 요소별로 class 로 분리하여 관리할 수 있고 각 class는 따로 js 파일로 분리하여 관리할 수 있으니 관리가 더욱 용이한 장점도 들 수 있는 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[vue, Proxy를 이용한 Router페이지 API CORS 우회]]></title>
            <link>https://velog.io/@ecof_/vue-Proxy%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Router%ED%8E%98%EC%9D%B4%EC%A7%80-API-CORS-%EC%9A%B0%ED%9A%8C</link>
            <guid>https://velog.io/@ecof_/vue-Proxy%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Router%ED%8E%98%EC%9D%B4%EC%A7%80-API-CORS-%EC%9A%B0%ED%9A%8C</guid>
            <pubDate>Mon, 16 May 2022 14:21:03 GMT</pubDate>
            <description><![CDATA[<p>메인페이지에서 cors를 우회하여 open api 에서 데이터를 받아오고 신이났지만 router를 이용해 넘어간 다음 페이지에서 404 에러가 날 맞이해주고 있었다.
본능적으로 vue.config.js 에 입력한 proxy가 잘못된 것 같은걸 느꼈지만 console을 찍어볼수도 없는 상황이라 매우 답답했다.
한가지 다른점은 console log 에 찍히는 Request URL 에 router 주소가 추가 되었다는 점 뿐,</p>
<hr>
<p>메인페이지 api 요청 Request URL
<img src="https://velog.velcdn.com/images/ecof_/post/a7fc3c9c-4838-4932-be9e-3d88e3cb35af/image.png" alt="">
라우터페이지(/product:상품id)
<img src="https://velog.velcdn.com/images/ecof_/post/ecbdf3d3-e6a9-48c8-922e-5765e451128a/image.png" alt=""></p>
<hr>
<p>뒤에 붙는 상품id는 어디갔는지 모르겠지만 router 주소가 추가되었다. 몇가지 검색을 해본결과 vue.config.js 파일의 devServer 에 넣어주었던 proxy를 추가하라길래 열심히 새로운 target 으로 &#39;/product&#39;, &#39;^/product&#39;, &#39;^/product/*&#39; 등을 넣어보았지만 전혀 작동하지 않았고, pathRewrite를 넣어보고, 메인페이지를 입력했던 부분에 같이 넣어보기도 하고 여러가지를 해보았지만 전부 실패, 홧김에 api 요청 url 에 메인페이지의 Request URL 앞부분을 집어 넣으니 허무하게 해결되었다.</p>
<hr>
<p>이전 api 요청 url
proxy에 입력한 api 요청 url의 앞부분을 제외</p>
<pre><code class="language-javascript">curl = `/openapi/OpenApiService.key=${apikey}&amp;apiCode=${apicode}&amp;productCode=${productCode}`</code></pre>
<p>해결한 api 요청 url
proxy에 입력한 api 요청 url의 앞부분을 본 api 주소가 아닌 localhost로 입력</p>
<pre><code class="language-javascript">curl = `http://localhost:8080/openapi/OpenApiService.key=${apikey}&amp;apiCode=${apicode}&amp;productCode=${productCode}`</code></pre>
<hr>
<p>지금은 devserver 라서 가능한 방법이지만 bulid 하게 될때는 또 다른 방법을 찾아야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[vue, Proxy를 이용한 CORS 우회]]></title>
            <link>https://velog.io/@ecof_/vue-Proxy%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-CORS-%EC%9A%B0%ED%9A%8C</link>
            <guid>https://velog.io/@ecof_/vue-Proxy%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-CORS-%EC%9A%B0%ED%9A%8C</guid>
            <pubDate>Sun, 15 May 2022 13:47:19 GMT</pubDate>
            <description><![CDATA[<p>사이드 프로젝트로 쇼핑몰의 껍데기만 만들어 보던중 상품이 없기에는 허전하고 하나하나 만들기는 거의 불가능 하니 쇼핑몰 API를 이용하여 상품정보를 받아오기로 했다.
이전 프로젝트를 할때 주소 조회를 해줄 Open API를 사용하려다가 CORS문제를 해결하지 못하고 결국 다른 방법으로 해결했던 기억이 있었기 때문에 지레 겁을 먹었지만 바닐라JS를 사용했던 그때와 달리 vue를 사용하고 있었기에 손쉽게 우회가 가능했다.</p>
<h2 id="최상단-디렉토리에-vueconfigjs를-생성">최상단 디렉토리에 vue.config.js를 생성</h2>
<p><img src="https://velog.velcdn.com/images/ecof_/post/824855f9-9bc5-419e-96c5-209b03b8211f/image.png" alt=""></p>
<h2 id="proxy-작성">Proxy 작성</h2>
<pre><code class="language-javascript">const { defineConfig } = require(&quot;@vue/cli-service&quot;);
module.exports = defineConfig({
  devServer: {
    proxy: {
      &quot;/&quot;: {
        &#39;target&#39;: &quot;open api 주소중 일부&quot;,
        &#39;pathRewrite&#39;: { &quot;^/&quot;: &quot;&quot; },
        &#39;ws&#39;: false,
      },
    },
  },
});</code></pre>
<p>devserver 내에 proxy를 작성, target에 들어가는 부분이 api를 요청할 url의 일부가 들어간다. 그 후 ajax든 XMLHttpRequest든 요청을 보낼 url에는 target에 들어간 부분을 제외하고 입력하면 된다.
ws 는 WebSocket관련한 것 같은데 사용하지 않고, 지속적으로 오류가 떠 false 로 넣어주었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[vue, 가변 배열에 v-for을 사용하여 key 값을 index로 사용시 문제점]]></title>
            <link>https://velog.io/@ecof_/vue-%EA%B0%80%EB%B3%80-%EB%B0%B0%EC%97%B4%EC%97%90-v-for%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-key-%EA%B0%92%EC%9D%84-index%EB%A1%9C-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EB%AC%B8%EC%A0%9C%EC%A0%90</link>
            <guid>https://velog.io/@ecof_/vue-%EA%B0%80%EB%B3%80-%EB%B0%B0%EC%97%B4%EC%97%90-v-for%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-key-%EA%B0%92%EC%9D%84-index%EB%A1%9C-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EB%AC%B8%EC%A0%9C%EC%A0%90</guid>
            <pubDate>Mon, 04 Apr 2022 15:32:11 GMT</pubDate>
            <description><![CDATA[<p>토이프로젝트 도중 v-for을 사용하여 만든 리스트의 삭제 함수를 만들었더니 버그가 발생했다.
포지션이 absolute에 임의의 위치를 가진 listitem1 과 마찬가지인 listitem2 가 존재할때 1녀석을 삭제했더니 2가 1의 위치에 가버리는 버그였다.</p>
<p>두시간정도 검색을 해보고 각종 함수들을 뜯어보다가 문제점을 찾지 못하던 도중 개발자 도구로 유심히 element가 변하는 모습을 지켜보니 listitem1을 삭제할때 listitem1에 해당하는 element가 삭제되고 그 위로 listitem2가 올라가는게 아닌, listitem2가 삭제가 되고 listitem1의 id 나 내용이 다른 함수에서 넣어준 임의의 위치값을 제외하고 listitem2의 정보로 바뀌고 있었다.</p>
<p><img src="https://i.pinimg.com/474x/27/9f/a6/279fa607335418994c2d96fae95b655f.jpg" alt=""></p>
<center>????????</center>

<p>이게 뭘까 하던 도중 설마하고 바꿔본 key 값이 정답이었다. 어디선가, 선생님인가 유튜브인가 key값을 꼭 사용해줘야 하고 또 단순한 index가 아닌 유니크한 값을 사용하라고 들었었는데 이유는 듣지 못했었건만, 그 문제점을 직접 겪을줄은 몰랐다.
<br></p>
<pre><code class="language-html">  &lt;div id=&quot;app&quot;&gt;
    &lt;!-- index를 key로 사용한 v-for --&gt;
    &lt;h1 style=&quot;position: absolute;&quot;&gt;index key&lt;/h1&gt;
    &lt;div
    v-for=&quot;(n, i) in list1&quot; :key=&quot;i&quot;
    :style=&quot;{backgroundColor : n.color}&quot; style=&quot;position: absolute; width: 200px; height: 190px;&quot;
    class=&quot;div1&quot;&gt;
      {{n.name}} &lt;button @click=&quot;remove(n.id)&quot;&gt;삭제&lt;/button&gt;
    &lt;/div&gt;

    &lt;!-- 문자열 + id값을 key로 사용한 v-for --&gt;
    &lt;h1 style=&quot;position: absolute; left: 220px;&quot;&gt;no index key&lt;/h1&gt;
    &lt;div
    v-for=&quot;(n, i) in list2&quot; :key=&quot;n.id&quot;
    :style=&quot;{backgroundColor : n.color}&quot; style=&quot;position: absolute; width: 200px; height: 190px; left:220px;&quot;
    class=&quot;div2&quot;&gt;
      {{n.name}} &lt;button @click=&quot;remove2(n.id)&quot;&gt;삭제&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;</code></pre>
<p>v-for을 이용하여 만든 두개의 리스트</p>
<p><img src="https://media.vlpt.us/images/ecof_/post/176ecca0-e286-4cd7-82eb-c139a5cb3d17/image.png" alt="">
만들어진 화면</p>
<pre><code class="language-javascript">    new Vue({
      el : &quot;#app&quot;,
      data: {
        list1 : [
          {name : &quot;첫번째 박스&quot;, id : 0, color: &quot;red&quot;},
          {name : &quot;두번째 박스&quot;, id : 1, color: &quot;blue&quot;},
          {name : &quot;세번째 박스&quot;, id : 2, color: &quot;green&quot;},
          {name : &quot;네번째 박스&quot;, id : 3, color: &quot;orange&quot;}
        ],
        list2 : [
          {name : &quot;첫번째 박스&quot;, id : 0, color: &quot;red&quot;},
          {name : &quot;두번째 박스&quot;, id : 1, color: &quot;blue&quot;},
          {name : &quot;세번째 박스&quot;, id : 2, color: &quot;green&quot;},
          {name : &quot;네번째 박스&quot;, id : 3, color: &quot;orange&quot;}
        ],
      },
      methods: {
        // 삭제 메소드
        remove(id) {
          this.list1.forEach((element , i)=&gt; {
            if (element.id == id) {
              this.list1.splice(i, 1)
            }
          });
        },
        remove2(id) {
          this.list2.forEach((element , i)=&gt; {
            if (element.id == id) {
              this.list2.splice(i, 1)
            }
          });
        }
      },
    })

    // 외부에서 정해주는 위치값
    let div = document.getElementsByClassName(&#39;div1&#39;)
    for (let i = 0; i &lt; div.length; i++) {
      div[i].style.top = 100 + (190 * (i)) + &#39;px&#39;
    }

    let div2 = document.getElementsByClassName(&#39;div2&#39;)
    for (let i = 0; i &lt; div2.length; i++) {
      div2[i].style.top = 100 + (190 * (i)) + &#39;px&#39;
    }</code></pre>
<p>vue 코드와 위치값을 정해주는 자바스크립트</p>
<p><img src="https://media.vlpt.us/images/ecof_/post/febe761a-ff18-4881-a902-399762b3204b/image.png" alt=""></p>
<p>여기서 각각 두번째 박스를 삭제하게 되면 이런 모양새가 된다.</p>
]]></description>
        </item>
    </channel>
</rss>