<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>맨땅에 헤딩_디지털 마케터</title>
    <link>https://jihyungk.tistory.com/</link>
    <description>DSP플랫폼 DA운영자 -&amp;gt; 컴퓨터 개발 공부 -&amp;gt; 오퍼월 광고 기획/ 운영 中</description>
    <language>ko</language>
    <pubDate>Wed, 22 Jul 2026 22:43:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>geograp</managingEditor>
    <image>
      <title>맨땅에 헤딩_디지털 마케터</title>
      <url>https://tistory1.daumcdn.net/tistory/6147320/attach/b96033c60f3a4554acf766f2767951bc</url>
      <link>https://jihyungk.tistory.com</link>
    </image>
    <item>
      <title>[코딩온] 웹 풀스택 영등포 5기 과정_docker(2)</title>
      <link>https://jihyungk.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0. Docker Desktop&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 플랫폼의 데스크톱 버전&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 GUI를 이용해 컨테이너를 쉽게 생성, 실행, 관리할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이미지 빌드하거나 Docker Hub에서 이미지 다운할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컨테이너 시작, 중지, 재시작, 삭제 뿐만 아니라 상태 모니터링 및 로그 확인 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컨테이너 간의 네트워크를 연결할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컨테이너의 보안을 강화할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Docker Desktop 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서 방문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/get-docker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.docker.com/get-docker/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1704374551939&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Get Docker&quot; data-og-description=&quot;Download and install Docker on the platform of your choice, including Mac, Linux, or Windows.&quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/get-docker/&quot; data-og-url=&quot;https://docs.docker.com/get-docker/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PIigC/hyU2pWAOP8/g1zoZ55UXjbxkuQRk3Vhd1/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128&quot;&gt;&lt;a href=&quot;https://docs.docker.com/get-docker/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/get-docker/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PIigC/hyU2pWAOP8/g1zoZ55UXjbxkuQRk3Vhd1/img.png?width=129&amp;amp;height=128&amp;amp;face=0_0_129_128');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Get Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Download and install Docker on the platform of your choice, including Mac, Linux, or Windows.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;651&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pIos9/btsC7oVQ9TM/h5aKZCGM1HYIRx92a75GRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pIos9/btsC7oVQ9TM/h5aKZCGM1HYIRx92a75GRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pIos9/btsC7oVQ9TM/h5aKZCGM1HYIRx92a75GRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpIos9%2FbtsC7oVQ9TM%2Fh5aKZCGM1HYIRx92a75GRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;651&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;651&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 저는 윈도우이고, installer는 별 다른 설정없이 그냥 next 몇번 넘겨서 설치해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;767&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYzcuu/btsC6VM2YLl/zoSx5swneL4szwO0rLLKdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYzcuu/btsC6VM2YLl/zoSx5swneL4szwO0rLLKdK/img.png&quot; data-alt=&quot;예,,,몇분째 username이 승인나지 않는 모습입니다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYzcuu/btsC6VM2YLl/zoSx5swneL4szwO0rLLKdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYzcuu%2FbtsC6VM2YLl%2FzoSx5swneL4szwO0rLLKdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;577&quot; height=&quot;767&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;767&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예,,,몇분째 username이 승인나지 않는 모습입니다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWiakd/btsC6yYG2lp/fEtsdUkLH2lxsYeM9Nybok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWiakd/btsC6yYG2lp/fEtsdUkLH2lxsYeM9Nybok/img.png&quot; data-alt=&quot;결국 걍 다른 이메일로 만듬&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWiakd/btsC6yYG2lp/fEtsdUkLH2lxsYeM9Nybok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWiakd%2FbtsC6yYG2lp%2FfEtsdUkLH2lxsYeM9Nybok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;517&quot; height=&quot;708&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결국 걍 다른 이메일로 만듬&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/90</guid>
      <comments>https://jihyungk.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 4 Jan 2024 16:18:15 +0900</pubDate>
    </item>
    <item>
      <title>[코딩온] 웹 풀스택 영등포 5기 과정_docker(1)</title>
      <link>https://jihyungk.tistory.com/89</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 온라인 수업을 듣고 정리하기 위해 왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 완전 핫한 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;0.Docker란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;컨테이너&lt;/b&gt;&lt;/span&gt;를 기반으로 하는 오픈 소스 가상화 플랫폼&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWeelu/btsC4f5W0We/7STkkilSbT3qrTWFBYfxJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWeelu/btsC4f5W0We/7STkkilSbT3qrTWFBYfxJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWeelu/btsC4f5W0We/7STkkilSbT3qrTWFBYfxJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWeelu%2FbtsC4f5W0We%2F7STkkilSbT3qrTWFBYfxJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;238&quot; height=&quot;212&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Container란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션의 코드, 라이브러리, 환경 설정을 포함하는 어떤 상자(?)로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 안전하고 효율적으로 실행하게끔하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 곳에서 다른 곳으로 쉽게 배포가 가능해서 이식성이 높은 것이 특징입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션을 실행하기 위한 가상의 환경으로, 커널쪽을 사용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가볍고 효율적으로 실행할 수 있어서 요즘 완전 핫한 기술입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;- Container 핵심 기술&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1) 호스트 OS의 자원을 분리해서 각 애플리케이션을 &lt;b&gt;독립성을 높여&lt;/b&gt; 안전하게 실행 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2) Container는 쉽게 &lt;b&gt;이동하고 공유하고 재사용&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;3) Container는 호스트 OS 커널을 공유해서 &lt;b&gt;가볍다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;- 가상머신 vs 도커&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 일전에 virtual mechine으로 CLI만 활용하여 Cent Os를 구축하는 과제를 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상머신으로 그냥 뭣도 모르고 하긴 했었는데,,, 확실히 비효율적이라는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상화 소프트웨어 OS 위에 별도의 가상 OS를 또 실행하는 형식이라서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제를 다시 설치해야합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVBjOx/btsCTyfsJYF/vqkSoHpjZ4GDAknKJhX6m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVBjOx/btsCTyfsJYF/vqkSoHpjZ4GDAknKJhX6m1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVBjOx/btsCTyfsJYF/vqkSoHpjZ4GDAknKJhX6m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVBjOx%2FbtsCTyfsJYF%2FvqkSoHpjZ4GDAknKJhX6m1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;648&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 &lt;b&gt;운영체제의 커널을 공유&lt;/b&gt;해서 애플리케이션을 실행하는 가상 환경입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 덕분에 &lt;b&gt;가볍고 효율적이며 빠른 실행 속도&lt;/b&gt;를 가집니다.(운영체제가 없으니까)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신에 운영체제의 커널을 공유해서 가상머신과 같은 완전한 독립성을 제공할 수 없고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커널의 업데이트나 문제가 생긴다면 컨테이너들의 영향을 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 강력한 보안기능을 제공하지 못합니다. (개인적으로 도커의 가장 큰 단점이라고,,,생각함미다..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Docker의 Architecture&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2-1. Docker Daemon&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker API 요청을 수신하고 Docker 내부의 오브젝트들을 관리함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client측에서 Daemon에게 명령어를 전달하고 Demon이 명령어를 실행하는 구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2-2. Docker Client&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLI명령어를 사용하여 도커와 상호작용하게 해주는 수단 (인터페이스를 지칭하는 듯...?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2-3. Docker Registry&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Images를 저장하는 곳 (도커 이미지는 가상머신의 스냅샷같은 것을 말합니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: Docker Hub - 누구나 도커를 저장할 수 있는 퍼블릭 레지스트리 (프라이빗도 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2-4. Docker objects&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커에서 생성하고 사용하는 기타 개체&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <category>도커</category>
      <category>부트캠프</category>
      <category>코딩</category>
      <category>코딩교육</category>
      <category>코딩온</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/89</guid>
      <comments>https://jihyungk.tistory.com/89#entry89comment</comments>
      <pubDate>Tue, 2 Jan 2024 22:50:02 +0900</pubDate>
    </item>
    <item>
      <title>[코딩온] 웹 풀스택 영등포 5기 과정_next.js(2)</title>
      <link>https://jihyungk.tistory.com/88</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 위해 next.js 인강을 들으면서 새로 익혔던&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next.js에 대해 2부 시작하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;3. Link 컴포넌트 사용&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매우 단순하지만 어쨌든 next 13부터 바뀐 내용이니 다뤄보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704185643645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Link from 'next/link'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;먼저 next의 link에서 &lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Link 컴포넌트&lt;/b&gt;&lt;/span&gt;를 가져옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704185855962&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Page() {
	return &amp;lt;Link href=&quot;/&quot;&amp;gt;Dashboard&amp;lt;/Link&amp;gt;
   }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;a태그 처럼 사용하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;이렇게 바로 사용하는 경우보다는, 버튼을 눌렀을 때 움직이는 경우가 더 많습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;그럴 경우에는 &lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;useRouter&lt;/b&gt;&lt;/span&gt;라는 훅을 사용해서 사용할 수 있습니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704186914396&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
	const router = useRouter()
    
    return (
    &amp;lt;button onClick={() =&amp;gt; router.push('/')}&amp;gt;
    	Main
    &amp;lt;/button&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;next/navigation에서 useRouter를 호출해 온 다음에 간단하게 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;그다음&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt; push&lt;/b&gt;&lt;/span&gt;라는 함수를 사용해서 가고 싶은 경로를 작성해 주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;여기서 가장 큰 유의점은 useRouter는 client 사이드에서만 사용이 가능합니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;4. 데이터 캐싱과 페칭&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 전체적인 캐싱을 다 공부하기에는 양이 너무 방대해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;fetch&lt;/b&gt;를 위주로 공부하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;fetch api&lt;/b&gt;는 next.js에서 확장해서 제공하며 사용을 권장하고 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 fetch는 서버 컴포넌트와 클라이언트 컴포넌트에서 다 사용이 가능하며&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next.js에서 만드는 api에서도 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 이 next.js에서 제공하는 fetch를 사용하게 되면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;발생하는 모든 데이터들을 캐싱을 하고 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DubQ7/btsC1nJGFFr/0k9wDcnnAUOFoyyuagkTB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DubQ7/btsC1nJGFFr/0k9wDcnnAUOFoyyuagkTB0/img.png&quot; data-alt=&quot;server side&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DubQ7/btsC1nJGFFr/0k9wDcnnAUOFoyyuagkTB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDubQ7%2FbtsC1nJGFFr%2F0k9wDcnnAUOFoyyuagkTB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;487&quot; height=&quot;407&quot; data-origin-width=&quot;487&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;server side&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 현재 얘기하는 fetch에 대한 데이터 caching은 보라색 영역입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Data Recalidating (데이터 재검증)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1. 시간 기반 재검증&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 시간이 지날 때까지 캐싱을 유효화하다가 시간이 지나면 무효화함&lt;/p&gt;
&lt;pre id=&quot;code_1704194760793&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch('https://...', { next: { revalidate: 3600 }})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next라는 키를 가진 객체를 만들고&lt;b&gt; revalidate&lt;/b&gt;를 추가해 주면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3600초 동안 유효한 데이터를 만들어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 3600초가 지난다면 그 시간 이후에는 만료가 되어 새로운 데이터를 가져와서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 재검증이 이루어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2. 온디맨드 재검증 - 태그 기반의 재검증&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수요가 있을 때 검증하는 방법&lt;/p&gt;
&lt;pre id=&quot;code_1704195964832&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 캐시에 태그를 지정
fetch('https://...', { next: { tags: ['collection'] }})

// 태그된 캐시를 재검증
revalidateTag('collection')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 재검증을 위해 &lt;b&gt;태그&lt;/b&gt;를 사용해서 다시 소환해서 캐시를 재검증합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 데이터의 재검증이 이뤄지면서 최신화가 이루어지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;5. 메타 데이터&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;5-1. 정적 메타데이터&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;metadata를 객체로 정의하는 방법에서 이루어집니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1704196412533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import type { Metadata } from 'next'

export const metadata: Metadata = {
	title: '...',
    description: '...',
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Metadata 객체를 정의&lt;/b&gt;해서 title과 description을 정의해 주고 외부로 export 해주면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 정적 메타데이터를 사용할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;5-2. 동적 메타데이터&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 원하는 방식의 메타데이터 객체를 함수로 하는 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704197479094&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import type { Metadata, ResolvingMetadata } from 'next'

export async function generateMetadata (
	{ params, searchParams }: Props,
    parent?: ResolvingMetadata
): Promise&amp;lt;Metadata&amp;gt; {

	const id = params.id
    const post = await fetch(`https:// .../${id}`).then((res) =&amp;gt; res.json())
    const proviousImages = (await parent).openGraph?.images || []
    
    return {
    	title: post.titile,
        openGraph: {
        	images: ['/.....jpg', ...previousImages],
        },
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 generateMetadata 함수를 호출하게 되면 &lt;b&gt;return 안에 있는 객체&lt;/b&gt;로 전환되면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;객체를 통해 페이지를 정의&lt;/b&gt;할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가령 어떤 페이스북 페이지를 공유하게 된다면 공유했을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 별로 다른 공유페이지 사진, 설명이 나오는 경우에 활용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next.js 정리 끝 ---------------------------------------------&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <category>코딩온 #부트캠프 #코딩교육</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/88</guid>
      <comments>https://jihyungk.tistory.com/88#entry88comment</comments>
      <pubDate>Mon, 1 Jan 2024 01:41:31 +0900</pubDate>
    </item>
    <item>
      <title>[코딩온] 웹 풀스택 영등포 5기 과정_프로젝트 회고록</title>
      <link>https://jihyungk.tistory.com/87</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차 프로젝트를 끝내고 돌아왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희의 이번 프로젝트 포인트는 [ AI, Next.js ] 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 ai를 조금이라도 도입하길 원해서,,,쫄랐었구요 ㅎㅎ,,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 next.js는 저희가 많은 인원에 페이지도 많지 않아서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;툴이 어렵더라도 도전해볼만 하지 않을까 싶어 겁없이 도전하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 SPA인 React와 다른 SSR이 있어서 이 부분을 살리기 위해 노력을 좀 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 사용자에게 일기처럼 정보를 입력받아서 AI를 통해 결과를 내보이는 작업이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인이기 때문에 사실 SSR과 완벽히 맞는 프로젝트는 아니었던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;그래두,,, 해봤으니까 안맞구나 느낀 것이지 않을까,,,&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 했던 작업페이지와 다사다난했던 트러블 슈팅까지 써보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;0. 작업 페이지&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) my-shop 페이지&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 페이지는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;사용자 별로 퍼스널한 물건을 추천하는 페이지&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;사용자별로 다르기때문에 profile 내의 간이 페이지처럼 있으며,&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Naver Shopping API&lt;/b&gt;를 사용하여 추천하고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buUFrW/btsCN8no687/eKz7KxrVE9vphV3ShvHrc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buUFrW/btsCN8no687/eKz7KxrVE9vphV3ShvHrc1/img.png&quot; data-alt=&quot;1. profile 내 my-shop 상점 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buUFrW/btsCN8no687/eKz7KxrVE9vphV3ShvHrc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuUFrW%2FbtsCN8no687%2FeKz7KxrVE9vphV3ShvHrc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1018&quot; height=&quot;860&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1. profile 내 my-shop 상점 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJuu80/btsCN37pOma/JkMRGsNHR6vtITal5AUls1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJuu80/btsCN37pOma/JkMRGsNHR6vtITal5AUls1/img.png&quot; data-alt=&quot;Naver 요청 날리는 코드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJuu80/btsCN37pOma/JkMRGsNHR6vtITal5AUls1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJuu80%2FbtsCN37pOma%2FJkMRGsNHR6vtITal5AUls1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;832&quot; height=&quot;432&quot; data-origin-width=&quot;832&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Naver 요청 날리는 코드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개의&lt;b&gt; Shopping API&lt;/b&gt;를 사용해보려고 검색을 많이 해봤는데, (쿠팡, 티몬 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 알고리즘을 고려하여 여러 페이지에서 검색해본 결과&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 쿼리를 가장 유연하게 사용할 수 있는 쇼핑 페이지가 단연 &lt;b&gt;네이버가 체감 1등&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버 검색 쿼리를 사용자별로 다르게 하고 싶어서 나름 알고리즘(?)도 적용하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FkivF/btsCOy0or4T/tzPp9PvEfArJ3fyO2sx1k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FkivF/btsCOy0or4T/tzPp9PvEfArJ3fyO2sx1k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FkivF/btsCOy0or4T/tzPp9PvEfArJ3fyO2sx1k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFkivF%2FbtsCOy0or4T%2FtzPp9PvEfArJ3fyO2sx1k0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;901&quot; height=&quot;428&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 회원가입 때 받았던 &lt;b&gt;성별&lt;/b&gt;과 &lt;b&gt;나이&lt;/b&gt;, 그리고 &lt;b&gt;사용자의 최근 기분&lt;/b&gt;을 API로 받아와서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 쿼리를 사용자별로 다르게 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Naver Shopping API 검색 쿼리 옵션 중에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sort(정렬 기준) 쿼리&lt;/b&gt;와 &lt;b&gt;start (검색 시작 위치)&lt;/b&gt;를 통해 같은 사용자의 상태값이더라도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 다르다면 늘 새로운 옵션으로 업데이트한 효과를 볼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) account 페이지&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원 정보 수정 페이지입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHr94R/btsCWKER58g/2fA0wCgnfwTPTPvGtDKCB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHr94R/btsCWKER58g/2fA0wCgnfwTPTPvGtDKCB0/img.png&quot; data-alt=&quot;2. 회원정보 수정 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHr94R/btsCWKER58g/2fA0wCgnfwTPTPvGtDKCB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHr94R%2FbtsCWKER58g%2F2fA0wCgnfwTPTPvGtDKCB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1020&quot; height=&quot;862&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2. 회원정보 수정 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회원가입 시 자동으로 부여되는 닉네임이랑 비밀번호는 변경하지 못하도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 아이디와 연령, 나이를 바꿀 수 있도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 트러블 슈팅&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) 새로고침 시 profile 페이지 내 메뉴바 유지 안됨&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;gt;&amp;gt;&amp;gt;&amp;gt; 메뉴바에서 useState로 초기값을 profile 페이지의 기본 페이지로 지정함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;gt;&amp;gt;&amp;gt;&amp;gt; 새로고침할 시 사용자가 선택했던 profile 메뉴바의 선택값이 초기화 되어서 페이지와 일치하지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;gt;&amp;gt;&amp;gt;&amp;gt; 헤더처럼 상주하는 컴포넌트가 아니라, profile 페이지에서만 상주하는 특성 때문에 초기화되는 점이 불편했음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;! How to fix&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 유저의 로그인 상태값을 &lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Recoil&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Recoil persistAtom&lt;/b&gt;&lt;/span&gt;을 통해 관리를 하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Recoil에 사용자가 현재 프로필 페이지 내에서 몇 번째 메뉴바 아이콘을 선택했는지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저장하고 관리하도록&lt;/b&gt; 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 프로필 페이지를 아예 벗어나서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다른 페이지로 이동할 때 헤더에서 &lt;/b&gt;&lt;b&gt;Recoil 상태를 초기화&lt;/b&gt; 하도록 하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 프로필 페이지를 들어갔을 때 초기화된 프로필 페이지와 메뉴바를 만날 수 있도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cczoh0/btsCTXEHVUB/KovVJhyRdJxmocEGLjPoZK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cczoh0/btsCTXEHVUB/KovVJhyRdJxmocEGLjPoZK/img.gif&quot; data-alt=&quot;문제의 영상&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cczoh0/btsCTXEHVUB/KovVJhyRdJxmocEGLjPoZK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cczoh0/btsCTXEHVUB/KovVJhyRdJxmocEGLjPoZK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;658&quot; height=&quot;644&quot; data-origin-width=&quot;658&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;문제의 영상&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egTXlk/btsCMzMdIII/uqFt7NDMCeeLprzGUT1tm0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egTXlk/btsCMzMdIII/uqFt7NDMCeeLprzGUT1tm0/img.gif&quot; data-alt=&quot;수정 후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egTXlk/btsCMzMdIII/uqFt7NDMCeeLprzGUT1tm0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/egTXlk/btsCMzMdIII/uqFt7NDMCeeLprzGUT1tm0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;604&quot; height=&quot;596&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수정 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) Naver Shopping API Cors error&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Naver Shopping API에서 request URL이 직접 호출되어 &lt;b&gt;Cors error&lt;/b&gt;가 남&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhxzH9/btsCQ5csaWo/7X0vnabaI9PWrnjKECfuRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhxzH9/btsCQ5csaWo/7X0vnabaI9PWrnjKECfuRk/img.png&quot; data-alt=&quot;하,,,,,,404,,,,&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhxzH9/btsCQ5csaWo/7X0vnabaI9PWrnjKECfuRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhxzH9%2FbtsCQ5csaWo%2F7X0vnabaI9PWrnjKECfuRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1082&quot; height=&quot;386&quot; data-origin-width=&quot;1082&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하,,,,,,404,,,,&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;! How to fix&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Proxy&lt;/b&gt;라는 것을 난 생 처음 사용해보았는데요, Next.js의 14버전에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cors error로 Proxy로 URL을 우회할 때 &lt;b&gt;next.config.js에서 rewrite&lt;/b&gt;로 뚫었습니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IOaut/btsCQrUecJ9/ZdtjpYKqy0gokkVf8oBWc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IOaut/btsCQrUecJ9/ZdtjpYKqy0gokkVf8oBWc0/img.png&quot; data-alt=&quot;next.config.js&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IOaut/btsCQrUecJ9/ZdtjpYKqy0gokkVf8oBWc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIOaut%2FbtsCQrUecJ9%2FZdtjpYKqy0gokkVf8oBWc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;638&quot; height=&quot;230&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;next.config.js&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source에 내가 우회해서 사용할 url을 작성하고 { :path* } 를 달면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;destination을 통해 api 요청을 날리게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQIVed/btsCUYwC5j3/ZI6PApxdCcmHv4DHWEz8tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQIVed/btsCUYwC5j3/ZI6PApxdCcmHv4DHWEz8tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQIVed/btsCUYwC5j3/ZI6PApxdCcmHv4DHWEz8tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQIVed%2FbtsCUYwC5j3%2FZI6PApxdCcmHv4DHWEz8tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;52&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 사용하면 하위 path를 잘 달고 API 요청을 대신 날리게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3) 아이폰 safari에서 svg 깨짐 현상&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이폰에서 safari로 열게 되면 SVG가 픽셀이 깨지는 현상이 일어났습니다.....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 오래전부터 있었던 iphone svg blurry 라는 오래묵은 이슈인 듯합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ykikn/btsC0ZJyRxf/7HMtXUXrRJ9WQ52tTwnkZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ykikn/btsC0ZJyRxf/7HMtXUXrRJ9WQ52tTwnkZk/img.png&quot; data-alt=&quot;수정 전 - error 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ykikn/btsC0ZJyRxf/7HMtXUXrRJ9WQ52tTwnkZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fykikn%2FbtsC0ZJyRxf%2F7HMtXUXrRJ9WQ52tTwnkZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1170&quot; height=&quot;249&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수정 전 - error 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;! How to fix&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단, 도움이 되었는지 모르나, svg 내의 width와 height를 %로 변경하였다. viewport도 변경함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 next.js 공식 문서에 webp확장자를 권한다고 되어있어서, &lt;b&gt;svg를 webp확장자로 변경&lt;/b&gt;함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clI18c/btsCSBQFDoM/I8oHkzdIZcPt9SN0eASIk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clI18c/btsCSBQFDoM/I8oHkzdIZcPt9SN0eASIk0/img.png&quot; data-alt=&quot;수정 후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clI18c/btsCSBQFDoM/I8oHkzdIZcPt9SN0eASIk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclI18c%2FbtsCSBQFDoM%2FI8oHkzdIZcPt9SN0eASIk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1170&quot; height=&quot;310&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수정 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝 -----------------&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <category>코딩온 #부트캠프 #코딩교육</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/87</guid>
      <comments>https://jihyungk.tistory.com/87#entry87comment</comments>
      <pubDate>Sun, 31 Dec 2023 23:22:47 +0900</pubDate>
    </item>
    <item>
      <title>[코딩온] 웹 풀스택 영등포 5기 과정_next.js(1)</title>
      <link>https://jihyungk.tistory.com/86</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3차 프로젝트에 들어가서 요즘 조금 바쁜,,,,나날들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 3차 프로젝트로 next.js와 scss를 사용하기로 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 프로젝트로 next.js를 도입하면서 배웠던 몇 가지 내용을 정리해보려합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;0. Next.js 왜 탄생하게 되었는가?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2013년 &lt;b&gt;React&lt;/b&gt;가 페이스북의 손을 타서 세상에 나오게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 React는 정말 센세이션했고, 지금 10년 이상 React는 여전히 프론트엔드의 강자라고 불리죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다들 잘 아시겠지만, &lt;b&gt;단방향 데이터 흐름&lt;/b&gt;과 &lt;b&gt;Virtual DOM&lt;/b&gt;이 큰 특징입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, next.js를 공부하기 전까지는 잘 와닿지 않았는데 &lt;b&gt;'Client Side Rendering'&lt;/b&gt;을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;Client Side Rendering&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 SPA에서는 CSR(Client Side Rendering)을 하고 MPA에서는 SSR(Server Side Rendering)을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA에서는 정적인 리소스를 한꺼번에 다운로드하고, 클라이언트의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적인 새로운 요청이 왔을 때 그 부분만 변환하여 필요한 컴포넌트만 갱신하는 방식이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSR을 합니다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;Server Side Rendering&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MPA의 구조에서 &lt;b&gt;Server Side 측에서 렌더링을 해두는 방식&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSR은 유저가 웹페이지를 방문하면 빈 HTML 뼈대를 보내고, 동적으로 DOM 요소를 그제서야 만들기 시작하기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기 로딩 속도가 느린 대신에, 구동만 하면 그 다음부터는 빠르다는장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 SSR은 빈 HTML이 아니라 이미 꽉 차있는, 그러니까 CSS까지 다 담긴 알찬&lt;b&gt; HTML을 미리 구동&lt;/b&gt;해두기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SEO에 유리&lt;/b&gt;합니다. 이는 곧 마케팅이죠 ㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[참고한 블로그&amp;darr; ]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev-ellachoi.tistory.com/28&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev-ellachoi.tistory.com/28&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSR만 하다보니 SEO를 하기가 너무 힘들어져서, &lt;b&gt;SSR&lt;/b&gt;을 구동하기로 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저에겐 좀 신박한 개념이었어요, 뭔가 유저가 초기 로딩만 기다리면 웹 페이지 이용이 수월하니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 CSR 시대가 왔구나 싶었는데, SEO 때문에 서버 측에서 Hydration을 하는 것이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 니즈가 생기게 된 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. app router&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 Next.js를 배우면서 제일 신기하고, 편했던 기능은 단연 &lt;b&gt;app router&lt;/b&gt;가 아닐까 싶습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날 옛적에 찍은 유투브를 보면서 pages router와 헷갈려서 시간을 좀 날려먹었는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pages router에서 Next.js 13버전으로 승급하며 app router로 갈아치기 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next.js를 create app하게 되면, &lt;b&gt;app&lt;/b&gt;이라는 폴더가 생성이됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brkn0U/btsB6glyvpm/zaM2ko8lXSEcs0ruP65KGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brkn0U/btsB6glyvpm/zaM2ko8lXSEcs0ruP65KGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brkn0U/btsB6glyvpm/zaM2ko8lXSEcs0ruP65KGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbrkn0U%2FbtsB6glyvpm%2FzaM2ko8lXSEcs0ruP65KGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;312&quot; height=&quot;263&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 프로젝트 팀의 app 폴더 내 구조인데요, 보시면 &lt;b&gt;app&lt;/b&gt; 폴더 내에 &lt;b&gt;profile&lt;/b&gt; 폴더 내에&lt;b&gt; page.tsx&lt;/b&gt; 가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(맞습니다! TypeScript를 겁없게도 사용 하고 있죠 ㅋ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 &lt;b&gt;파일 구조에 따라 router 명이 달라집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무슨 말이냐면, &lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;app/ profile/ myShop/ page.tsx&lt;/b&gt;&lt;/span&gt;의 구조를 갖춘다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;localhost:3000/profile/myShop&lt;/b&gt;&lt;/span&gt;에 page.tsx가 뜨게 된다는말입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7lgdS/btsB7i4cc6Q/7k3aVpHs49G4debCxldIH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7lgdS/btsB7i4cc6Q/7k3aVpHs49G4debCxldIH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7lgdS/btsB7i4cc6Q/7k3aVpHs49G4debCxldIH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7lgdS%2FbtsB7i4cc6Q%2F7k3aVpHs49G4debCxldIH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1388&quot; height=&quot;536&quot; data-origin-width=&quot;1388&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 똑똑한 사람이 이런 개념을 만들었을 까요?!?!?!? 진짜,,,,너무 대단한 것같습니다.....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 입장에서,,,,너무 깔끔하고 좋아요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;page.tsx&lt;/b&gt;를 만들면 &lt;b&gt;정상 작동&lt;/b&gt; 되었을 때 그 page라는 이름을 가진 파일을 뱉어내고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;error.tsx&lt;/b&gt;를 만들면 &lt;b&gt;에러&lt;/b&gt;가 났을 때 error 페이지를 뱉어내고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;loading.tsx&lt;/b&gt;를 만들면 &lt;b&gt;로딩&lt;/b&gt; 중일 때 loading 페이지를 뱉어냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 라우터의 개념이 있는 app폴더는 가급적 깔끔하게 router의 역할로 두는 편이 낫다고 생각해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 오로지 페이지를 불러오는 개념으로 router 본연의 색깔을 해치지 않도록 노력하고 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 기본 RSC&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서는 기본적으로 &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;b&gt;RSC( &lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;b&gt;React Server Component)&lt;/b&gt;를 기본 컴포넌트 렌더링 방식으로 채택하고 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;RSC는 JS의 번들 크기를 줄일 수 있고, &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;Server 측이니까 데이터베이스와 가까운 곳에서 조회하기 때문에 빠르다는 장점이 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;그러나 특정 컴포넌트가&lt;b&gt; useState나, useEffect처럼 유저와 소통하는 CSR를 사용&lt;/b&gt;하려면&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;'use client'&lt;/b&gt;를 컴포넌트 파일 상단에 선언해주면 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HYikC/btsB5B4yvA4/hxlsj4EKyHFqLomzVvtuP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HYikC/btsB5B4yvA4/hxlsj4EKyHFqLomzVvtuP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HYikC/btsB5B4yvA4/hxlsj4EKyHFqLomzVvtuP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHYikC%2FbtsB5B4yvA4%2Fhxlsj4EKyHFqLomzVvtuP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;142&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;저도 현재 열심히 만들고 있는 menu bar의 경우 서버단의 데이터베이스 조회보다는,&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;user와의 상호작용이 많기 때문에 use client를 선언해주고 useState를 열심히 사용하고 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;그래서 사실, CSR을 사용할 때에는&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt; DOM에서 제일 리프에 있는 컴포넌트들을 CSR하는 것이 &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이상적이라고 합니다.&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bosvM5/btsCc443TKn/lIOpahfZvOlMLbXQcmKWJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bosvM5/btsCc443TKn/lIOpahfZvOlMLbXQcmKWJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bosvM5/btsCc443TKn/lIOpahfZvOlMLbXQcmKWJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbosvM5%2FbtsCc443TKn%2FlIOpahfZvOlMLbXQcmKWJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;930&quot; height=&quot;690&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;3. Link 컴포넌트 사용 / 4. 데이터 페칭 / 5. 메타 데이터&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;이 부분은 2부에서 다루도록 하겠습니다!!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <category>코딩온 #부트캠프 #코딩교육</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/86</guid>
      <comments>https://jihyungk.tistory.com/86#entry86comment</comments>
      <pubDate>Sun, 17 Dec 2023 23:08:46 +0900</pubDate>
    </item>
    <item>
      <title>[SeSSAC] 웹 풀스택 영등포 5기 과정_SpringBoot_dto,vo,axios, API</title>
      <link>https://jihyungk.tistory.com/85</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;br /&gt;업보처럼 차곡차곡 수업 내용 복습을 미루다가 더 늦기전에 후다닥 하는 중입니다ㅠ &lt;br /&gt;&lt;br /&gt;스프링 부트 설치는 그다지 어렵지 않고, 그 이후에 정확히 원리를 알고 이용하는 것이 중요하기 때문에&lt;br /&gt;설치&amp;nbsp;후에&amp;nbsp;내용을&amp;nbsp;다뤄보도록&amp;nbsp;하겠습니다! &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;0.&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;설치&amp;nbsp;후&amp;nbsp;이&amp;nbsp;파일들&amp;nbsp;뭔데?&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) src/main/java&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;저희가 추후 작성할 대부분의 자바 파일들이 들어갈 공간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨트롤러, DTO, 데이터 베이스 처리를 위한 엔티티,&amp;nbsp; 서비스 파일 등 다양한 파일이 들어갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) src/main/resource&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기는 자바 파일을 제외한 환경 설정 및 HTML, CSS, 정적 파일 등이 들어갈 공간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 resource파일 내에 다양한 하위 디렉토리들이 또 있는데요,&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;static&lt;/b&gt; : 정적인 파일들이 들어갑니다. js,image, html, css 등이 들어갑니다!&lt;/li&gt;
&lt;li&gt;&lt;b&gt;templates:&lt;/b&gt; HTML 파일의 형태로 자바의 객체와 연동되는 파일이라고 합니다. 저희 수업에서는 thymeleaf(타임리프)라는 서버 사이드 템플릿 엔진을 사용하고 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;application.properties:&lt;/b&gt; 해당 애플리케이션의 설정을 정의하는데 사용되는 프로퍼티 파일입니다. 예시로는, 서버 포트를 설정하고, 데이터베이스 연결을 설정하거나 이름 설정 등 다양한 설정을 정의할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3) build.gradle&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파일은 그레이들이라는 아이가 사용하는 환경 파일입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(&lt;b&gt;gradle은 Groovy 언어를 기반으로 한 빌드 도구&lt;/b&gt;로, 프로젝트를 구성하고 빌드 스크립트를 작성합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Maven과 Ant 보다 좋다고 하네요)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 출저: &lt;a href=&quot;https://wikidocs.net/160947&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wikidocs.net/160947&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1701790282159&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2-01 스프링부트 프로젝트의 구조&quot; data-og-description=&quot;현재 SBB 프로젝트는 HelloController.java와 HelloLombok.java 파일만 생성한 상태다. 그런데 이보다 규모를 갖춘 프로젝트를 만들고자 한다면 프로젝트&amp;hellip;&quot; data-og-host=&quot;wikidocs.net&quot; data-og-source-url=&quot;https://wikidocs.net/160947&quot; data-og-url=&quot;https://wikidocs.net/160947&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uau7u/hyUE0yiZyh/ayfx3aCqhL9wG0qLawCZak/img.png?width=308&amp;amp;height=400&amp;amp;face=88_82_218_224,https://scrap.kakaocdn.net/dn/4Adqi/hyUE3BO3q9/gVvnwDWvduJa7ZEV9DpbLK/img.png?width=346&amp;amp;height=403&amp;amp;face=0_0_346_403&quot;&gt;&lt;a href=&quot;https://wikidocs.net/160947&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://wikidocs.net/160947&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uau7u/hyUE0yiZyh/ayfx3aCqhL9wG0qLawCZak/img.png?width=308&amp;amp;height=400&amp;amp;face=88_82_218_224,https://scrap.kakaocdn.net/dn/4Adqi/hyUE3BO3q9/gVvnwDWvduJa7ZEV9DpbLK/img.png?width=346&amp;amp;height=403&amp;amp;face=0_0_346_403');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2-01 스프링부트 프로젝트의 구조&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 SBB 프로젝트는 HelloController.java와 HelloLombok.java 파일만 생성한 상태다. 그런데 이보다 규모를 갖춘 프로젝트를 만들고자 한다면 프로젝트&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;wikidocs.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. DTO, VO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바를 배운지 얼마 되지 않았지만, REST API를 배우니 자주 사용하는 단어가 등장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO와 VO라는 단어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) DTO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MNfQJ/btsBux8hmQp/ba0uVddffFEcobUPFmg4I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MNfQJ/btsBux8hmQp/ba0uVddffFEcobUPFmg4I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MNfQJ/btsBux8hmQp/ba0uVddffFEcobUPFmg4I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMNfQJ%2FbtsBux8hmQp%2Fba0uVddffFEcobUPFmg4I1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;163&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로직을 갖고 있지 않은 순수한 데이터 객체를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 &quot;&lt;b&gt;전달&lt;/b&gt;&quot;의 용도로 사용하기 때문에 &lt;b&gt;getter와 setter를 제외한 타 로직은 들어가지 않습니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 밑에서 배우는 VO는 객체에 있는 데이터 그 자체를 갖고 가는 느낌이고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO는 객체 상자여서 그걸 나를 수 있는 형태? 같은 느낌이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아닐수도,,,)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emnWcZ/btsBvnEkVHv/f0K97AA4j2Svkv3nghGxak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emnWcZ/btsBvnEkVHv/f0K97AA4j2Svkv3nghGxak/img.png&quot; data-alt=&quot;UserDTO 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emnWcZ/btsBvnEkVHv/f0K97AA4j2Svkv3nghGxak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemnWcZ%2FbtsBvnEkVHv%2Ff0K97AA4j2Svkv3nghGxak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;332&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;UserDTO 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깔끔하고 간단하쥬?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) VO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO와 달리 값 오브젝트를 지닌 &lt;b&gt;데이터 값 그 자체&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VO는 setter가 없고, &lt;b&gt;getter만 있기 때문에&lt;/b&gt;, 값 변경이 불가능하고 &lt;b&gt;데이터 불변성을 보장&lt;/b&gt;한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;Read-Only&lt;/b&gt; 속성을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 값 자체가 의미가 있는 게 VO 이고, 이 전달될 데이터들이 잘 보존되는 걸 보장하는 게 DTO라고 하네요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 DTO와 VO가 따로 뭐 모듈이나, 어떤 새로운 무언가인 줄 알았는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저 이런 속성을 가진 데이터를 정의하고, 저희가 이걸 사회적으로 각각 DTO, VO라고 부르기로 한거라네요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3) api를 해보자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수업 시간에 api를 배우면서 간단한 구조를 만들고, get, post 등을 mapping하는 것을 배웠었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4vgmn/btsBxUPY7VO/Xc6ka01Wm45zKa5c5pQsSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4vgmn/btsBxUPY7VO/Xc6ka01Wm45zKa5c5pQsSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4vgmn/btsBxUPY7VO/Xc6ka01Wm45zKa5c5pQsSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4vgmn%2FbtsBxUPY7VO%2FXc6ka01Wm45zKa5c5pQsSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;332&quot; height=&quot;253&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더 구조를 본다면 java파일 안에 controller와 배웠던 dto, vo 패키지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;resources 패키지 안에는 static패키지와 templates패키지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 controller 중,&lt;b&gt; HelloController&lt;/b&gt;를 보도록 하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1701852464748&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller
public class HelloController {
    @GetMapping(&quot;hi&quot;)
    public String getHi(Model model) {
        Hello hello = new Hello(99);
        int age = 17;
        List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;Kim&quot;, &quot;Lee&quot;, &quot;Hong&quot;, &quot;Park&quot;);
        model.addAttribute(&quot;hello&quot;, &quot;Spring World&quot;);
        model.addAttribute(&quot;uText&quot;, &quot;&amp;lt;onstrong&amp;gt;Hello&amp;lt;/strg&amp;gt;&quot;);
        model.addAttribute(&quot;value&quot;, &quot;이름을 입력하세요!&quot;);
        model.addAttribute(&quot;WithValue&quot;, &quot;hello&quot;);
        model.addAttribute(&quot;link&quot;, &quot;hi&quot;);
        model.addAttribute(&quot;imgSrc&quot;, &quot;cutecat.jpg&quot;);
        model.addAttribute(&quot;userRole&quot;, &quot;admin&quot;);
        model.addAttribute(&quot;isAdmin&quot;, false);
        model.addAttribute(&quot;names&quot;, names);
        model.addAttribute(&quot;classHello&quot;, hello);
        return  &quot;hi&quot;;
    }

    class Hello {
        private int age;
        public Hello(int age) {this.age = age;}
        public int getAge() {return age;}
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@Controller 어노테이션:&lt;/b&gt; 해당 클래스가 컨트롤러임을 알려줌&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@GetMapping(&quot;hi&quot;):&lt;/b&gt; /hi 경로로 들어오는 GET 요청에 대한 처리를 담당하는 메소드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Model model:&lt;/b&gt; Thymeleaf 템플릿에 데이터를 전달하기 위한 모델 객체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hello 클래스:&lt;/b&gt; 데이터 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Controller를 통해 이런 Thymeleaf로 view를 보여줄 수 있게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1701853273375&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot; xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;Title&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;!-- 타임리프 표현식과 문법 --&amp;gt;
    &amp;lt;p th:text=&quot;'안녕하세요. ' + ${hello}&quot;&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;p th:utext=&quot;${uText}&quot;&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;input type=&quot;text&quot; th:value=&quot;${value}&quot;&amp;gt;
    &amp;lt;p th:with=&quot;temp=${withValue}&quot; th:text=&quot;${temp}&quot;&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;a th:href=&quot;@{/{id}(id=${link})}&quot;&amp;gt;Link 1 (hi)&amp;lt;/a&amp;gt; &amp;lt;br /&amp;gt;
    &amp;lt;a th:href=&quot;@{/hi}&quot;&amp;gt;Link 2 (hi)&amp;lt;/a&amp;gt; &amp;lt;br /&amp;gt;
    &amp;lt;a th:href=&quot;@{https://www.google.com}&quot;&amp;gt;Google&amp;lt;/a&amp;gt; &amp;lt;br /&amp;gt;
    &amp;lt;img th:src=&quot;${imgSrc}&quot;&amp;gt;

    &amp;lt;div th:switch=&quot;${userRole}&quot;&amp;gt;
        &amp;lt;p th:case=&quot;'admin'&quot;&amp;gt;Hello, Admin&amp;lt;/p&amp;gt;
        &amp;lt;p th:case=&quot;'user'&quot;&amp;gt;Hello, User&amp;lt;/p&amp;gt;
        &amp;lt;p th:case=&quot;*&quot;&amp;gt;Hello, Unknown&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div&amp;gt;
        &amp;lt;p th:if=&quot;${isAdmin}&quot;&amp;gt;Welcome, Admin&amp;lt;/p&amp;gt;
        &amp;lt;p th:unless=&quot;${isAdmin}&quot;&amp;gt;Welcome, Admin&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li th:each=&quot;name:${names}&quot; th:text=&quot;${name}&quot;&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;div th:text=&quot;${classHello.getAge()}&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lhGJ2/btsBvg7gTTY/6SMgjti1fNyvneJdYx53WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lhGJ2/btsBvg7gTTY/6SMgjti1fNyvneJdYx53WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lhGJ2/btsBvg7gTTY/6SMgjti1fNyvneJdYx53WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlhGJ2%2FbtsBvg7gTTY%2F6SMgjti1fNyvneJdYx53WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;822&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시면, 순서에 따라 제가 Controller에서 addAttribute한 name값과 일치한다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thymeleaf에서 잘 표현되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4) GetMapping을 다양하게 사용하는 법&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아는 분들은 아시다시피, Get을 사용하는 것은 단순히 url에 따른 html을 로드하는 것도 있지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url의 뒤에 &lt;b&gt;query&lt;/b&gt;를 사용하여 사용자값에 따라 다른 url을 보여주기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여, 알아보도록 하겠습니다!&lt;/p&gt;
&lt;pre id=&quot;code_1701853842384&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // case 1.
    @GetMapping(&quot;/get/response1&quot;)
    public String getResponse1(@RequestParam(value=&quot;name&quot;) String  name, @RequestParam(value=&quot;age&quot;) String age, Model model) {
       
        model.addAttribute(&quot;name&quot;, name);
        return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case1.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@RequestParam&lt;/b&gt;을 이용하여 value에는 key값을, 그 다음에는 value값을 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에는, required=true가 디폴트로 되어있어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약의 뒤에 값이 없다면 이 controller를 찾지 못해서 400 error가 뜨게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701854723150&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;   // case 2.
    @GetMapping(&quot;/get/response2&quot;)
    public String getResponse2(@RequestParam(value=&quot;name&quot;, required = false) String  name, Model model) {
        model.addAttribute(&quot;name&quot;, name);
        return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case2.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우는 case1과 같지만, 이번에는 required=false를 설정하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤의 값이 없어도 400에러가 뜨지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;pre id=&quot;code_1701854725910&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    // case 3.
    @GetMapping(&quot;/get/response3/{name}/{age}&quot;)
    public String getResponse3(@PathVariable(value=&quot;name&quot;) String n, 
                               @PathVariable String age, Model model) {
        model.addAttribute(&quot;name&quot;, n);
        model.addAttribute(&quot;age&quot;, &quot;13&quot;);
        return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case3.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우는 url에 RequestParam대신에 &lt;b&gt;@PathVariable&lt;/b&gt;을 사용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;url에 있는 여러개의 변수를 받아올 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clvAhY/btsBzw8R5pH/FwFKacmDO7yQYxGO2tFQj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clvAhY/btsBzw8R5pH/FwFKacmDO7yQYxGO2tFQj1/img.png&quot; data-alt=&quot;name에는 asdf가, age에는 33을 입력하니, 잘 반영이 되는 것을 볼 수 있습니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clvAhY/btsBzw8R5pH/FwFKacmDO7yQYxGO2tFQj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclvAhY%2FbtsBzw8R5pH%2FFwFKacmDO7yQYxGO2tFQj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;192&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;name에는 asdf가, age에는 33을 입력하니, 잘 반영이 되는 것을 볼 수 있습니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;pre id=&quot;code_1701854728398&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    // case 4.
    @GetMapping({&quot;/get/response4/{name}&quot;, &quot;/get/response4/{name}/{age}&quot;})
    public String getResponse4(@PathVariable(value=&quot;name&quot;) String n,
                               @PathVariable(required = false) String age, Model model) {
        model.addAttribute(&quot;name&quot;, n);
        model.addAttribute(&quot;age&quot;, age);
        return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case4.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개의 url패턴을 하나의 메소드에서 처리할 수 있는 경우입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;age값이 false라서, name값이 있는 url과 name값과 age값 전부 있는 url을 유연하게 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs8bBL/btsBrOquDUZ/FIPZNSyCiHCc5QQaQXLd91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs8bBL/btsBrOquDUZ/FIPZNSyCiHCc5QQaQXLd91/img.png&quot; data-alt=&quot;age가 파라미터에 붙지 않아도 ok&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs8bBL/btsBrOquDUZ/FIPZNSyCiHCc5QQaQXLd91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs8bBL%2FbtsBrOquDUZ%2FFIPZNSyCiHCc5QQaQXLd91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;200&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;age가 파라미터에 붙지 않아도 ok&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brYMBN/btsByaZIBST/hhWtTIjCAw0whNARe4fDkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brYMBN/btsByaZIBST/hhWtTIjCAw0whNARe4fDkk/img.png&quot; data-alt=&quot;age가 뒤에 붙어도 ok&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brYMBN/btsByaZIBST/hhWtTIjCAw0whNARe4fDkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrYMBN%2FbtsByaZIBST%2FhhWtTIjCAw0whNARe4fDkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;527&quot; height=&quot;203&quot; data-origin-width=&quot;527&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;age가 뒤에 붙어도 ok&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;5) Post도 알아보자&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701855050165&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // case 1.
	@PostMapping(&quot;/post/response1&quot;)
        public String postResponse1(@RequestParam(value=&quot;name&quot;) String name, Model model) {
            model.addAttribute(&quot;name&quot;, name);
            return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case 1.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Post 전송은 &lt;b&gt;@PostMapping&lt;/b&gt; 어노테이션을 활용하며, 전달되는 값은 &lt;b&gt;@RequestParam&lt;/b&gt;을 사용해서 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt; HTML 폼으로 POST 요청을 보낼 때는 &lt;/span&gt;@RequestParam&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;을 사용하여 쿼리 파라미터를 읽어올 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name이라는 key값이 담아서 name이라는 value로 전달하며, response라는 html을 반환하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;pre id=&quot;code_1701855246240&quot; class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    // case 2.
    @PostMapping(&quot;/post/response2&quot;)
        public String postResponse2(@RequestParam(value=&quot;name&quot;, required = false) String name, Model model) {
            model.addAttribute(&quot;name&quot;, name);
            return &quot;response&quot;;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case 2.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 케이스는 1과 동일한데, name값에 required = false가 추가 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name값에 해당하는 키가 없어도 실행은 된다~ 이 말입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;pre id=&quot;code_1701856047038&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // case 3.
    @PostMapping(&quot;/post/response3&quot;)
    @ResponseBody
    public String postResponse3(@RequestParam(value=&quot;name&quot;, required = false) String name, Model model) {
        model.addAttribute(&quot;name&quot;, name);
        return name;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;case 3.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 앞선 모든 케이스에서는 return을 template 내 html파일로 진행했었는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post로 리턴하는 &lt;b&gt;문자열의 그대로 값&lt;/b&gt;을 전달할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@ResponseBody&lt;/b&gt; 어노테이션을 사용한다면 html파일을 불러오지 않고, 값을 &lt;b&gt;send&lt;/b&gt;할 수 있습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;5) post의 값을 객체로 전달할 때&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 post의 값을 받아올 때 늘 하나하나 받아오면 좋겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그걸 객체로 처리해야할 때가 있잖아요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 경우입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1701873152272&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @GetMapping(&quot;/dto/response1&quot;)
    @ResponseBody
    public String dtoResponse1(@ModelAttribute UserDTO userDTO) {
        String msg = &quot;이름 : &quot; + userDTO.getName() + &quot;, 나이 : &quot; + userDTO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;@ModelAttribute&lt;/b&gt;로 이 들어오는 데이터가 UserDTO라는 객체인 것을 알려주고 매핑해줍니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 userDTO의 getter로 데이터에 접근할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 @ModelAttribute는 생략이 가능합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701873758729&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @PostMapping(&quot;/dto/response3&quot;)
    @ResponseBody
    public String dtoResponse3(@RequestBody UserDTO userDTO) {
        String msg = &quot;이름 : &quot; + userDTO.getName() + &quot;, 나이 : &quot; + userDTO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 위에서 @ModelAttribute를 사용했느냐 @RequestBody를 사용했느냐의 차이인데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 값을 입력한 곳은 &lt;b&gt;일반 폼 전송&lt;/b&gt;으로, &lt;b&gt;www-x-form-urlencoded의 형태로 데이터를 전송&lt;/b&gt;하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 형태로는 &lt;b&gt;RequestBody를 받을 수 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오로지 json형태와 xml 형태로 데이터가 들어와야만 RequestBody 어노테이션을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;6) axios와 DTO, VO를 사용할 때&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기나긴 여정이 될 것입니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO를 axios와 쓸 때 5가지 경우를 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1. Get + DTO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701876951707&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function dtoResponse1() {
        var form = document.getElementById('form_dto1');
        axios.get(`/axios/response1?name=${form.name.value}&amp;amp;age=${form.age.value}`)
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse1 : ', res.data );
            });
    }
    
    function dtoResponse2() {
        var form = document.getElementById('form_dto1');
        axios.get(`/axios/response2?name=${form.name.value}&amp;amp;age=${form.age.value}`)
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse2 : ', res.data );
            });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1701876981439&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @GetMapping(&quot;/axios/response1&quot;) // 정상
    @ResponseBody
    public String axiosAPI1(@RequestParam(value = &quot;name&quot;) String name, @RequestParam(value = &quot;age&quot;) String age){
        String msg = &quot;이름 : &quot; + name + &quot;\n나이 :&quot; + age;
        return msg;
    }
    
    @GetMapping(&quot;/axios/response2&quot;) // 정상
    @ResponseBody
    public String axiosAPI2(UserDTO userDTO){
            String msg = &quot;이름 : &quot; + userDTO.getName() + &quot;\n나이 :&quot; + userDTO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #374151; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 URL에 노출되어 전송되기 때문에 일반적인 GET 요청에 사용 가능합니다.&lt;/li&gt;
&lt;li&gt;@RequestParam은 각각의 파라미터를 직접 받아옵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2. POST + DTO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701877114437&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   function dtoResponse3() {
        var form = document.getElementById('form_dto2');
        axios.post(`/axios/response3`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse3 : ', res.data );
            });
    }
    
    
    function dtoResponse4() {
        var form = document.getElementById('form_dto2');
        axios.post(`/axios/response4`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse4 : ', res.data );
            });
    }
    
    
    function dtoResponse5() {
        var form = document.getElementById('form_dto2');
        axios.post(`/axios/response5`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse5 : ', res.data );
            });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1701877145670&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   // case 1.
   @PostMapping(&quot;/axios/response3&quot;) // error
    @ResponseBody
    public String axiosAPI3(@RequestParam(value = &quot;name&quot;, required = false) String name, @RequestParam(value = &quot;age&quot;, required = false) String age){
        String msg = &quot;이름 : &quot; + name + &quot;\n나이 :&quot; + age;
        return msg;
    }
    
    // case 2.
    @PostMapping(&quot;/axios/response4&quot;) // null
    @ResponseBody
    public String axiosAPI4(UserDTO userDTO){
        String msg = &quot;이름 : &quot; + userDTO.getName() + &quot;\n나이 :&quot; + userDTO.getAge();
        return msg;
    }
    
    // case 3.
    @PostMapping(&quot;/axios/response5&quot;) // 정상
    @ResponseBody
    public String axiosAPI5(@RequestBody UserDTO userDTO){
        String msg = &quot;이름 : &quot; + userDTO.getName() + &quot;\n나이 :&quot; + userDTO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;post는 get보다 약간 더 까다롭습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;case1&lt;/b&gt;: @RequestParam은 주로 URL의 쿼리 파라미터를 받아오는 데 사용되므로, POST 요청의 본문에 담긴 데이터는 읽을 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;case2:&lt;/b&gt; @ModelAttribute&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;는 주로 HTML 폼 데이터를 받아오는 데 사용되지만, JSON 형식의 데이터를 처리하기 어렵습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;b&gt;case3&lt;/b&gt;: @RequestBody&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;는 POST 요청의 본문(body)에 담긴 데이터를 읽어와 객체로 변환합니다.&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt; &lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;JSON 형식의 데이터를 처리할 때 주로 사용되며, 이 경우에는 &lt;/span&gt;axios.post&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt; 메소드로 JSON 데이터를 전송하고, 서버에서 &lt;/span&gt;@RequestBody&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;로 받아 처리합니다&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;b&gt;결론:&lt;/b&gt; &lt;b&gt;POST + DTO에는 @RequestBody를 사용하여 데이트를 받아와야한다!!!!!!!!!!!!!&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;3. GET + VO&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701877339205&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   function voResponse1() {
        var form = document.getElementById('form_vo1');
        axios.get(`/axios/vo/response1?name=${form.name.value}&amp;amp;age=${form.age.value}`)
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'dtoResponse1 : ', res.data );
            });
    }
    
    
    function voResponse2() {
        var form = document.getElementById('form_vo1');
        axios.get(`/axios/vo/response2?name=${form.name.value}&amp;amp;age=${form.age.value}`)
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'voResponse2 : ', res.data );
            });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1701877361638&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // case 1.
    @GetMapping(&quot;/axios/vo/response1&quot;)
    @ResponseBody
    public String axiosVOAPI1(@RequestParam(value = &quot;name&quot;) String name, @RequestParam(value = &quot;age&quot;) String age){
        String msg = &quot;이름 : &quot; + name + &quot;\n나이 :&quot; + age;
        return msg;
    }
    
    // case 2.
    @GetMapping(&quot;/axios/vo/response2&quot;)
    @ResponseBody
    public String axiosVOAPI2(UserVo userVO){
        String msg = &quot;이름 : &quot; + userVO.getName() + &quot;\n나이 :&quot; + userVO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보이는 두가지의 경우 전부 잘 되고 가능합니다.&lt;/li&gt;
&lt;li&gt;@RequestParam으로 받아올 수도 있고 @ModelAttribute에서 UserVo에 mapping하여 받아오기도 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4. POST + VO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701877539942&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   function voResponse3() {
        var form = document.getElementById('form_vo2');
        axios.post(`/axios/vo/response3`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'voResponse3 : ', res.data );
            });
    }
    
    
    function voResponse4() {
        var form = document.getElementById('form_vo2');
        axios.post(`/axios/vo/response4`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'voResponse4 : ', res.data );
            });
    }
    
    
    function voResponse5() {
        var form = document.getElementById('form_vo2');
        axios.post(`/axios/vo/response5`, {name: form.name.value, age: form.age.value})
            .then((res)=&amp;gt;{
                console.log( res );
                console.log( 'voResponse5 : ', res.data  );
            });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1701877556004&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // case 1.
    @PostMapping(&quot;/axios/vo/response3&quot;)
    @ResponseBody
    public String axiosVOAPI3(
    			@RequestParam(value = &quot;name&quot;, required = false) String name, 
                @RequestParam(value = &quot;age&quot;, required = false) String age){
        String msg = &quot;이름 : &quot; + name + &quot;\n나이 :&quot; + age;
        return msg;
    }
    
    // case 2.
    @PostMapping(&quot;/axios/vo/response4&quot;)
    @ResponseBody
    public String axiosVOAPI4(UserVo userVO){
        String msg = &quot;이름 : &quot; + userVO.getName() + &quot;\n나이 :&quot; + userVO.getAge();
        return msg;
    }
    
    // case 3.
    @PostMapping(&quot;/axios/vo/response5&quot;)
    @ResponseBody
    public String axiosVOAPI5(@RequestBody UserVo userVO){
        String msg = &quot;이름 : &quot; + userVO.getName() + &quot;\n나이 :&quot; + userVO.getAge();
        return msg;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;case1:&lt;/b&gt; @RequestParam을 사용하여 POST 요청의 본문(body)에서 데이터를 읽어오는 방식입니다. 하지만 이 방식은 일반적으로 HTML 폼 데이터를 처리할 때 사용되므로, JSON 형식의 데이터를 처리하기 어렵습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;case2:&lt;/b&gt; UserVo 클래스를 사용하여 객체로 바로 매핑하는 방식입니다. 하지만 @ModelAttribute는 JSON 형식의 데이터를 처리하기 어렵습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;case3:&lt;/b&gt; @RequestBody를 사용하여 JSON 형식의 데이터를 읽어오는 방식입니다. Axios에서 POST 요청을 보낼 때 JSON 형식의 데이터를 본문에 담아 전송하고, 서버에서는 @RequestBody를 통해 해당 데이터를 UserVo 객체로 변환하여 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결론: POST+ VO에서는 (폼 데이터가 아니라면) RequestBody로 보낸다!!!!!!!!!!!!!&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/85</guid>
      <comments>https://jihyungk.tistory.com/85#entry85comment</comments>
      <pubDate>Thu, 7 Dec 2023 01:02:43 +0900</pubDate>
    </item>
    <item>
      <title>[SeSSAC] 웹 풀스택 영등포 5기 과정_Java(Class)</title>
      <link>https://jihyungk.tistory.com/84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바 강국이라고 불리는 한국에서 개발자로서 취업을 하고자 한다면,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바를 빼놓을 수 없죠!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 자바를 배우게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기초적인 문법을 배웠고, 아직 기초적인 문법을 진행 중이지만 수업 포인트 위주로 정리하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 start!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;0.클래스와 객체, 인스턴스&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클래스:&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 사용자가 정의하는 자료형이자, 객체를 만들기 위한 하나의 &quot;틀&quot;이라고 저는 기억에 저장이 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;객체:&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스로 부터 생성된 무언가(?)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인스턴스:&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 메모리 할당이 되어 저장된 것(new 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 메소드의 접근 제어자(Access Modifier)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 클래스를 저장하는 묶음을 &lt;b&gt;패키지(package)&lt;/b&gt;라고 하는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패키지와 클래스의 저장 구조를 통해 외부에서 클래스의 접근을 보호할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3zko/btsASHds2Wk/NlusY73SVv23uGVMZD9kMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3zko/btsASHds2Wk/NlusY73SVv23uGVMZD9kMK/img.png&quot; data-alt=&quot;자바 접근 제어자 범위 표&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3zko/btsASHds2Wk/NlusY73SVv23uGVMZD9kMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3zko%2FbtsASHds2Wk%2FNlusY73SVv23uGVMZD9kMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;233&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;자바 접근 제어자 범위 표&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. Static&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적변수는 클래스가 선되는 순간에 Method Area라는 어떤 영역에 메모리 할당을 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여 정적변수가 불필요한 상황에서도 프로그램이 종료가 될 때까지 가비지 컬렉터로도 회수가 되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(non-static 변수는 메모리 중 heap에 할당이 됩니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도, static을 사용하는 이유는, 중복되는 변수 및 메소드의 선언을 줄일 수 있어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 사용한다면&lt;b&gt; 가독성도 좋아지고, 전체적인 메모리 효율성도 증대되기 때문&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1700901118383&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Constants {
    public static final double PI = 3.14159;
    public static final int MAX_VALUE = 100;

    public static void main(String[] args) {
        System.out.println(&quot;The value of PI: &quot; + Constants.PI);
        System.out.println(&quot;Maximum allowed value: &quot; + Constants.MAX_VALUE);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static이라는 변수 두개를 만들면, 이 정적변수는 객체가 아닌 클래스에 종속되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 클래스명 + dot 연산자 +&amp;nbsp; static 변수명 ]&lt;/b&gt; 으로 바로 접근이 가능하며,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 값이 바뀐다면 바뀐 값을 전체적으로 공유할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3. final&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static은 전역적으로 공용하는 변수 느낌이라면, 이번엔 &lt;b&gt;변수의 값 변경을 금지하는 필드&lt;/b&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;final은 값 변경을 막고 오로지 읽기만 허용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 static + final 을 같이 선언하게 된다면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 할당을 하여 공용적으로 쓸 수 있으나 값을 변경할 순 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최초의 한 번 초기화된 값 이후로 값을 바꿀 수 없죠!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 메소드 오버라이딩와 메소드 오버로딩&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개념은 저도,,,, 둘의 개념은 알겠는데, 이름이 너무 헷갈렸던 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;*메소드 오버라이딩&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: &lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt;상위 클래스에서 이미 정의된 메소드를 하위 클래스에서 동일한 시그니처로 다시 정의하는 것&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700901601268&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Animal {
    void makeSound() {
        System.out.println(&quot;동물 소리&quot;);
    }
}

class Dog extends Animal {
    // 메소드 오버라이딩
    @Override
    void makeSound() {
        System.out.println(&quot;왈왈!&quot;);
    }
}

class Cat extends Animal {
    // 메소드 오버라이딩
    @Override
    void makeSound() {
        System.out.println(&quot;야옹~&quot;);
    }
}

public class AnimalTest {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();

        dog.makeSound(); // 왈왈! 출력
        cat.makeSound(); // 야옹~ 출력
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;* 메소드 오버로딩&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0f0f0f; text-align: start;&quot;&gt; 동일한 메소드 이름을 가진 여러 메소드를 정의하는 것&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700901751839&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public double add(double a, double b) {
        return a + b;
    }

    public String concatenate(String str1, String str2) {
        return str1 + str2;
    }

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        
        int sumInt = calculator.add(3, 4);
        System.out.println(&quot;Sum of integers: &quot; + sumInt);

        double sumDouble = calculator.add(2.5, 3.7);
        System.out.println(&quot;Sum of doubles: &quot; + sumDouble);

        String result = calculator.concatenate(&quot;Hello, &quot;, &quot;World!&quot;);
        System.out.println(&quot;Concatenated String: &quot; + result);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/84</guid>
      <comments>https://jihyungk.tistory.com/84#entry84comment</comments>
      <pubDate>Sat, 25 Nov 2023 17:46:39 +0900</pubDate>
    </item>
    <item>
      <title>[SeSSAC] 웹 풀스택 영등포 5기 과정_socket</title>
      <link>https://jihyungk.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로젝트가 끝남과 동시에 또 수업을 시작하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숨 돌릴 틈이 진짜 없는 느낌 ㅠㅡㅠ,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 소켓에 대해 배웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;0. 소켓(socket)이란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹소켓은 HTTP와 달리 &lt;b&gt;양방향 실시간 데이터 소통&lt;/b&gt;을 하기 위해 생겨난 기술입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP의 위에서 동작하는 HTTP와 달리 조금 더 밑에서 동작한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소켓은 떨어져 있는 두 호스트를 연결해 주는 도구로써 인터페이스 역할을 한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소켓을 통해 데이터를 주고 받는 것은 양방향 데이터 통신 채널을 만드는 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 소켓 통신 흐름도&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c50rGG/btsAuvKFJlp/4Vejykw8cEKPU7e6gbGQw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c50rGG/btsAuvKFJlp/4Vejykw8cEKPU7e6gbGQw1/img.png&quot; data-alt=&quot;소켓 통신의 흐름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c50rGG/btsAuvKFJlp/4Vejykw8cEKPU7e6gbGQw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc50rGG%2FbtsAuvKFJlp%2F4Vejykw8cEKPU7e6gbGQw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;786&quot; height=&quot;542&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;소켓 통신의 흐름&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하기의 블로그에 꽤나 쉽고 자세하게 나와있어서 읽어보시는 것을 추천드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://helloworld-88.tistory.com/215&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://helloworld-88.tistory.com/215&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1700150737243&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[기본] 소켓(SOCKET)통신 이란?&quot; data-og-description=&quot;소켓통신 소켓(SOCKET)이란?소켓(Socket)은 프로세스가 드넓은 네트워크 세계로 데이터를 내보내거나 혹은 그 세계로부터 데이터를 받기 위한 실제적인 창구 역할을 한다. 그러므로 프로세스가 데&quot; data-og-host=&quot;helloworld-88.tistory.com&quot; data-og-source-url=&quot;https://helloworld-88.tistory.com/215&quot; data-og-url=&quot;https://helloworld-88.tistory.com/215&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/l3qh6/hyUu1c51Yl/ZY1GemkrlP6OoKyzLYBVek/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/PbIV9/hyUyxnRoor/Xq2vqGR0OhODuW6wh08IGk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAB296/hyUyoxF2dE/yH5iX2chF8XiZ2Cn8sYfmk/img.jpg?width=790&amp;amp;height=605&amp;amp;face=0_0_790_605&quot;&gt;&lt;a href=&quot;https://helloworld-88.tistory.com/215&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://helloworld-88.tistory.com/215&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/l3qh6/hyUu1c51Yl/ZY1GemkrlP6OoKyzLYBVek/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/PbIV9/hyUyxnRoor/Xq2vqGR0OhODuW6wh08IGk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAB296/hyUyoxF2dE/yH5iX2chF8XiZ2Cn8sYfmk/img.jpg?width=790&amp;amp;height=605&amp;amp;face=0_0_790_605');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[기본] 소켓(SOCKET)통신 이란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소켓통신 소켓(SOCKET)이란?소켓(Socket)은 프로세스가 드넓은 네트워크 세계로 데이터를 내보내거나 혹은 그 세계로부터 데이터를 받기 위한 실제적인 창구 역할을 한다. 그러므로 프로세스가 데&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;helloworld-88.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. web socket&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 소켓 (줄여서 ws라고 부르는 듯) 은 앞서 알아본 소켓과는 다른 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 그거나 그거나인 줄 알았는데 아니더라고요,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소켓&lt;/b&gt;은 앞서 알아보았듯이 어떠한 두 개의 호스트를 연결하고 데이터를 주고받는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;네트워크 프로그래밍의 일반적인 용어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;웹 소켓&lt;/b&gt;은 &lt;b&gt;HTML5에서 도입된 웹의 표준 기술&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저와 웹 서버가 실시간 양방향 통신 (핸드셰이크)를 통신 위한 특별한 프로토콜이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠르게 작동하고, 통신할 때 아주 적은 데이터를 이용하는 것이 장점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;- 웹 소캣 이벤트&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 소켓의 이벤트가 4가지 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-1. OPEN&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700151378909&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.addEventListener('open', function (event) {
  console.log('웹 소켓이 열렸습니다.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 웹 소켓 서버에 성공적으로 연결되어 열렸을 때 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-2. MESSAGE&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700151440912&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.addEventListener('message', function (event) {
  console.log('서버에서 메시지 수신:', event.data);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 클라이언트로 메시지를 보낼 때 발생하는 이벤트입니다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-3. ERROR&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700151498866&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.addEventListener('error', function (event) {
  console.error('웹 소켓 오류 발생:', event);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 소켓 연결 중 오류가 있을 대 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-4. CLOSE&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700151553235&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.addEventListener('close', function (event) {
  console.log('웹 소켓이 닫혔습니다.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 소켓 연결이 종료되었을 때 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에, 웹 소켓 서버에서도 웹 소켓과 연결해서 이벤트를 처리해야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 아무런 준비 없이 웹 소켓을 실행할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서&lt;b&gt; WS라는 모듈을 설치&lt;/b&gt;해서 클라이언트와 웹 소켓으로 주고받을 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1700151718499&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install ws&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이벤트를 등록하고 처리하는 함수인 &lt;b&gt;on&lt;/b&gt;을 통해 클라이언트와 소켓을 연결할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1700151757568&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const ws = require('ws');

const server = app.listen(PORT, () =&amp;gt; {
    console.log(`http://localhost:${PORT}`);
})

const wsServer = new ws.Server({server}); // 웹 소켓 서버 접속

const sockets= []; // 빈 배열

//  on : 이벤트 등록 함수
wsServer.on('connection', (socket) =&amp;gt; {
    sockets.push(socket); // 배열에 접속한 클라이언트 객체 추가

    // 클라이언트 메세지 수신
    socket.on('message', (message) =&amp;gt; {
      console.log(`클라이언트로 부터 받은 메세지 :: ${message}`);

      // 웹 소켓 서버에 접속한 모든 클라이언트(브라우저 탭)에게 메세지 전송
      // = 브로드캐스팅(여러 컴퓨터한테 데이터 전송)
        sockets.forEach((socket) =&amp;gt; {
          socket.send(`${message}`);        
        });
    });

    socket.on('close', () =&amp;gt; {
      console.log('[클라이언트 연결 종료]')
    })
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. socket.io&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;socket.io는 자바스크립트의 라이브러리로 기본적으로 웹 소켓을 위해 구축되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 같은 개발자가 웹 소켓을 좀 더 쉽고 간편하게 쓰도록 도와주는 라이브러리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에도 웹 소켓과 같은 기본 이벤트가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-1. CONNECTION&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700152084481&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;io.on('connection', function (socket) {
  console.log('새로운 클라이언트가 연결되었습니다.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 서버에 연결되었을 때 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-2. DISCONNECT&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700152127344&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.on('disconnect', function () {
  console.log('클라이언트가 연결을 종료했습니다.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 소켓에 대한 연결을 해제했을 때 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-3. ERROR&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700152202679&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.on('error', function (error) {
  console.error('에러 발생:', error);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 중 오류가 발생했을 때 발생하는 이벤트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-4. CUSTOM&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700152247247&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버에서 사용자 정의 이벤트 발생
socket.emit('customEvent', { message: '사용자 정의 이벤트 발생' });

// 클라이언트에서 사용자 정의 이벤트 수신
socket.on('customEvent', function (data) {
  console.log('사용자 정의 이벤트 수신:', data.message);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 원하는 이벤트 이름으로 설정하고 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 헷갈렸던 건데,&lt;b&gt; emit이 보내는 쪽&lt;/b&gt;이고 &lt;b&gt;on이 받는 쪽&lt;/b&gt;입니다!!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 이러한 내용을 바탕으로 간단한 단체 채팅방을 구현했었는데요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 카카오톡처럼&lt;b&gt; 단체 채팅&lt;/b&gt;에서&lt;b&gt; 입장과 퇴장&lt;/b&gt;을 나타내는 소켓을 구현해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wVnff/btsAuuyABMl/ojnk3hgugQEOh674WudX60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wVnff/btsAuuyABMl/ojnk3hgugQEOh674WudX60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wVnff/btsAuuyABMl/ojnk3hgugQEOh674WudX60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwVnff%2FbtsAuuyABMl%2Fojnk3hgugQEOh674WudX60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;269&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;1543&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czHYmh/btsAxHp9G6b/Ks6zmWU4kiMdZKiBjI0IH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czHYmh/btsAxHp9G6b/Ks6zmWU4kiMdZKiBjI0IH0/img.png&quot; data-alt=&quot;입장 후&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czHYmh/btsAxHp9G6b/Ks6zmWU4kiMdZKiBjI0IH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczHYmh%2FbtsAxHp9G6b%2FKs6zmWU4kiMdZKiBjI0IH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1519&quot; height=&quot;1543&quot; data-origin-width=&quot;1519&quot; data-origin-height=&quot;1543&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;입장 후&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;client 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700194797443&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 입장할 때 !!
    &amp;lt;div class=&quot;entry-box&quot;&amp;gt;
        &amp;lt;input
            type=&quot;text&quot;
            id=&quot;nickname&quot;
            placeholder=&quot;닉네임&quot;
            autofocus
            onkeypress=&quot;if(window.event.keyCode==13){join()}&quot;
            /&amp;gt;
        &amp;lt;button type=&quot;button&quot; onclick=&quot;join();&quot;&amp;gt;입장&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;
    
    &amp;lt;script&amp;gt;
    // 채팅방 입장 시 setNick을 통해 닉네임을 서버측에 보냄 (닉네임 중복 검사를 위해)
        function join() {
                socket.emit('setNick', document.querySelector('#nickname').value); }
        
        socket.on('notice', (msg) =&amp;gt; {
            document.querySelector('.chat-list').insertAdjacentHTML('beforeend', 
            `&amp;lt;div style=&quot;justify-items: center; text-align: center; text-color: gray; font-size: 10px;&quot;&amp;gt;${msg}&amp;lt;/div&amp;gt;`)
        });
    &amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 입장 창을 거쳐 join 함수를 통해 서버 소켓으로&lt;b&gt; 'setNick'이라는 커스텀이벤트&lt;/b&gt;로 전달하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;server 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700193944605&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; socket.on('setNick', (nick) =&amp;gt; {
        console.log(`닉네임 설정 완료 :: ${nick}님 입장`);
        console.log('접속 유저 목록 :: ', nickArray);
        
        // 프론트에서 입력한 nick이 nickObs 객체에 존재하는지 검사
        // 이미 존재: error 이벤트 + '이미 존재하는 닉네임 입니다'
        // 새 닉네임: notice 이벤트 + '00님이 입장하셨습니다.'
        if (Object.values(nickArray).indexOf(nick) &amp;gt; -1 ) {
            socket.emit('error', `이미 존재하는 닉네임입니다.`);
        } else {
            // 새로운 닉네임
            nickArray[socket.id] = nick;
            socket.emit('entrySuccess', nick); // 해당 소켓 데이터 전송
            io.emit('notice', `${nick}님이 입장하셨습니다.`);
            io.emit('updateNicks', nickArray); // 전체 사용자 닉네임 모음 객체 전달
            updateList();
        }
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server에서는 &lt;b&gt;setNick&lt;/b&gt;을 받고 있고 콜백함수로 nick을 받아서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 존재하는 닉네임인지 확인하고, 만약 새로운 닉네임이라면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입장해서 &lt;b&gt;'notice'라는 커스텀 이벤트&lt;/b&gt;로 메시지와 함께 클라이언트로 보내고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;client 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700197008613&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.on('notice', (msg) =&amp;gt; {
    document.querySelector('.chat-list').insertAdjacentHTML('beforeend', 
    `&amp;lt;div 
    	style=&quot;justify-items: center; text-align: center; 
        text-color: gray; font-size: 10px;&quot;&amp;gt;
        	${msg}
     &amp;lt;/div&amp;gt;`)
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 socket.on의 &lt;b&gt;'notice'&lt;/b&gt;를 통해서 chat-list에 div를 삽입해서&lt;b&gt; '${nick}님이 입장하셨습니다.'&lt;/b&gt;라는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문구가 사용자에게 보이게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;퇴장&lt;/b&gt;도 마찬가지로 client 측의 notice를 이용하여 msg만 바꿔서 이용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 custom 이벤트가 아니라 socket.io의 기본 이벤트인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;disconnect 이벤트를 사용해서 퇴장을 공지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;server 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700197186159&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    socket.on('disconnect', () =&amp;gt; {
        console.log(`접속 끊김 :: ${socket.id}`);
        io.emit('notice', `${nickArray[socket.id]}님이 퇴장하셨습니다.`);
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 메시지 기능을 어떻게 구현할 수 있는지 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 html에서 &lt;b&gt;my msg&lt;/b&gt;라는 부분과 &lt;b&gt;other msg&lt;/b&gt;라는 부분이 나눠져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;my msg는 내가 보내서 채팅이 오른쪽에 있고, other msg는 남이 보낸 메시지로 채팅이 왼쪽에 위치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJZIcf/btsAuRf8NZu/1isngqigS2TQx8qzdhOOF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJZIcf/btsAuRf8NZu/1isngqigS2TQx8qzdhOOF1/img.png&quot; data-alt=&quot;채팅방 구현&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJZIcf/btsAuRf8NZu/1isngqigS2TQx8qzdhOOF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJZIcf%2FbtsAuRf8NZu%2F1isngqigS2TQx8qzdhOOF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1516&quot; height=&quot;750&quot; data-origin-width=&quot;1516&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;채팅방 구현&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;client 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700197689844&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        function send() {
            socket.emit('send', {
                nick: myNick, 
                msg: document.querySelector('.input-msg').value});
            document.querySelector('.input-msg').value = '';
        }

    
    socket.on('sendMsg', (data) =&amp;gt; {
            if (data.nick === myNick){
                document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
                    `&amp;lt;div class=&quot;my-chat&quot;&amp;gt;
                    &amp;lt;div class=&quot;my-chat-msg&quot;&amp;gt;${data.msg}&amp;lt;/div&amp;gt;
                    &amp;lt;div class=&quot;my-pic&quot;&amp;gt;${data.nick}&amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;`);
            } else {
                document.querySelector('.chat-list').insertAdjacentHTML('beforeend',
                    `&amp;lt;div class=&quot;other-chat&quot;&amp;gt;
                        &amp;lt;div class=&quot;other-pic&quot;&amp;gt;${data.nick}&amp;lt;/div&amp;gt;
                    &amp;lt;div class=&quot;other-chat-msg&quot;&amp;gt; ${data.msg}&amp;lt;/div&amp;gt;
                    &amp;lt;/div&amp;gt;`);
            }
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chat-list라는 div가 있어서, 만약 내 닉네임과 일치한다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;my-chat이라는 div를 추가해서 오른쪽에 div를 생성해서 붙이는 방식을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 만약 내 닉네임과 일치하지 않는다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;other-chat이라는 div를 추가해서 왼쪽에 생성하여 붙이는 방식을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;server 측 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1700197958269&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    socket.on('send', (data) =&amp;gt; {
        io.emit('sendMsg', data);
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 단체메시지 방이고, 개인 DM 기능은 하지 않아서 socket의&lt;b&gt; send로 닉네임과 메시지를&lt;/b&gt; 받은 다음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;io (전체에 소켓을 보냄)으로 emit을 통해 client 측&lt;/b&gt;에 보냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 my 메시지인지 other 메세지인지 판별해서 메세지가 잘 뜨고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메세지 도중에 입장하거나 퇴장한 사람이 있다면 계속 div를 붙이는 방식이기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 나오게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2338&quot; data-origin-height=&quot;1185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bobSCA/btsAs8vYU3m/lX7ZJtvVf2sES8RTucyGZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bobSCA/btsAs8vYU3m/lX7ZJtvVf2sES8RTucyGZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bobSCA/btsAs8vYU3m/lX7ZJtvVf2sES8RTucyGZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbobSCA%2FbtsAs8vYU3m%2FlX7ZJtvVf2sES8RTucyGZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2338&quot; height=&quot;1185&quot; data-origin-width=&quot;2338&quot; data-origin-height=&quot;1185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 귓속말 기능도 넣고, css 도 디벨롭 해 볼 예정입니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/83</guid>
      <comments>https://jihyungk.tistory.com/83#entry83comment</comments>
      <pubDate>Fri, 17 Nov 2023 14:22:49 +0900</pubDate>
    </item>
    <item>
      <title>SeSSAC 웹 풀스텍 과정 회고록[SeSSAC] 웹 풀스택 영등포 5기 과정_2차 프로젝트 회고록</title>
      <link>https://jihyungk.tistory.com/82</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;전 과정 중 2차 프로젝트가 끝이 났습니다!! 룰루 ˞♡ฅ(ᐤ꒳ᐤฅ)&amp;nbsp;&amp;lsaquo;3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서 저는 &lt;b&gt;[ 프론트 개발, 팀장 ]을&lt;/b&gt; 맡았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트가 1차보다 조금 더 길어서 그런지 조금,,,,,,,더,,,,,,,,,,,기가 빨린 느낌,,,,,,,,,,,,,,,,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 디벨롭하는 현재까지도 잘 진행이 되고 있어 마무리가 괜찮은 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;발표할 때 웹 배포가 제대로 안되가지고,,,,얼마나 좌절했는지,, 다들 양해해 주셔서 감사해요&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sHOg1/btsAcSUupkE/hjZSIycJR9FP5c9VoaFW50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sHOg1/btsAcSUupkE/hjZSIycJR9FP5c9VoaFW50/img.png&quot; data-alt=&quot;나의 미친 깃 컨트리뷰터&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sHOg1/btsAcSUupkE/hjZSIycJR9FP5c9VoaFW50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsHOg1%2FbtsAcSUupkE%2FhjZSIycJR9FP5c9VoaFW50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;288&quot; data-origin-width=&quot;463&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나의 미친 깃 컨트리뷰터&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예 제가 이번 플젝에서 난생 처음 프론트를 하면서 3만에 육박하는 코드를 작성하였어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 제 컨트리뷰터 보고 감작 놀랬어요 ㅎ..................&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 폭풍 코딩 하느라 바빠서 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;팀원들을 제대로 못챙긴것같아 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;미안합니다..................&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 프론트는 빡세&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서론은 그만하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 웹사이트를 만들면서, 제가 도전했던 것에 대해 적어보도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. 웹사이트 간단 설명&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 &lt;b&gt;[ Wait Mate ]&lt;/b&gt;라는 &lt;u&gt;웨이팅 구인 구직 플랫폼&lt;/u&gt;을 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서&lt;b&gt; 돈을 지불하고 웨이팅을 부탁할 사람(별칭: &lt;span style=&quot;color: #1b711d;&quot;&gt;웨이트메이트&lt;span style=&quot;color: #000000;&quot;&gt;)과&lt;/span&gt;,&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;돈을 받고 웨이팅을 해줄 사람(별칭: &lt;span style=&quot;color: #1b711d;&quot;&gt;프록시&lt;span style=&quot;color: #000000;&quot;&gt;)을&lt;/span&gt;&lt;/span&gt;&lt;/b&gt; 구하는 플랫폼을 기획하고 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sd5lu/btsAmGSVfko/rUlc8Ws6RLNF1lg4lyaO7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sd5lu/btsAmGSVfko/rUlc8Ws6RLNF1lg4lyaO7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sd5lu/btsAmGSVfko/rUlc8Ws6RLNF1lg4lyaO7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fsd5lu%2FbtsAmGSVfko%2FrUlc8Ws6RLNF1lg4lyaO7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1638&quot; height=&quot;812&quot; data-origin-width=&quot;1638&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. 디자인적 요소&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 정말 고민을 많이 했는데, 귀여운 캐릭터와 어울리는 웹페이지 테마를 만들고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둥글둥글한 요소를 많이 넣었어요. 색감 팔레트도 최종 발탁된 보라색과 함께 넣었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dn9tRa/btsz94BcwGe/UKEkA3uop6noRrup1Vtm00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dn9tRa/btsz94BcwGe/UKEkA3uop6noRrup1Vtm00/img.png&quot; data-alt=&quot;참고한 색상 및 테마&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dn9tRa/btsz94BcwGe/UKEkA3uop6noRrup1Vtm00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdn9tRa%2Fbtsz94BcwGe%2FUKEkA3uop6noRrup1Vtm00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;180&quot; height=&quot;200&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참고한 색상 및 테마&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 제일 고민하던 메인페이지는 크몽에 맡기고, 그 해당하는 메인페이지 느낌을 살려서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 페이지 디자인을 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고,&amp;nbsp; &lt;b&gt;디자인 및 기획 소통은 figma로 진행하였습니다!!!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난생처음 해보는 figma였는데, ppt와 포토샵의 중간 같아서 재밌었어요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmtLu0/btsz93oO7cR/1ITGIhgQoruMXs4LXdtib1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmtLu0/btsz93oO7cR/1ITGIhgQoruMXs4LXdtib1/img.png&quot; data-alt=&quot;figma 일부 발췌&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmtLu0/btsz93oO7cR/1ITGIhgQoruMXs4LXdtib1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmtLu0%2Fbtsz93oO7cR%2F1ITGIhgQoruMXs4LXdtib1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;808&quot; height=&quot;406&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;figma 일부 발췌&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3. 프론트에 사용한 기술 스택&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vUza4/btsAjhzG67K/CDlkYDYUn5NB2YgSpkKCe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vUza4/btsAjhzG67K/CDlkYDYUn5NB2YgSpkKCe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vUza4/btsAjhzG67K/CDlkYDYUn5NB2YgSpkKCe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvUza4%2FbtsAjhzG67K%2FCDlkYDYUn5NB2YgSpkKCe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;40&quot; height=&quot;35&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 리액트 (React)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 수업시간에 배웠던 리액트를 활용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FnH2M/btsAcTfwfCQ/uZYKThujKzSVtJMKYWKJc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FnH2M/btsAcTfwfCQ/uZYKThujKzSVtJMKYWKJc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FnH2M/btsAcTfwfCQ/uZYKThujKzSVtJMKYWKJc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFnH2M%2FbtsAcTfwfCQ%2FuZYKThujKzSVtJMKYWKJc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;40&quot; height=&quot;24&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 테일윈드 (tailwind)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 따로 만들지 않고, 트렌디하며 저희처럼 간소한 페이지에 제격인 테일윈드를 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XuuRY/btsAc6eDe9E/gk4xp9I0bYDbx2UFrtn9kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XuuRY/btsAc6eDe9E/gk4xp9I0bYDbx2UFrtn9kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XuuRY/btsAc6eDe9E/gk4xp9I0bYDbx2UFrtn9kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXuuRY%2FbtsAc6eDe9E%2Fgk4xp9I0bYDbx2UFrtn9kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;40&quot; height=&quot;30&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Scss&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테일윈드로 보완되지 않는 css를 위해 보조 개념으로 Scss를 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- JavaScript&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 수업시간에 이틀에 걸쳐 TypeScript를 배웠으나, 부족하며 단기간 완성해야 하는 프로젝트에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빠른 코딩이 불가하다고 판단하에 협의하여 TypeScript를 도입하지 않기로 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4. 내가 도전한 것들&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4-1.&amp;nbsp; 반응형에 대한 고민&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 첫 프론트 도전인 만큼, 반응형에 대해 고민이 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 반응형 뒤늦게 하려고 하면 너무 힘들다고 해서 처음부터 반응형을 많이 고려하고 싶었기 때문이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 저희 웹 사이트는 헤더와 사이드바로 구성되어 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l57d9/btsAaVRIFKh/CrKsgNdREhTI5PEn78v78K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l57d9/btsAaVRIFKh/CrKsgNdREhTI5PEn78v78K/img.png&quot; data-alt=&quot;위-헤더 / 왼쪽 - 사이드바&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l57d9/btsAaVRIFKh/CrKsgNdREhTI5PEn78v78K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl57d9%2FbtsAaVRIFKh%2FCrKsgNdREhTI5PEn78v78K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1342&quot; height=&quot;792&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위-헤더 / 왼쪽 - 사이드바&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구성하다 보니 세로로 긴 모바일에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 부분이 가려지고, 옆 방향 스크롤이 생기고, 튕겨 나와서 보이지 않으며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다 사용감이 좋지 않아 고민을 한 결과,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;웹 사이즈에서 보이는 사이드바와 모바일에서 보이는 사이드바 컴포넌트를 따로 작성&lt;/b&gt;하기로 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wcluk/btsAbcMdtyv/cKFwSUEUgVZ0MByU1JKV71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wcluk/btsAbcMdtyv/cKFwSUEUgVZ0MByU1JKV71/img.png&quot; data-alt=&quot;mobile전용 사이드바 적용한 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wcluk/btsAbcMdtyv/cKFwSUEUgVZ0MByU1JKV71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwcluk%2FbtsAbcMdtyv%2FcKFwSUEUgVZ0MByU1JKV71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;825&quot; height=&quot;830&quot; data-origin-width=&quot;825&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;mobile전용 사이드바 적용한 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 웹사이트는 헤더와 사이드바, 풋터가 반복되고, 이를 제외한 나머지 영역의 컴포넌트만 바뀌면 되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Templete이라는 파일&lt;/b&gt;이 있어, 그 안에 컴포넌트를 넣어서 보여주는 방식이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcyx8E/btsz9xXT4ue/ixEFDYdApC3ly3N66nBfWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcyx8E/btsz9xXT4ue/ixEFDYdApC3ly3N66nBfWk/img.png&quot; data-alt=&quot;Templete.js 내부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcyx8E/btsz9xXT4ue/ixEFDYdApC3ly3N66nBfWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdcyx8E%2Fbtsz9xXT4ue%2FixEFDYdApC3ly3N66nBfWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;861&quot; height=&quot;512&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Templete.js 내부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 사이드 바를 보여줄 때&lt;b&gt; Mobile크기&lt;/b&gt;라면 (700px 이하라면)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MobileSidebar 컴포넌트&lt;/b&gt;가 보이고, &lt;b&gt;웹 크기&lt;/b&gt;라면 (700px 이상이라면) 그냥 &lt;b&gt;Sidebar 컴포넌트&lt;/b&gt;가 보이게 되는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 왼쪽에 구성되어 있던 사이드바를 모바일에선 위로 올려, 모바일에서도 예쁜 모양을 유지할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 이 사이드바뿐만 아니라 다른 페이지 들도 반응형을 위해 노력했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반응형에 대처하는 방법은 여러 가지가 있지만,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 컴포넌트마다 &lt;b&gt;700px이하 이었는지 아닌지 상태를 관리하는 변수를 넣어서 실시간으로 감지&lt;/b&gt;하도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU8naK/btsAkiYpZgO/FTmqDvLB5weVkvuU6uHoK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU8naK/btsAkiYpZgO/FTmqDvLB5weVkvuU6uHoK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU8naK/btsAkiYpZgO/FTmqDvLB5weVkvuU6uHoK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU8naK%2FbtsAkiYpZgO%2FFTmqDvLB5weVkvuU6uHoK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;898&quot; height=&quot;301&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여, 아래에선 이 변수를 삼항연산자로 이용해 flex 방향을 바꾸기도 하고, Text 크기도 바꾸기도 하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;142&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9zZgO/btsAaWXr71g/KkDKHre8NV1T2wGuTukg61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9zZgO/btsAaWXr71g/KkDKHre8NV1T2wGuTukg61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9zZgO/btsAaWXr71g/KkDKHre8NV1T2wGuTukg61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9zZgO%2FbtsAaWXr71g%2FKkDKHre8NV1T2wGuTukg61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;142&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 삼항연산자로 사용하니, 테일윈드의 장점도 부각되고 단점도 부각되어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 조금 더 가독성이 좋은 방법을 물색하는 것이 목표입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4-2. KAKAO 우편번호 API 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 사이트는 유저가 &lt;b&gt;웨이팅 장소를 등록&lt;/b&gt;하고,&lt;b&gt; 이 장소를 map에 띄워주는 서비스&lt;/b&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한국 지리에도 잘 맞고, 유저가 등록한 우편번호를 좌표로 변경하여 map에 띄워줄 수 있다는 점에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;KAKAO API를 적극 활용&lt;/b&gt;하기로 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GLkZ2/btsAkjbXAUe/1eokzAG6z2fW0yddvVBZ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GLkZ2/btsAkjbXAUe/1eokzAG6z2fW0yddvVBZ31/img.png&quot; data-alt=&quot;register의 주소 검색 항목&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GLkZ2/btsAkjbXAUe/1eokzAG6z2fW0yddvVBZ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGLkZ2%2FbtsAkjbXAUe%2F1eokzAG6z2fW0yddvVBZ31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;476&quot; height=&quot;655&quot; data-origin-width=&quot;476&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;register의 주소 검색 항목&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 우편번호&amp;nbsp; API를 이용해서 주소 검색을 띄우는 것은 어렵지 않았으나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 사용자가 검색을 완료해서 적용하는 부분이 어려웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까, 사용자가 주소 검색을 완료한 후에 저 form의 주소 필드에 그 값을 넣는 것이 어려웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 값이 form의 input 태그에 열심히 넣어줘도 정작 form 내 data에는 그 input값이 먹지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;우편주소의 api와 react-hook-form의 Controller가 컴플릭트가 난다&lt;/b&gt;고 판단하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모달을 띄우는 &lt;b&gt;컴포넌트를 따로 분리&lt;/b&gt;하여 해결하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D5ORS/btsAklAQGEs/hxcXKE9sE65uQAywfNqSg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D5ORS/btsAklAQGEs/hxcXKE9sE65uQAywfNqSg1/img.png&quot; data-alt=&quot;AddressSearchModal로 컴포넌트 분리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D5ORS/btsAklAQGEs/hxcXKE9sE65uQAywfNqSg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD5ORS%2FbtsAklAQGEs%2FhxcXKE9sE65uQAywfNqSg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;177&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AddressSearchModal로 컴포넌트 분리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인을 아주 정확히 찾지는 못하겠으나, 놀랍게도 컴포넌트를 분리하여 처리 과정을 따로 만들고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세터 함수를 프롭으로 넘겨주어 세팅하니 잘 작동이 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 address 정보를 map에 띄우기 위하여 좌표를 가져와야 했는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안타깝게 이 우편주소 API으 기본 기능에 해당 주소의 좌표는 없었습니다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 인터넷을 뒤졌지만, 생각보다 자료가 없고 찾아도 잘 먹히지 않아서 공식문서를 샅샅이 뒤졌습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbXIf0/btsz9xwP3XO/D1lSjU0kS0gBdHIg9IGR61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbXIf0/btsz9xwP3XO/D1lSjU0kS0gBdHIg9IGR61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbXIf0/btsz9xwP3XO/D1lSjU0kS0gBdHIg9IGR61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbXIf0%2Fbtsz9xwP3XO%2FD1lSjU0kS0gBdHIg9IGR61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;897&quot; height=&quot;758&quot; data-origin-width=&quot;897&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 config를 통해&lt;b&gt; headers에 인증키와 Content-Type&lt;/b&gt;을 공식 문서에 나와있는 대로 넣었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 여기서 이 apiKey는 KAKAO DEVELOPER에서 발급받은 제 &lt;b&gt;&lt;i&gt;REST API KEY&lt;/i&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(다른 키 아니고 무조건 REST API KEY)이어야 합니다...... 다시 말합니다 무조건 REST API KEY)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakao.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1699883511322&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Kakao Developers&quot; data-og-description=&quot;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&quot; data-og-host=&quot;developers.kakao.com&quot; data-og-source-url=&quot;https://developers.kakao.com/&quot; data-og-url=&quot;https://developers.kakao.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fkE7m/hyUuTk4UMb/s0IMA3as3mBA76CAwqs9tK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/ddjOc3/hyUuWB6DBh/8LzYmx5KQOD4RX638G5ic1/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/g49OW/hyUu2CiQYt/kwfUOWTaSJk8ojLsivXAN1/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakao.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fkE7m/hyUuTk4UMb/s0IMA3as3mBA76CAwqs9tK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/ddjOc3/hyUuWB6DBh/8LzYmx5KQOD4RX638G5ic1/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000,https://scrap.kakaocdn.net/dn/g49OW/hyUu2CiQYt/kwfUOWTaSJk8ojLsivXAN1/img.png?width=3840&amp;amp;height=1000&amp;amp;face=0_0_3840_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kakao Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakao.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 이 url을 세팅하여 axios 요청을 날리면 result에 데이터를 받아서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 공식문서에 있는 대로 &lt;b&gt;result.data.documents[0]에 각각의 x와 y 좌표&lt;/b&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 x와 y변수에 해당하는 좌표값을 넣어주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 간단하면서 시간도 많이 들였고, 공식 문서의 위대함을 알 수 있었던 부분이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;(워낙 바닥이라 성장할 일 밖에 없지만 성장한 듯,,,)&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4-3. 사용자 경험을 위한 쿠키 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 사실 지난번에는 백을 담당했었기 때문에, 프론트의 기본인 쿠키와 세션 사용을 몰라서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언젠가는 해야겠는데, 사용자 입장에서 쿠키가 필요하면서 보안에 노출되어도 걱정 없는 파트가 무엇일까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각을 했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 웹사이트는 &lt;b&gt;지역기반&lt;/b&gt;인 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐 예를 들어, 웨이팅 장소뿐만 아니라 웨이팅을 대신해줄 사람(프록시)를 찾는 것도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 &lt;b&gt;시군구 단위의 지역을 기반&lt;/b&gt;으로 찾을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SvKRJ/btsAaHZ1LHD/OhRoCnnCEKiWqHKvkrStvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SvKRJ/btsAaHZ1LHD/OhRoCnnCEKiWqHKvkrStvk/img.png&quot; data-alt=&quot;서울시 관악구를 검색한 프록시 list 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SvKRJ/btsAaHZ1LHD/OhRoCnnCEKiWqHKvkrStvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSvKRJ%2FbtsAaHZ1LHD%2FOhRoCnnCEKiWqHKvkrStvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;681&quot; height=&quot;470&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;서울시 관악구를 검색한 프록시 list 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 만약 &lt;b&gt;저 list 중 하나를 눌러 detail 페이지에 갔다가 다시 list로 나오게 된다면&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;검색했던 지역이 사라지고 다시 전체 리스트가 뜨게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 입장에서 분명 검색했던 리스트 그대로 보고 싶을 텐데 저조차도 매우 불편하더라고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;지역 검색 기록을 쿠키로 사용&lt;/b&gt;하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 쿠키를 도입하기 전에 세션과 쿠키를 고민하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 사용자가 창을 닫으면 사라진다는 점에서 세션을 사용해야 할 것 같았는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 작은 메모리지만, 서버와의 연결도 서버의 메모리 사용도 원하지 않고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그저 클라이언트 쪽에서 가볍게 사용하기를 원했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 쿠키를 도입하기로 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 &lt;b&gt;react-cookie npm을 사용&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZAteV/btsAaWbY5Et/OvKLhVrHJaKh2ulIhvrmbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZAteV/btsAaWbY5Et/OvKLhVrHJaKh2ulIhvrmbk/img.png&quot; data-alt=&quot;store 폴더 내 userCookie.js 파일 내부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZAteV/btsAaWbY5Et/OvKLhVrHJaKh2ulIhvrmbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZAteV%2FbtsAaWbY5Et%2FOvKLhVrHJaKh2ulIhvrmbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;321&quot; data-origin-width=&quot;633&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;store 폴더 내 userCookie.js 파일 내부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말씀드렸듯이, 매우 가벼운 쿠키 사용을 원하여, set과 get만 해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC2JH0%2FbtsAjtTsIFg%2FOhCFM3i0KSdMkgAKo72s1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1356&quot; height=&quot;400&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;select 박스의 &lt;b&gt;default value&lt;/b&gt;로 cookies의 address의&amp;nbsp; value의 값이 있다면 찾아서 넣고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애초에 cookies.address 내에 값이 없다면, cookie 내에&lt;b&gt; value가 없어서 에러가 뜨기 때문에&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;find 함수를 사용&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 cities의 리스트 내에서 만약 선택을 해서 onChange를 한다면 선택한 옵션에 따라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setCookies를 통해 address 쿠키 항목에 선택한 address의 value값을&amp;nbsp; 넣어주고 600초 간 유지하도록 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;maxAge 같은 경우 조금 고민을 했지만, 일단 저희의 원활한 테스트를 위해서 600초로 제한하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 진짜로 시중에 배포를 하게 된다면 이 maxAge를 적절한 시간으로 유저 데이터를 통해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제한할 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4-4.&amp;nbsp; react-select npm 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 사용자의 지역 기반 list를 구성할 때 어떻게 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자에게 &lt;b&gt;시군구를 편리하게 제공할지 고민&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 사용한 KAKAO 우편번호 API를 사용하여 유저가 입력하게 할 수 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웨이팅을 부탁할 프록시를 찾는 것도, 내가 앞으로 웨이팅을 할 리스트를 찾는 일도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'시군구 단위'를 통해 선택하여 지정하는 것이 편리하다고 생각&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;select 박스&lt;/b&gt;를 선택하였고 list가 있는 페이지는 cities를 props로 넘겨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J2Uci/btsAbnAwfaq/TtSV4P8Wxyx21KKkzfpXn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J2Uci/btsAbnAwfaq/TtSV4P8Wxyx21KKkzfpXn0/img.png&quot; data-alt=&quot;cities 내 일부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J2Uci/btsAbnAwfaq/TtSV4P8Wxyx21KKkzfpXn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ2Uci%2FbtsAbnAwfaq%2FTtSV4P8Wxyx21KKkzfpXn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;613&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;cities 내 일부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나 초장기 react 내 날 것의 &lt;b&gt;select box는 사용자가 지역을 검색할 수 없었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글링 하며 검색한 결과, react에 select box를 위한 npm이 있다는 것을 알게 되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무엇보다 유저가 select box 내에서 &lt;b&gt;지역을 직접 검색이 가능하다는 편리성을 위해 적용&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MYno8/btsz92DnhL4/thIRkZDKR96tqPxEEH9SH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MYno8/btsz92DnhL4/thIRkZDKR96tqPxEEH9SH0/img.png&quot; data-alt=&quot;select npm 도입하여 검색가능한 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MYno8/btsz92DnhL4/thIRkZDKR96tqPxEEH9SH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMYno8%2Fbtsz92DnhL4%2FthIRkZDKR96tqPxEEH9SH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;271&quot; height=&quot;105&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;select npm 도입하여 검색가능한 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 쿠키를 보여드리며 설명드렸던 그 코드가 &lt;b&gt;react select npm&lt;/b&gt;을 도입한 모습입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC2JH0/btsAjtTsIFg/OhCFM3i0KSdMkgAKo72s1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC2JH0%2FbtsAjtTsIFg%2FOhCFM3i0KSdMkgAKo72s1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1356&quot; height=&quot;400&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 select npm을 도입하는 것은 어렵지 않았지만, 의외로 작업이 좀 오래 걸렸던 것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전국의 시군구 list가 있는 cities를 전면 개조하는 것이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본래, select npm을 도입하기 전에는 label로 '시'와 '도'를 표현하고 그 아래에 군구 단위를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택할 수 있도록 하였으나 select npm은 오로지 &lt;b&gt;label과 value를 일대일 data 매칭&lt;/b&gt;으로 이루어져&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;있어서 저 cities를 싹 다 갈아엎는 작업이 오래 걸렸습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4-5. react-hook-form npm 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 웨이팅을 기다리고 돈을 버는 입장(프록시)이든,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웨이팅을 돈을 내고 부탁하는 입장(웨이트메이트)이든,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자가 정보를 등록해야 하는 구조&lt;/b&gt;를 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여 수업시간에도 배웠던&lt;b&gt; react-hook-form&lt;/b&gt;을 적극 사용하기로 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 wait mate의 register의 경우, 사용자에게 받는 정보가 워낙 많기에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 npm을 도입하지 않을 이유가 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GkG8K/btsAiFUpIoK/0pwyRvJ2s9tw2XNWK8DTk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GkG8K/btsAiFUpIoK/0pwyRvJ2s9tw2XNWK8DTk1/img.png&quot; data-alt=&quot;wait mate의 register form의 일부 Controller&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GkG8K/btsAiFUpIoK/0pwyRvJ2s9tw2XNWK8DTk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGkG8K%2FbtsAiFUpIoK%2F0pwyRvJ2s9tw2XNWK8DTk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;575&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;wait mate의 register form의 일부 Controller&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;react-hook-form&lt;/b&gt;을 통해 많은 옵션도 걸어주고, 유효성 검사와 그 결과에 따른&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지도 다르게 보여줄 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 register를 클릭하지 않아도 무조건 경고문이 뜨는 것을 방지하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폼의 규칙을 반하여 register 버튼을 눌렀을 경우에만 해당하는 경고문들을 띄우도록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;clickReigster라는 옵션을 넣음으로써&lt;/b&gt; 무조건 유저가 폼의 순서대로 입력하지 않아도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경고문이 뜨지 않도록 하였습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(만약 title을 작성하지 않고 다른 항목으로 넘어갈 경우, title을 입력하라고 경고문이 나오게 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 유저의 반감을 살 수 있다고 판단하였습니다. register를 하려고 할 때 고쳐야 할 경우 나와야 하는 것이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UX 상 더욱 좋아 보였습니다)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;5. 트러블 슈팅&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업 과정에서 트러블 슈팅도 있었지만, 개인적으로 고군분투했던 트러블 슈팅 위주로 적어보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;5-1. 배열에서 함수 사용 시 배열이 있는지부터 체크해볼것&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list 페이지 작업하면서 내 나름 트러블이 있었던 구간은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slice 함수가 적용되지 않는다는 빨간 에러가 뜨는 것이었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1Bups/btsAmIXcw1g/JqVPEGatPw9YbCDhZPNtv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1Bups/btsAmIXcw1g/JqVPEGatPw9YbCDhZPNtv0/img.png&quot; data-alt=&quot;바로 이 에러!!!!!!!!!!!!!!!!!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1Bups/btsAmIXcw1g/JqVPEGatPw9YbCDhZPNtv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1Bups%2FbtsAmIXcw1g%2FJqVPEGatPw9YbCDhZPNtv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;926&quot; height=&quot;380&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바로 이 에러!!!!!!!!!!!!!!!!!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 저를 많이 많이 괴롭혔었는데, 아니 대체 잘 설정된 배열 타입에 slice라는 properies가 되지 않는다고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외치느냐 말이야ㅠㅠㅠ 하면서 옵셔널 체이닝도 적용해보고 배열타입이라고 지정도 해줬는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결이 되지 않았다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;=&amp;gt; 해결 방법은, server에서 데이터를 넘겨서 배열에 set해줄 때, 정확한 데이터로 set을 해줘야한다는 것이었다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bccs9e/btsAfAe7ZcB/IpQdLsKfu0bbRWrAschY5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bccs9e/btsAfAe7ZcB/IpQdLsKfu0bbRWrAschY5k/img.png&quot; data-alt=&quot;server에서 데이터를 받는 부분&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bccs9e/btsAfAe7ZcB/IpQdLsKfu0bbRWrAschY5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbccs9e%2FbtsAfAe7ZcB%2FIpQdLsKfu0bbRWrAschY5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;105&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;server에서 데이터를 받는 부분&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 오타가 나거나 구조분해로 가져오지 않는다면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set 함수로 값을 지정해줄 때 제대로 된 배열이 먹히지 않으니 type도 바뀌어버려서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 관련된 메서드가 먹지 않는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;5-2. 폼 데이터 유효성 검사&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 해결을 제대로 못한 트러블 슈팅이긴한데, 너무 충격적이라 남겨본다...ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 type 어쩌고가 절 많이 괴롭혔는데 (이래서 typescript 사용하나봐요,,,,,ㅠㅠ)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9G5G/btsAmBDO2Ec/rIAUcFjBSCKbWrjuXNJcl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9G5G/btsAmBDO2Ec/rIAUcFjBSCKbWrjuXNJcl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9G5G/btsAmBDO2Ec/rIAUcFjBSCKbWrjuXNJcl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9G5G%2FbtsAmBDO2Ec%2FrIAUcFjBSCKbWrjuXNJcl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;947&quot; height=&quot;411&quot; data-origin-width=&quot;947&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이슈가 생긴 폼은 유난히 유저에게 요구하는 정보가 많았던&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웨이팅 메이트 등록 폼인데요, 유저가 정말 폼에 있는 순서 그대로 작성하면 상관이 없지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 API 우편주소 모달을 거친 부분에서 하나라도 뒤틀리게 된다면 바로 에러가 납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다음 API 우편 주소 모달로 컴포넌트가 이동 될 때 자꾸 제 멋대로 register를 진행&lt;/b&gt;하더라구요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(다른 필수값이 채워지지 않은채로 register가 진행됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그래서 form data를 server로 보내는 submit을 하기 전에 유효성을 한번 더 체크해줬어요!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ztHRw/btsAjjEelma/kMF6zUsznkEym2DpBLpLh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ztHRw/btsAjjEelma/kMF6zUsznkEym2DpBLpLh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ztHRw/btsAjjEelma/kMF6zUsznkEym2DpBLpLh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FztHRw%2FbtsAjjEelma%2FkMF6zUsznkEym2DpBLpLh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;667&quot; height=&quot;202&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면 alert가 뜨면서 register를 클릭했던 상태도 false로 바꿔주고 제출도 막아줄 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완전 유하게 UX를 만든 건 아니지만, 그래도 데이터 오류로 폼이 제출 되는 것보다는 한번 alert를 넣으니&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server와의 동작에서는 예외처리를 할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 사용자에게 정보를 받는 폼같은 경우는 버튼을 한번 누른다면 비활성화도 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러번 등록하지 못하도록 하는 예외처리 같은게 중요하다고 느꼈습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;5-3. 로컬 스토리지로 유저 데이터 보관하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 다들 아시겠지만 비동기 언어라서, 때로 저희를 당혹스럽게 만들 때가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 구현한 채팅방의 경우, 사용자의 id값을 확인해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수신자와 발신자가 같은 사람의 채팅방이 생성되는 것을 방지하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 있는 채팅방의 경우에도 굳이 다른 채팅방을 만들 필요가 없다고 판단하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;채팅방이 새로 생성되는 것을 방지하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 로그인한 유저의 정보를 어떻게 관리할 것인지 여기저기 물어보았는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 압도적이라고 할 만한 방법은 없고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 특성에 잘 맞추어 반영을 해야한다는 답변만 들을 뿐이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 저희는 초보라서 어떤 프로젝트에 어떤 특성을 반영하기 보다는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가볍고 사용감이 당장 좋았던 &lt;b&gt;zustand&lt;/b&gt;를 선택하여 사용하였으나,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 zustand는 채팅방을 생성하기 전에 id값을 가져와서 예외처리들을 확인하기에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져오는&lt;b&gt; id값 속도가 굉장히 느린 친구&lt;/b&gt;였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여 뒤늦게라도 리더님의 충고에 따라&lt;b&gt; Local Storage&lt;/b&gt;를 도입하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(세션스토리지랑 고민하였으나, 탭을 닫아도 지속적으로 유지해야하는 채팅창의 속성을 따라서 로컬스토리지로 결정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용법은 굉장히 간단하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vBsn0/btsAq1Del5v/hcl5xQU3qjHLTQLisNXWK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vBsn0/btsAq1Del5v/hcl5xQU3qjHLTQLisNXWK0/img.png&quot; data-alt=&quot;로그인 시 로컬 스토리지에 원하는 값을 키 -값 쌍으로 삽입&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vBsn0/btsAq1Del5v/hcl5xQU3qjHLTQLisNXWK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvBsn0%2FbtsAq1Del5v%2Fhcl5xQU3qjHLTQLisNXWK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;858&quot; height=&quot;232&quot; data-origin-width=&quot;858&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로그인 시 로컬 스토리지에 원하는 값을 키 -값 쌍으로 삽입&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJG9Vy/btsAuLMWIgU/mBVDXtELX8O4FQijK9BfZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJG9Vy/btsAuLMWIgU/mBVDXtELX8O4FQijK9BfZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJG9Vy/btsAuLMWIgU/mBVDXtELX8O4FQijK9BfZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJG9Vy%2FbtsAuLMWIgU%2FmBVDXtELX8O4FQijK9BfZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;267&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 개발자 탭에서 손쉽게 로컬 스토리지의 값을 볼 수 있었습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰과 같은 인증이 아닌 단순 id값이라서 암호화같은 건 도입하지 않았습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 간단한 것을 모르고 사용할 줄 몰랐다니,,,,,,,,,,,,,,, 진작에 도입하지 않아서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼란을 초래한 시간들이 아깝습니다......&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;6. 아쉬웠던 점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는, 리액트의 컴포넌트 성질을 많이 이용하려 노력하였으나 겹치는 비효율적인 코드가 많았던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 줄이는 방안으로 3차를 진행하고, 추후에 2차를 디벨롭할 수 있도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 제 파트도 너무 많아서 잘 참여하지 못했던 소캣 chatting 프론&amp;nbsp;부분도 아쉬워서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 이 부분도 많이 참여하고 싶다는 생각이 들었습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/82</guid>
      <comments>https://jihyungk.tistory.com/82#entry82comment</comments>
      <pubDate>Tue, 14 Nov 2023 02:27:51 +0900</pubDate>
    </item>
    <item>
      <title>[SeSSAC] 웹 풀스택 영등포 5기 과정_REACT(7)_Redux</title>
      <link>https://jihyungk.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Redux에 대해 배웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;0. Redux란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript의 &lt;b&gt;상태 관리 라이브러리입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 React와 함께 사용되지만, 다른 JavaScript의 프레임워크나 라이브러리에서 사용 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux의 목표는 애플리케이션의 상태를 예측 가능하고 효율적으로 관리하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 한마디로 &lt;b&gt;props 지옥&lt;/b&gt;을 벗어나는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gtzca/btsyUMAexHg/fqBcZLH2byipSERBAPOyvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gtzca/btsyUMAexHg/fqBcZLH2byipSERBAPOyvk/img.png&quot; data-alt=&quot;출처 https://www.slideshare.net/binhqdgmail/006-react-redux-framework&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gtzca/btsyUMAexHg/fqBcZLH2byipSERBAPOyvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGtzca%2FbtsyUMAexHg%2FfqBcZLH2byipSERBAPOyvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;479&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 https://www.slideshare.net/binhqdgmail/006-react-redux-framework&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 수가 많아지는 대형 프로젝트에서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 그림처럼 state를 전해주기 위한 props를 엄청나게 많이 써야 하는 경우가 발생하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 사용하게 된다면,&amp;nbsp; *&lt;b&gt;전역*&lt;/b&gt;으로 상태를 관리할 수 있어서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;store&lt;/b&gt;라는 곳에서 언제든 꺼내쓸 수가 있습니다. (오른쪽 그림과 같이)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;1. Redux의 핵심 개념&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-1. Store (스토어)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redux에서 &lt;b&gt;상태를 관리하는 중심 역할을 하는 객체&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;애플리케이션의 모든 상태가 저장되는 &lt;b&gt;저장소&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;getState, dispatch, subscribe과 같은 메서드를 제공함&lt;/li&gt;
&lt;li&gt;한 개의 프로젝트에 하나의 스토어만 가질 수 있음&lt;/li&gt;
&lt;li&gt;스토어에 있는 데이터는 컴포넌트에서 직접 조작하지 않고 리듀서 함수를 통해 간접적으로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-2. Action (액션)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상태 변경&lt;/b&gt;을 설명하는 일반적인 객체&lt;/li&gt;
&lt;li&gt;반드시 &lt;b&gt;type&lt;/b&gt; 필드를 가지고, 필요에 따라 추가 데이터를 포함(payload)할 수 있음&lt;/li&gt;
&lt;li&gt;리듀서가 수행할 작업을 설명해 줌&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-3. Reducer (리듀서)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;액션을 처리하고 새로운 상태를 반환하는 순수 함수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이전 상태와 액션을 인자로 받아 새로운 상태를 생성함&lt;/li&gt;
&lt;li&gt;스토어가 리듀서를 통해 &lt;b&gt;상태를 업데이트함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Http요청, 데이터 저장 같은 건 하면 안 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1-4. Dispatch (디스패치)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스토어를 통해 &lt;b&gt;액션을 전달&lt;/b&gt;하는 메서드&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 개념만 보면 섭섭하니까 실제 코드들을 가져와서 보도록 하겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;2. Redux 시작하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 시작하려면 먼저 Redux 모듈을 설치해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1697819400044&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install redux react-redux @reduxjs/toolkit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 설치한 리덕스를 사용하기 위해 리액트에 적용해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZSyXd/btsyTECHo8w/E9lKCyV1hPZeHbkYGYqYJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZSyXd/btsyTECHo8w/E9lKCyV1hPZeHbkYGYqYJ1/img.png&quot; data-alt=&quot;index.js 내부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZSyXd/btsyTECHo8w/E9lKCyV1hPZeHbkYGYqYJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZSyXd%2FbtsyTECHo8w%2FE9lKCyV1hPZeHbkYGYqYJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;781&quot; height=&quot;432&quot; data-origin-width=&quot;781&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;index.js 내부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 이 리액트의 모든 요소를 아우르는 index.js 파일에서 Redux를 적용하고 있는 모습입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import 되는 함수들도 헷갈리니, 하나하나 정리해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697819615773&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Provider } from 'react-redux';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr;&lt;/b&gt; React에서 Redux 스토어(저장소)를 사용하려면&lt;b&gt; Provider 컴포넌트&lt;/b&gt;를 가져와야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컴포넌트는 Redux 스토어를 애플리케이션에 제공하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697819703213&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore } from '@reduxjs/toolkit';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Redux Toolkit&lt;/b&gt;에서 제공하는 &lt;b&gt;configureStore 함수&lt;/b&gt;를 가져오고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 configureStore함수는 Redux 스토어를 설정하는 데 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux Toolkit은 간단하고 효율적으로 Redux를 사용하도록 도와주는 도구 모음입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697819752663&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { composeWithDevTools } from 'redux-devtools-extension';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Redux DevTools확장&lt;/b&gt;을 사용하여 개발 중에 Redux 동작을 모니터링해 주는 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697819822402&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import rootReducer from './store';
import Practice from './Practice';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 각각의 파일에 있는 리듀서와 컴포넌트를 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rootReducer는 제가 store파일에 만든 주요 리듀서이고, Practice는 제가 실습용으로 만든 컴포넌트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697819916750&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const root = ReactDOM.createRoot(document.getElementById('root'));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;rarr;&lt;span&gt;React18 이후의 새로운 기능 중 하나입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 더 빠르고 반응적인 애플리케이션을 만들 수 있도록 도와주는 도구입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;사용자 경험을 향상하기 위해 병렬적으로 여러 작업을 처리하는 Concurrent Mode 기능이 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 &lt;b&gt;Current Mode 내에서 createRoot 메서드를 사용한 것&lt;/b&gt;입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;createRoot 메서드는 애플리케이션의 루트를 생성하고 초기 렌더링을 시작하고 이후에도 업데이트를 지원합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697820173457&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const store = configureStore({ reducer: rootReducer }, composeWithDevTools());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 이 코드는 Redux Toolkit을 사용하고 Redux의 스토어를 구체적으로 설정하는 부분입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;configureStore 함수는 초기 스토어 설정을 구성&lt;/b&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;여기서는 매개 객체로 &lt;b&gt;{ reducer: rootReducer }가&lt;/b&gt; 전달되어 스토어는 이 리듀서를 사용하여 액션을 처리합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;b&gt;composeWithDevTools 함수&lt;/b&gt;는 개발 중에 Redux 스토어의 상태 및 액션을 쉽게 추적하도록 도와줍니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;스토어의 동작을 모니터링하고 디버깅하기 위해 스토어를 확장하기도 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697820393232&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;root.render(
    &amp;lt;Provider store={store}&amp;gt;
      &amp;lt;App4 /&amp;gt;
      &amp;lt;hr /&amp;gt;
      &amp;lt;Practice /&amp;gt;
    &amp;lt;/Provider&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; 여기서 핵심은 App4나 Practice와 같은 컴포넌트들을 감싼&lt;b&gt;&amp;lt;Provider&amp;gt;&amp;lt;/Provider&amp;gt;입니다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;여기서 Provider에 &lt;b&gt;props&lt;/b&gt;로 &lt;b&gt;store&lt;/b&gt;가 전달되어 모든 컴포넌트에서 store가 사용가능한 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 추가로, chrome에서 확장 프로그램으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux DevTools를 설치해서 리액트 앱에 적용하면 Redux 스토어에 저장된 상태를&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간편하게! 확인할 수 있습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CRL7B/btsyUOdPooB/t1242E3E5KXIpKKP9GnDw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CRL7B/btsyUOdPooB/t1242E3E5KXIpKKP9GnDw0/img.png&quot; data-alt=&quot;Redux DevTools&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CRL7B/btsyUOdPooB/t1242E3E5KXIpKKP9GnDw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCRL7B%2FbtsyUOdPooB%2Ft1242E3E5KXIpKKP9GnDw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;497&quot; height=&quot;197&quot; data-origin-width=&quot;497&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Redux DevTools&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1697856894048&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 리액트 앱에 적용하기
npm install redux-devtools-extension&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;3. Redux 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 현재 제가 소개해드릴 간단한 실습은,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 사용해서 input창에 숫자를 입력하고 입금 버튼을 선택한다면 통장잔액을 +로 변화시키고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출금 버튼을 선택한다면 통장잔액을 그만큼 -로 변화시키는 실습입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

            &lt;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&gt;
        
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n6UgY/btsyTkxSFzY/V23yR25P0Hq3NRavCqQPQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n6UgY/btsyTkxSFzY/V23yR25P0Hq3NRavCqQPQ0/img.png&quot; data-alt=&quot;실습 메인 코드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n6UgY/btsyTkxSFzY/V23yR25P0Hq3NRavCqQPQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn6UgY%2FbtsyTkxSFzY%2FV23yR25P0Hq3NRavCqQPQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;888&quot; height=&quot;573&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실습 메인 코드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 중심부가 되는 파일 먼저 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 전에 공부했던 &lt;b&gt;useState 훅&lt;/b&gt;을 input에 들어온 금액을 위해 사용하고 있고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 외 redux 관련 훅인 &lt;b&gt;useSelector와 useDispatch를 사용&lt;/b&gt;하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3-1. useSelector&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redux 스토어에서 &lt;b&gt;상태값을 선택하는 데&lt;/b&gt; 사용되는 훅&lt;/li&gt;
&lt;li&gt;Redux 스토어의 상태를 읽고 불러와서 컴포넌트에서 사용가능하게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1697858523193&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; const money = useSelector((state) =&amp;gt; state.money.money);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 현재&lt;b&gt; store&lt;/b&gt;에 있는 &lt;b&gt;money의 money&lt;/b&gt;항목을 불러오고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드가 store에서 money항목을 찾아올 수 있는 이유도 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 src 폴더 내 store 폴더를 만들고 그 폴더 내에서 &lt;b&gt;moneyReducer.js&lt;/b&gt;라는 파일을&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들었고, 이 파일은 순전히 &lt;b&gt;돈관리를 하는 store(reducer)를 담당&lt;/b&gt;하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K4c7Y/btsyRV6BNIy/jU5cOPTJMQeQT8M0bcOIN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K4c7Y/btsyRV6BNIy/jU5cOPTJMQeQT8M0bcOIN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K4c7Y/btsyRV6BNIy/jU5cOPTJMQeQT8M0bcOIN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK4c7Y%2FbtsyRV6BNIy%2FjU5cOPTJMQeQT8M0bcOIN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;191&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 파일 내에서 전달하는 상태 값에 따라 입금인지 출금인지 구분하여 값을 변경하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그 store의 money가 변경된 상태값을 money라는 변수에 넣어서 활용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3-2. useDispatch&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redux 스토어에 &lt;b&gt;액션을 디스패치&lt;/b&gt;하기 위해 사용되는 훅&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1697901272247&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const dispatch = useDispatch();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스패치는 주로 이렇게 훅을 &lt;b&gt;변수&lt;/b&gt;에 담아서 활용한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1697901327747&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Deposit = (num) =&amp;gt; ({type: 'DEPOSIT', payload: num});
const Withdrawal = (num) =&amp;gt; ({type: 'WITHDRAWAL', payload: num});

&amp;lt;button onClick={() =&amp;gt; {dispatch(Deposit(parseInt(inputNum)))}}&amp;gt;입금&amp;lt;/button&amp;gt;
&amp;lt;button onClick={() =&amp;gt; {dispatch(Withdrawal(parseInt(inputNum)))}}&amp;gt;출금&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 실습에서는 &lt;b&gt;입금이라는 버튼을 클릭했을 때 dispatch를 활용해서&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;type은 'DEPOSIT'이고 payload로 매개 변수 num을 전달&lt;/b&gt;하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로, &lt;b&gt;출금이라는 버튼을 클릭했을 때 dispatch를 활용해서&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;type은 'WITHDRAWAL'이고 payload로 매개변수 num을 전달&lt;/b&gt;하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 된다면, dispatch함수를 통해 store로 type과 payload가 전달됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs2z5w/btsyR85G8cO/Hhm8P8NZ4dOWsLGHRbBHmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs2z5w/btsyR85G8cO/Hhm8P8NZ4dOWsLGHRbBHmk/img.png&quot; data-alt=&quot;store내 moneyReducer&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs2z5w/btsyR85G8cO/Hhm8P8NZ4dOWsLGHRbBHmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs2z5w%2FbtsyR85G8cO%2FHhm8P8NZ4dOWsLGHRbBHmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;613&quot; height=&quot;445&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;store내 moneyReducer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 입금이 눌러졌다면 type을 통해 case 'DEPOSIT'이 들어가게 되어&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;moeny가 업데이트되는 것입니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 저는 이 case 'DEPOSIT'을 어떻게 이 dispatch가 찾아가는지 신기할 따름이었는데요,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 store 폴더 내에서는 &lt;b&gt;index.js&lt;/b&gt;와 같은 하나의 대표 파일에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Reducer와 변수를 넣어서 관리한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdUB5Q/btsyXYmJIXo/fs1uQ9l45oyLScMhEuVOIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdUB5Q/btsyXYmJIXo/fs1uQ9l45oyLScMhEuVOIK/img.png&quot; data-alt=&quot;store 폴더 내 index.js 파일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdUB5Q/btsyXYmJIXo/fs1uQ9l45oyLScMhEuVOIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdUB5Q%2FbtsyXYmJIXo%2Ffs1uQ9l45oyLScMhEuVOIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;308&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;store 폴더 내 index.js 파일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 제일 중요한 개념은 &lt;b&gt;combineReducers&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3-3. combineReducers&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 &lt;b&gt;리듀서들을 하나로 합칠 때&lt;/b&gt; 사용되는 함수&lt;/li&gt;
&lt;li&gt;주어진 리듀서들을 모으고 조합하여 하나의&lt;b&gt; root리듀서를 생성&lt;/b&gt;함&lt;/li&gt;
&lt;li&gt;이 리듀서들의 상태 트리를 통해 dispatch로 type이 들어오면 &lt;b&gt;알맞은 리듀서로 연결해 주는&lt;/b&gt; 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 루트리듀서를 통해 &lt;b&gt;type에 알맞게 리듀서 처리&lt;/b&gt;를 해준다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해서, &lt;u&gt;만약 같은 store 폴더 내에서 같은 type의 이름을 갖게 된다면,&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;해당 이름의 type을 가진 모든 리듀서에게 전달하는 상황이 발생한다고 합니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 리액트의 Reducer의 개념과 전체적인 흐름을 알아보았습니다 :D&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 공부한 것들/SeSSAC 웹 풀스텍 과정 회고록</category>
      <author>geograp</author>
      <guid isPermaLink="true">https://jihyungk.tistory.com/81</guid>
      <comments>https://jihyungk.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 22 Oct 2023 00:49:24 +0900</pubDate>
    </item>
  </channel>
</rss>