<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ijooha 님의 블로그</title>
    <link>https://ijooha.tistory.com/</link>
    <description>ijooha 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 21 Aug 2026 05:26:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ijooha</managingEditor>
    <item>
      <title>[RIOT-APP 트러블슈팅] 동적 페이지 생성</title>
      <link>https://ijooha.tistory.com/114</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #953b34; color: #ffffff;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;동적 라우팅 구현 이슈&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;동적 라우팅을 구현할 때 URL 파라미터를 받아서 해당 파라미터에 맞는 페이지를 동적으로 렌더링하고자 했으나,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;params가 제대로 동작하지 않아 문제가 발생했다.&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;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #953b34; color: #ffffff;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;해결 과정&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;처음에는&amp;nbsp;params.id가&amp;nbsp;undefined로 출력되는 문제를 겪었고, 이를 해결하기 위해 여러 가지 방법을 시도했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;폴더 구조나 파일 구성, 링크 설정 등에서 문제가 있을 수 있기 때문에 하나씩 차근차근 점검했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우선 Next.js에서 동적 라우팅을 사용하려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;[id]&lt;/span&gt;와 같은 폴더 이름을 사용해야 한다는 점을 다시 확인하고, 이 구조로 맞게 설정했는지 다시 보니 문제가 없었다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음 파일 구성을 계속 살펴봤는데, 동적 페이지를 구현하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;[id]&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;폴더를 만든 후, 해당 폴더에 파일을 생성하고 링크를 설정했지만, 링크 설정에서 상위 폴더의 이름을 빼먹는 실수를 했다.....&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;링크를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;Link href={&lt;/span&gt;/${page}/${champion.id}&lt;span&gt;} /&amp;gt;&lt;/span&gt;와 같이 수정하였고, 이때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;page&lt;/span&gt;를 동적으로 받아 처리할 수 있게 했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;페이지 내에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;champions&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;페이지와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;rotation&lt;/span&gt;&lt;span&gt;&amp;nbsp;&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;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;카드 컴포넌트&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1742358762046&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;Link href={`/${page}/${champion.id}`}&amp;gt; //rotation페이지에서 가는 것인지, champion에서 가는 페이지인지 확인하기 위한 용도
      &amp;lt;div&amp;gt;
        &amp;lt;Image
          src={loadingImg(champion.id)}
          alt={champion.name}
          width={300}
          height={200}
        /&amp;gt;
        &amp;lt;div&amp;gt;{champion.name}&amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;{champion.title}&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 컴포넌트에서 props로 어떤 페이지인지 받을 수 있게 해 나누어 주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rotation 페이지에서 디테일 페이지로 넘어가면 rotation/detail로 가고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;champion 페이지에서 디테일 페이지로 넘어가면 champion/detail로 가도록 설정되었다.&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;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;항상 폴더와 파일 구조, 링크 설정을 꼼꼼히 점검하면서 작업을 해야겠다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;실수로 인한 문제는 의외로 간단한 부분에서 발생하는 경우가 대부분인 것 같다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;처음부터 차근차근 살펴보는 습관을 길러야겠다!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Projects</category>
      <category>next.js</category>
      <category>riot-app</category>
      <category>typscript</category>
      <category>트러블슈팅</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/114</guid>
      <comments>https://ijooha.tistory.com/114#entry114comment</comments>
      <pubDate>Wed, 19 Mar 2025 13:46:25 +0900</pubDate>
    </item>
    <item>
      <title>[Headless UI 라이브러리 개발] Pagination 구현 계획</title>
      <link>https://ijooha.tistory.com/113</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #1a5490; color: #ffffff;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Pagination 이란?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pagination은 데이터를 여러 페이지로 나누어 보여주기 위한 기법으로, 아래와 같은 예시들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&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;796&quot; data-origin-height=&quot;172&quot;&gt;&lt;a href=&quot;https://ui.shadcn.com/docs/components/pagination&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TzInb/btsML051wuB/akvzGxqf3hI4HUSHAlnVpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTzInb%2FbtsML051wuB%2FakvzGxqf3hI4HUSHAlnVpk%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;65&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;596&quot; data-origin-height=&quot;130&quot;&gt;&lt;a href=&quot;https://www.heroui.com/docs/components/pagination&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MakgS/btsMLVX3eLm/LIK0vcbTJwUOzQ15vrcUl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMakgS%2FbtsMLVX3eLm%2FLIK0vcbTJwUOzQ15vrcUl1%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;65&quot; data-origin-width=&quot;596&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;108&quot;&gt;&lt;a href=&quot;https://mui.com/material-ui/react-pagination/?srsltid=AfmBOooqoFfNORqJD65Ms2Lla7pAeZZGlVcxNwGHJAwHNrdSG3yh8cbW&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPatAG/btsMKFILW5l/LwyDNaCbBC0TfPyQ8zo6PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPatAG%2FbtsMKFILW5l%2FLwyDNaCbBC0TfPyQ8zo6PK%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;45&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/a&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;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Pagination &amp;nbsp;컴포넌트 개발 목표&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;접근성이 높고 재사용 가능한&lt;/b&gt; Pagination 컴포넌트 구현하기!&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;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Pagination 컴포넌트에서 고려해야할 기능&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;Pagination 컴포넌트를 제작하기 앞서 고려해야할 기능들을 정리해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&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;1 기본 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 페이지 번호 표시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; '이전', '다음' 버튼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; '처음', '마지막' 버튼 (사용자가 해당 기능 사용할지 선택)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 페이지 버튼을 클릭하면 해당 페이지로 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 총 페이지수와 현재 페이지 표시 (사용자가 해당 기능 사용할지 선택)&lt;/p&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;2 추가 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 범위 기반 페이지네이션 (1-5페이지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 비활성화된 버튼 기능 (첫번째, 마지막 페이지에서 '이전', '다음', '처음', '마지막' 버튼 비활성화)&lt;/p&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;3 기본 디자인 요소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 사용자가 아이콘을 직접 수정할 수 있도록 함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 클릭된 페이지 버튼에 효과주기&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;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ffffff; background-color: #1a5490;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Link? Button?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;처음에 이미 만들어져있는 headless ui들의 pagination들을 살펴봤을 때, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;1. Link를 사용하여 각 버튼을 구성하는 방식과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;2. 그냥 버튼만을 사용하는 방식이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&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: #1a5490;&quot;&gt;&lt;b&gt;1 Link 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;사용자가 페이지를 이동할 때 새로운 url로 이동하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;일반적으로 Next.js와 같은 SPA(Single Page Application)에서 페이지 이동을 할 때 자주 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;br /&gt;&amp;bull; SEO 최적화 : 페이지를 새로 로드하는 방식이므로, 검색 엔진이 각 페이지를 별도로 인식할 수 있다.&lt;br /&gt;&amp;bull; 브라우저 히스토리 : '뒤로가기'를 통해 이전 페이지로 돌아갈 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;단점&lt;/b&gt;&lt;br /&gt;&amp;bull; &amp;nbsp;새로고침 : 페이지를 이동할 때마다 전체 페이지가 새로 로드되기 때문에 지연이 발생한다.&lt;br /&gt;&amp;bull; &amp;nbsp;URL 구조 필요 : url을 기반으로 페이지가 이동하기 때문에 url을 반영해야 한다.&lt;/blockquote&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: #1a5490;&quot;&gt;&lt;b&gt;2 Button&amp;nbsp;사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;클라이언트 측에서만 동작하며, AJAX 요청을 통해 새로운 데이터를 가져올 때 사용하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;br /&gt;&amp;bull; 빠른 페이지 전환 : 페이지를 새로고침 하지 않고 데이터를 갱신하기만 하면 되어 전환이 빠르다.&lt;br /&gt;&amp;bull; url에 의존하지 않음 : 사용자가 url을 수정하여 특정 페이지로 이동하거나 페이지를 새로 고침해도 문제가 발생하지 않는다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;단점&lt;/b&gt;&lt;br /&gt;&amp;bull; SEO 최적화 문제 : url에 페이지 번호를 반영하지 않기 때문에 각 페이지를 별도로 크롤링하지 못한다.&lt;br /&gt;&amp;bull; 히스토리 문제 : 사용자가 '뒤로 가기'를 할 때, 페이지 상태가 변경되지만 url은 변경되지 않기 때문에 이전 상태로 돌아갈 수 없다.&lt;/blockquote&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: #1a5490;&quot;&gt;&lt;b&gt;  어떤 상황에서 어떤 방식을 사용해야 할까?&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;1 Link&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; SEO 최적화가 중요한 경우 (예: 검색 결과에서 페이지가 노출되어야 하는 경우)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 각 페이지가 고유한 url을 가져야 하는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 사용자가 뒤로가기/ 앞으로 가기 기능을 사용해야 할 경우&lt;/p&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;2 Button&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 페이지 새로고침 없이 빠른 페이지 전환이 필요한 경우 (단순한 목록 표시, 데이터 필터링 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; SEO 최적화가 중요하지 않은 경우 (개인 대시보드나 비공개 페이지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 서버에 요청을 보내 동적으로 데이터를 갱신하고자 할 경우&lt;/p&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;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;결론!!!! SEO가 필요하면 Link 기반, 속도가 중요한 경우 Button 기반 Pagination을 사용하는 것이 일반적이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;때에 따라 혼합하여 사용하는 경우도 있다고 하니, 둘 중 어느쪽을 택해도 무방할 것 같다는 생각이 들었고, Button으로 진행하기로 결정했다.&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;style3&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;Pagination 컴포넌트의 구조&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;bull; Pagination&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 전체 페이지네이션을 담당하는 컴포넌트&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;bull; Buttons&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 각 페이지 번호를 표시하고, 클릭 시 해당 페이지로 이동하는 버튼&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;bull; Previous, Next&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 이전/다음 페이지로 이동하는 버튼&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;bull; Start, End&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 시작/끝 페이지로 이동하는 버튼&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;bull; PageInfo&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;구현 계획&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;bull;&amp;nbsp;Pagination 컴포넌트를 생성하고, currentPage, totalPages, pageLimit 등을 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;&lt;b&gt;2 페이지네이션 버튼 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&amp;nbsp;'이전', '다음', '처음', '끝' 등의 버튼을 누르면 해당 페이지로 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; '처음', '끝' 버튼의 경우 사용자가 사용하거나 사용하지 않을 수 있도록 설정&lt;/p&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;3 페이지 이동 및 상태 업데이트&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 각 버튼 클릭 시 currentPage를 변경하여 ui 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; '이전', '다음', '처음', '끝' 버튼으로 ui 변경&lt;/p&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;4 접근성 개선&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 버튼에 aria-label을 추가하여 스크린 리더가 읽을 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 페이지 이동이 가능할 때에만 버튼들이 활성화 되도록 설정&lt;/p&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;5 스타일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 기본 스타일 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 현재 페이지 강조&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 비활성화된 버튼 스타일링&lt;/p&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;6 추가 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; 사용자가 한 번에 몇개의 페이지를 표시할지 선택할 수 있는 기능&lt;/p&gt;</description>
      <category>Projects/zenui</category>
      <category>headless ui</category>
      <category>zenui</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/113</guid>
      <comments>https://ijooha.tistory.com/113#entry113comment</comments>
      <pubDate>Mon, 17 Mar 2025 18:22:37 +0900</pubDate>
    </item>
    <item>
      <title>[Headless UI 라이브러리 개발] Headless UI 라이브러리와 storybook 사용법</title>
      <link>https://ijooha.tistory.com/112</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ffffff; background-color: #1a5490;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Headless UI 라이브러리란?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Headless는 오직 &lt;b&gt;기능만을 제공&lt;/b&gt;해주는 ui 라이브러리이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 ui 라이브러리와는 다르게 Headless는 &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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;어떤 경우에 Headless UI를 사용할까?&lt;/b&gt;&lt;/span&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;따라서 Headless ui는 ui의 &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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #1a5490; color: #ffffff;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;storybook 이란?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UI 컴포넌트를 독립적으로 개발하고 문서화할 수 있는 도구&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 개별 UI 컴포넌트를 따로 렌더링하여, 다양한 상태(props, events)를 직접 조작하여 테스트할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;1536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfxtOO/btsMK3Cpejy/olO2QBslvzUWjJklvFyUuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfxtOO/btsMK3Cpejy/olO2QBslvzUWjJklvFyUuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfxtOO/btsMK3Cpejy/olO2QBslvzUWjJklvFyUuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfxtOO%2FbtsMK3Cpejy%2FolO2QBslvzUWjJklvFyUuK%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;500&quot; height=&quot;683&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;1536&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;storybook의 특징&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;각 ui 컴포넌트를 독립적으로 테스트하고 개발할 수 있게 하기 때문에, 컴포넌트 자체의 로직과 스타일링에 집중할 수 있다.&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;2 자동 문서화&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;3 반응형 뷰포트 지원&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;4 다양한 프레임워크 지원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React, Vue, Angular, Svelte 등 여러 프레임워크와 호환 가능하다.&lt;/p&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;storybook의 구성&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 컴포넌트 파일(jsx, tsx)이 있고, 그 외 &lt;b&gt;스토리 파일&lt;/b&gt;이 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스토리 파일에서는 컴포넌트의 다양한 상태(variant)를 정의해줄 수 있는데, 기본적인 형태는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;//.stories.jsx / .stories.tsx&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741935958683&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Meta, StoryObj } from &quot;@storybook/react&quot;;
import { Button } from &quot;./Button&quot;; // 컴포넌트 import

// Storybook에서 보여줄 메타데이터 설정
const meta: Meta&amp;lt;typeof Button&amp;gt; = {
  title: &quot;Components/Button&quot;, // Storybook에서 보일 그룹명
  component: Button, // 어떤 컴포넌트인지 지정
};
export default meta;

// 각 버튼 변형(variant) 정의
export const Primary: StoryObj&amp;lt;typeof Button&amp;gt; = {
  args: {
    label: &quot;Click Me&quot;,
    variant: &quot;primary&quot;,
  },
};

export const Secondary: StoryObj&amp;lt;typeof Button&amp;gt; = {
  args: {
    label: &quot;Click Me&quot;,
    variant: &quot;secondary&quot;,
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 스토리 파일을 작성하여 컴포넌트의 다양한 상태를 미리 보고 테스트해볼 수 있고, 자동으로 문서화 시킬 수 있다.&lt;/p&gt;</description>
      <category>Projects/zenui</category>
      <category>headless ui</category>
      <category>zenui</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/112</guid>
      <comments>https://ijooha.tistory.com/112#entry112comment</comments>
      <pubDate>Fri, 14 Mar 2025 16:31:33 +0900</pubDate>
    </item>
    <item>
      <title>[react/과제] MBTI Test: 무료 MBTI 검사 페이지</title>
      <link>https://ijooha.tistory.com/111</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;'무료 MBTI 검사 페이지 만들기'&lt;/b&gt;로 tanstack, zustand, tailwind 활용해보기&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/ijooha16/free-mbti-test&quot;&gt;GitHub 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://pokemon-dex-neon.vercel.app/&quot;&gt;포켓몬 도감 사이트 바로가기&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://ijooha.tistory.com/110&quot;&gt;트러블 슈팅&lt;/a&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #6164c6; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;개요&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;무료 MBTI 검사 사이트이다.&lt;br /&gt;로그인 하여 테스트 페이지에서 자신의 성격 유형을 파악하고,&lt;br /&gt;결과 페이지에서 다른 사람들의 유형도 살펴볼 수 있다.&lt;br /&gt;숨기기 또는 공개하기를 눌러 자신의 결과를 공개하거나 숨길 수 있다.&lt;/blockquote&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;react, tanstack, zustand, axios, json-server, tailwind, react-toastify 사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2390&quot; data-origin-height=&quot;1246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKE2N/btsMuybxI0l/qXKcDpe7aX0oF8YJYe2sMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKE2N/btsMuybxI0l/qXKcDpe7aX0oF8YJYe2sMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKE2N/btsMuybxI0l/qXKcDpe7aX0oF8YJYe2sMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKE2N%2FbtsMuybxI0l%2FqXKcDpe7aX0oF8YJYe2sMk%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;2390&quot; height=&quot;1246&quot; data-origin-width=&quot;2390&quot; data-origin-height=&quot;1246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote style=&quot;text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&amp;bull; 로그인/회원가입 또는 테스트하기를 눌러&amp;nbsp;&lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;span style=&quot;caret-color: #f3c000;&quot;&gt;로그인 하기 (로그인 하지 않은 사용자는 접근할 수 없다.)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;bull; 테스트를 진행하고 결과 페이지에서 &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;span style=&quot;caret-color: #f3c000;&quot;&gt;결과 확인하기&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;bull; 검사 결과를 &lt;span style=&quot;color: #f3c000;&quot;&gt;삭제하거나 결과의 공개 범위를 설정&lt;/span&gt;할 수 있다.&lt;/blockquote&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;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;tanstack과 zustand를 활용해볼 수 있어 좋았고, &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;더불어 tailwind, json-server을 공부하고 써볼 수 있는 기회였다!&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #6164c6; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;파일 구성&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1740377322553&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;│── db.json
│── index.html
│── server.js
│
├── src
│   ├── api                # API 호출 관련 파일
│   │   ├── api.js
│   │   ├── auth.js
│   │   ├── testResults.js
│   │
│   ├── assets             # 정적 파일 (이미지, 아이콘 등)
│   │
│   ├── components         # 재사용 가능한 UI 컴포넌트
│   │   ├── layout         # 레이아웃 관련 컴포넌트
│   │   │   ├── Footer.jsx
│   │   │   ├── Header.jsx
│   │   │   ├── Layout.jsx
│   │   │   ├── Navi.jsx
│   │   │   ├── Title.jsx
│   │   ├── AuthForm.jsx
│   │   ├── Btn.jsx
│   │   ├── ResultCard.jsx
│   │   ├── ShareBtn.jsx
│   │   ├── TestForm.jsx
│   │
│   ├── data               # 데이터 관련 파일
│   │   ├── questions.js
│   │
│   ├── pages              # 페이지 단위 컴포넌트
│   │   ├── Home.jsx
│   │   ├── Login.jsx
│   │   ├── Profile.jsx
│   │   ├── ResultPage.jsx
│   │   ├── Signup.jsx
│   │   ├── TestPage.jsx
│   │
│   ├── routes             # 라우트 관련 파일
│   │   ├── ProtectedRoute.jsx
│   │   ├── Router.jsx
│   │
│   ├── tanstack           # React Query 관련 폴더
│   │   ├── mutations
│   │   │   ├── useAuthMutations.js
│   │   │   ├── useResultMutations.js
│   │   ├── queries
│   │   │   ├── useQueries.js
│   │   ├── client.js
│   │
│   ├── utils              # 유틸리티 함수 모음
│   │   ├── mbtiCalculator.js
│   │
│   ├── zustand/store      # Zustand 상태 관리
│   │   ├── useAuthStore.js
│   │
│   ├── App.jsx
│   ├── index.css
│   ├── main.jsx&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&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;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #6164c6; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;페이지 설명&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2390&quot; data-origin-height=&quot;1246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4NK5A/btsMtNNPLv6/CYy6oSeHzKoKssUxYxhnKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4NK5A/btsMtNNPLv6/CYy6oSeHzKoKssUxYxhnKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4NK5A/btsMtNNPLv6/CYy6oSeHzKoKssUxYxhnKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4NK5A%2FbtsMtNNPLv6%2FCYy6oSeHzKoKssUxYxhnKK%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;2390&quot; height=&quot;1246&quot; data-origin-width=&quot;2390&quot; data-origin-height=&quot;1246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;홈페이지에서 테스트 하러 가기 혹은 로그인/회원가입을 누르면 &lt;b&gt;로그인 페이지로 이동&lt;/b&gt;한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;(로그인 하지 않은 회원은 결과보기 페이지, 테스트 페이지에 접근할 수 없다.)&lt;/span&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RiaSX/btsMsRKcfhj/xnONU1piQKcFbvjhX6ygsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RiaSX/btsMsRKcfhj/xnONU1piQKcFbvjhX6ygsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RiaSX/btsMsRKcfhj/xnONU1piQKcFbvjhX6ygsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRiaSX%2FbtsMsRKcfhj%2FxnONU1piQKcFbvjhX6ygsk%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;2858&quot; height=&quot;1414&quot; data-origin-width=&quot;2858&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;검사 결과가 있는 경우 자신의 &lt;b&gt;가장 최근 검사 결과&lt;/b&gt;가 뜨게되고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Flqa/btsMsVZ35jE/VEiBXLr1p7Jo3Yddlc7hEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Flqa/btsMsVZ35jE/VEiBXLr1p7Jo3Yddlc7hEk/img.png&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;1762&quot; data-is-animation=&quot;false&quot; width=&quot;429&quot; height=&quot;264&quot; data-widthpercent=&quot;52.99&quot; style=&quot;width: 52.373615%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Flqa/btsMsVZ35jE/VEiBXLr1p7Jo3Yddlc7hEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Flqa%2FbtsMsVZ35jE%2FVEiBXLr1p7Jo3Yddlc7hEk%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;2862&quot; height=&quot;1762&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oL3x0/btsMuxp9RRy/mxkK0AbfiSXvSzmB5sIZpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oL3x0/btsMuxp9RRy/mxkK0AbfiSXvSzmB5sIZpK/img.png&quot; data-origin-width=&quot;2882&quot; data-origin-height=&quot;2000&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.01&quot; style=&quot;width: 46.463595%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oL3x0/btsMuxp9RRy/mxkK0AbfiSXvSzmB5sIZpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoL3x0%2FbtsMuxp9RRy%2FmxkK0AbfiSXvSzmB5sIZpK%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;2882&quot; height=&quot;2000&quot;/&gt;&lt;/span&gt;&lt;/div&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;테스트 페이지&lt;/b&gt;에서 테스트를 진행하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과페이지&lt;/b&gt;로 가 자신의 결과와 더불어 다른 사람들의 검사 결과를 확인할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자신의 검사 결과는 &lt;b&gt;숨기기 버튼&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #6164c6; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;기능 설명&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;01 Axios: API 요청&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&amp;bull; jwt 인증을 적용하여 회원가입과 로그인 기능을 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; json-server를 사용하여 결과 데이터를 업데이트, 수정 및 삭제 가능하게 했다.&lt;/span&gt;&lt;/span&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;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;02 Tanstack: 서버와 로컬 상태 동기화&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; useMutation을 사용하여 회원 관련 정보와 검사 결과가 즉시 반영되도록 했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; useQuery로 항상 최신 상태가 유지되도록 했다.&lt;/span&gt;&lt;/span&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;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;03 Zustand: 전역 상태 관리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; 사용자 정보를 관리하여 API 호출을 줄였다.&lt;/span&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 style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; localStorage에 정보를 저장하여 새로고침 해도 로그인 상태가 유지되도록 했다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; 저장된 로그인 상태를 통해 사용자가 접근할 수 있는 페이지와 없는 페이지를 분리했다.&lt;/span&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이번에 새로운 라이브러리들을 왕창 사용해볼 수 있어서 좋았다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;zustand,와 tanstack 등 사용성이 좋은 라이브러리를 알게되고 연습도 해봤다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;더불어 tailwind도 처음 써봤는데 너무 편리했고,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;json-server로 가상의 DB를 만들어주는 방법도 알게되어 기쁘다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;다른 프로젝트를 할 때 모두 유용하게 자주 써먹을 수 있을 것 같다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>react</category>
      <category>실습</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/111</guid>
      <comments>https://ijooha.tistory.com/111#entry111comment</comments>
      <pubDate>Tue, 25 Feb 2025 16:22:18 +0900</pubDate>
    </item>
    <item>
      <title>[react/공부] 깔끔한 코드 쓰기 : MBTI Test 사이트 프로젝트 트러블 슈팅</title>
      <link>https://ijooha.tistory.com/110</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;깔끔하게 코드 쓰기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/ijooha16/free-mbti-test&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;프로젝트 링크&lt;/a&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;개요&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 완료했지만 코드가 너무 장황하고 가독성이 떨어져 보였다. &lt;br /&gt;어떻게 하면 깔끔하고 직관적으로 만들 수 있을지 고민하다가,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 컴포넌트에서 사용한 &lt;b&gt;useMutation&lt;/b&gt;과 &lt;b&gt;useQuery&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;과정  &amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 useMutation 분리&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;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;const mutation = useMutation({ mutationFn: async () =&amp;gt; { ... } })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;짧게 예시로 작성한 거라 나름 깔끔해보이지만 거의 열줄짜리 훅들이었고, useQuery와 함께 사용하거나 훅이 많아지면 굉장히 길었다.&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;code&gt;useMutations.js&lt;/code&gt; 파일을 만들고, Mutation 훅들을 따로 빼주었다.&lt;br /&gt;사용 목적에 맞게 이름을 정리하여 &lt;b&gt;useAuthMutations&lt;/b&gt;, &lt;b&gt;useResultsMutations&lt;/b&gt;로 나누고, &lt;br /&gt;회원가입과 로그인 같은 경우 &lt;b&gt;useRegisterMutation&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 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;훅을 그런식으로 컴포넌트 밖에서 사용하면 안된다고... 에러가 떴다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;그렇게 사용 목적에 맞게 각 파일에 필요한 api를 불러 훅들을 만들어줬다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;export const useRegisterMutation = () =&amp;gt; {
  return useMutation({
    mutationFn: registerUser,
    onSuccess: () =&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;그 후 컴포넌트에서는 단순히 mutation 훅을 불러와서 사용했는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 처음에는 아래와 같이 훅을 먼저 불러온 후, mutate를 붙여 선언해준 형태였다.&lt;/p&gt;
&lt;pre id=&quot;code_1740375897896&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const LoginMutation = useLoginMutation();
const login = LoginMutation.mutate;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이것도 두개가 넘어가니 너무 길고 지저분해 보여서 구조분해를 해서 사용해보기로 했다.&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;objectivec&quot;&gt;&lt;code&gt;const { mutate: login } = useLoginMutation();
login(id, pw);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하니 코드가 훨씬 깔끔해졌고, &lt;b&gt;구조분해 할당&lt;/b&gt;을 활용해 &lt;code&gt;mutate&lt;/code&gt;를 &lt;b&gt;직관적인 변수명&lt;/b&gt;으로 변경할 수 있었다.&lt;br /&gt;필요한 경우 &lt;code&gt;onSuccess&lt;/code&gt; 등 추가적인 메소드도 활용할 수 있어 사용성이 더 좋아진 것 같다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;02 useQuery 분리&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;그 후 useQuery도 분리해보기로 했다.&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;code&gt;useQuery&lt;/code&gt;를 사용했다.&lt;br /&gt;그래서 하나의 파일 &lt;code&gt;useQueries.js&lt;/code&gt;에 모두 모아 정리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 함수에 묶어서 정리해줬고,&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;export const useTestResultsQuery = () =&amp;gt; {
  return useQuery(['testResults'], fetchTestResults);
};&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;const { data: result } = useTestResultsQuery();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;코드가 깔끔해지려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최대한 분리할 수 있는 것은 분리&lt;/b&gt;하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;직관적인 변수명을 활용&lt;/b&gt;하는 것이 너무 중요한 것 같다.&lt;br /&gt;이번에 프로젝트를 빨리 끝낸 김에 코드 정리에 시간을 많이 투자해 보았는데,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이 기회로 깔끔하게 코드 적는 능력이 한 단계 성장한 느낌이 들어 기쁘다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;앞으로도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유지보수하기 쉬운, 그리고 가독성이 좋은 코드&lt;/b&gt;를 목표로 여러가지 방법을 찾아보고 시도해봐야겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>react</category>
      <category>코드잘쓰기</category>
      <category>트러블슈팅</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/110</guid>
      <comments>https://ijooha.tistory.com/110#entry110comment</comments>
      <pubDate>Mon, 24 Feb 2025 14:53:18 +0900</pubDate>
    </item>
    <item>
      <title>[react/공부] invalidateQuery와 refetchQueries 차이점 및 queryClient 메소드</title>
      <link>https://ijooha.tistory.com/109</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;invalidateQuery와 refetchQueries 차이점 및 queryClient 메소드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;쿼리 클라이언트 메소드&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border: 1px solid black; border-collapse: collapse; width: 606px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;메소드&lt;/th&gt;
&lt;th style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.getQueryData('key')&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;캐싱된 데이터를 가져옴 (API 요청 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.setQueryData('key', data)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;캐싱된 데이터를 즉시 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.invalidateQueries('key')&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;다음 패치 시 새로운 데이터로 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.refetchQueries('key')&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;즉시 새로운 데이터를 불러옴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.removeQueries('key')&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;해당 캐시를 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 312px;&quot;&gt;queryClient.fetchQuery('key', fetchFn)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid black; padding: 8px; width: 294px;&quot;&gt;새로운 데이터를 API 요청 후 가져옴&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;혼자 사용할 수 있을까?&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 디비와 연결되는 메소드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invalidateQueries, fetchQuery, refetchQueries는 디비와 직접적으로 연결되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useQuery&lt;/b&gt;나 &lt;b&gt;useMutation&lt;/b&gt; 내부에서 사용해야 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;02 독립적으로 사용 가능한 메소드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getQueryData, setQueryData, removeQueries 같은 메소드는 디비와 연결되지 않으며, &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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;캐시를 업데이트 해주는 세 가지 메소드&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;캐시를 새롭게 업데이트 해주는 방법은 세가지가 있는데, 모두 기존 캐쉬를 무시하고 새로운 데이터를 덮어씌운다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;그 세가지 메소드가 정말 너무 헷갈려서 튜터님께도 여쭤보고 gpt랑 씨름하고 구글링을 정말 많이 했다......&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 setQueryData&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setQueryData는 &lt;b&gt;DB와 상관없이&lt;/b&gt; 사용자가 임의적으로 데이터를 수정하고 덮어 씌울 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 DB와 직접적으로 소통하는 아래 두 메소드와는 조금 다른 형태&lt;/p&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;color: #c66262;&quot;&gt;&lt;b&gt;02 invalidateQueries vs refetchQueries&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;invalidateQueries와 refetchQueries는 모두 &lt;b&gt;디비와 연결&lt;/b&gt;되어 있으며 새로운 정보를 덮어 씌우는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&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;invalidateQueries&lt;/b&gt;: 데이터가 변하긴 하지만, 곧바로 반영되지 않고 &lt;b&gt;다음 패치 때&lt;/b&gt; 반영&lt;/li&gt;
&lt;li&gt;&lt;b&gt;refetchQueries&lt;/b&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;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;그래서 예를 들면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쇼핑몰의 장바구니에 아이템을 담는 경우&lt;/b&gt;, 해당 아이템은 &lt;b&gt;invalidateQueries&lt;/b&gt;로 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;(장바구니 페이지에 가야지만 확인하는 데이터이므로 곧바로 반영될 필요가 없음)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쇼핑카트 아이콘 위에 나타나는 아이템 개수&lt;/b&gt;는 즉시 UI에 반영되어야 하므로 &lt;b&gt;refetchQueries&lt;/b&gt;를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이거 이해해서 너무 뿌듯하고....... 행복하고..........&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;차이점을 명확히 알지 않아도 될 거 같아서 중간에 포기할까 했지만,&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;막상 알고나니 나름 중요한 차이점이었어서 끝까지 파고 알아내길 잘한 거 같다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>cache</category>
      <category>queryClient</category>
      <category>react</category>
      <category>tanstack</category>
      <category>공부</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/109</guid>
      <comments>https://ijooha.tistory.com/109#entry109comment</comments>
      <pubDate>Sun, 23 Feb 2025 11:53:08 +0900</pubDate>
    </item>
    <item>
      <title>[react/공부] axios 알아보기</title>
      <link>https://ijooha.tistory.com/108</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;axios&lt;/b&gt; 알아보기&lt;/span&gt;&lt;/span&gt;&lt;/h2&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;axios란?&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;axios는 기존의 fetch와 같은 역할을 하지만, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt; 등의 메소드를 활용하여 API의 데이터를 보다 쉽게 변경/삭제할 수 있도록 한다.&lt;br /&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;가장 큰 차이점은 &lt;b&gt;fetch는 기본적으로 JSON 변환 과정이 필요하지만, axios는 자동으로 변환해준다!!!! &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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;사용법&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 설치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install axios&lt;/code&gt;&lt;/pre&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: #c66262;&quot;&gt;&lt;b&gt;02 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import axios from 'axios';

const fetchData = async () =&amp;gt; {
  try {
    const response = await axios.get('https://api.example.com/data');
    console.log(response.data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

fetchData();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;위와 같이 fetch 대신 axios와 몇 가지 메소드를 합쳐서 사용하면 된다.&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;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;03 메소드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 169px;&quot;&gt;메소드&lt;/th&gt;
&lt;th style=&quot;width: 133px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 169px;&quot;&gt;axios.post(url, data)&lt;/td&gt;
&lt;td style=&quot;width: 133px;&quot;&gt;새로운 데이터를 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 169px;&quot;&gt;axios.patch(url, data)&lt;/td&gt;
&lt;td style=&quot;width: 133px;&quot;&gt;데이터의 일부를 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 169px;&quot;&gt;axios.put(url, data)&lt;/td&gt;
&lt;td style=&quot;width: 133px;&quot;&gt;데이터 전체를 교체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 169px;&quot;&gt;axios.delete(url)&lt;/td&gt;
&lt;td style=&quot;width: 133px;&quot;&gt;데이터 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이 메소드들은 이전 글에 써둔 &lt;b&gt;tanstack의 &lt;code&gt;useQuery&lt;/code&gt; (GET) 과&amp;nbsp;&lt;code&gt;useMutation&lt;/code&gt; (PUT, POST, DELETE)과 함께 사용&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;fetch를 사용할때마다 json형식으로 바꿔줘야 해서 좀 헷갈리고 종종 빼먹었엇는데&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;쓰지 않아도 된다는 게 진짜 큰 장점인 것 같다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>axios</category>
      <category>react</category>
      <category>공부</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/108</guid>
      <comments>https://ijooha.tistory.com/108#entry108comment</comments>
      <pubDate>Sat, 22 Feb 2025 15:59:12 +0900</pubDate>
    </item>
    <item>
      <title>[react/공부] tanstack 알아보기</title>
      <link>https://ijooha.tistory.com/107</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;tanstack&lt;/b&gt; 알아보기&lt;/span&gt;&lt;/span&gt;&lt;/h2&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tanstack이란?&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;tanstack은 캐쉬 저장소로, 기존에 API를 가져올 때 쓰던 fetch, useEffect의 기능을 한 번에 수행하는 역할을 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;여러 가지 메소드로 캐쉬를 변경, 삭제할 수 있고, API도 변경, 삭제, 데이터를 불러올 수 있다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;사용법&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 설치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;npm install @tanstack/react-query&lt;/code&gt;&lt;/pre&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: #c66262;&quot;&gt;&lt;b&gt;02 Provider&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;상위 컴포넌트에 가서 아래와 같이 프로바이더로 감싸주기&lt;/p&gt;
&lt;pre id=&quot;code_1740099948465&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import &quot;./index.css&quot;;
import App from &quot;./App.jsx&quot;;

const queryClient = new QueryClient();

createRoot(document.getElementById(&quot;root&quot;)).render(
  &amp;lt;StrictMode&amp;gt;
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;App /&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  &amp;lt;/StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&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: #c66262;&quot;&gt;&lt;b&gt;03 정보를 불러올 때 사용하는 useQuery&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;탠스택의 사용법은 크게 두 가지로 나뉜다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;하나는 GET과 함께 사용하는 &lt;code&gt;useQuery&lt;/code&gt;이고, 나머지 하나는 PUT, PATCH, DELETE, POST 등 API에 값을 넣어 변경해야 할 때 사용하는 &lt;code&gt;useMutation&lt;/code&gt;이다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;먼저 &lt;code&gt;useQuery&lt;/code&gt;를 사용하는 방법은 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { useQuery } from &quot;@tanstack/react-query&quot;;
import axios from &quot;axios&quot;;

const fetchData = async () =&amp;gt; {
  const { data } = await axios.get(&quot;/api/data&quot;);
  return data;
};

const Component = () =&amp;gt; {
  const { data, isLoading, error } = useQuery([&quot;dataKey&quot;], fetchData);

  if (isLoading) return &amp;lt;div&amp;gt;로딩중...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;에러 발생&amp;lt;/div&amp;gt;;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;데이터 로드 완료!&amp;lt;/h2&amp;gt;
      &amp;lt;pre&amp;gt;{JSON.stringify(data, null, 2)}&amp;lt;/pre&amp;gt; {/* JSON 데이터를 보기 좋게 출력 */}
    &amp;lt;/div&amp;gt;
  );
};

export default Component;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: red;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;** 캐싱 키는 항상 배열 안 문자열의 형태로 들어가야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이렇게 구조분해할당했을 때 &lt;code&gt;data&lt;/code&gt;, &lt;code&gt;isLoading&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;를 주게 되는데, 원하는 곳에 갖다 쓰면 된다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;color: #c66262;&quot;&gt;&lt;b&gt;04 데이터를 변경할 때 사용하는 useMutation&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;POST(정보 생성), PATCH(수정), PUT(교체), DELETE(삭제) 등 정보를 변경해야 할 &lt;code&gt;payload&lt;/code&gt;를 전달해야 할 때 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useMutation } from '@tanstack/react-query';
import axios from 'axios';

const postData = async (newData) =&amp;gt; {
  const { data } = await axios.post('/api/data', newData);
  return data;
};

const Component = () =&amp;gt; {
  const mutation = useMutation(postData);

  return (
     mutation.mutate({ name: '새 데이터' })}&amp;gt;
      데이터 추가
    
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;이렇게 &lt;code&gt;onSuccess&lt;/code&gt;, &lt;code&gt;onError&lt;/code&gt;를 반환하는데, 이를 &lt;code&gt;try&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;처럼 사용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;이 코드를 써준 후에 그 &lt;code&gt;payload&lt;/code&gt;를 전달하는 역할은 아래와 같이 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;mutation.mutate({ name: '새로운 데이터' });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;나는 이번 프로젝트에서 아직까진 onClick 콜백함수 안에만 써줬다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;form으로 정보를 넣어주는 경우(로그인, 회원가입)&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;메소드&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 세팅&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();&lt;/code&gt;&lt;/pre&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: #c66262;&quot;&gt;&lt;b&gt;02 메소드 종류&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;height: 134px; border-collapse: collapse; width: 550px;&quot; border=&quot;1px solid&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;th style=&quot;height: 20px; width: 336px;&quot;&gt;메소드&lt;/th&gt;
&lt;th style=&quot;height: 20px; width: 214px;&quot;&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.getQueryData(['캐싱키'])&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;데이터 가져오기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.setQueryData&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;캐시 직접 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.invalidateQueries&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;캐시 무효화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.refetchQueries&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;데이터 다시 패칭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.fetchQuery(쿼리키, 함수)&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;데이터 직접 가져오기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px; width: 336px;&quot;&gt;queryClient.removeQueries&lt;/td&gt;
&lt;td style=&quot;height: 19px; width: 214px;&quot;&gt;캐시 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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: #c66262;&quot;&gt;&lt;b&gt;03 메소드 차이점&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #dddddd;&quot;&gt;set, invalidate, refetch가 아무리 봐도 기능이 똑같은 거 같아서 그 차이점을 알아봤다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 546px;&quot; border=&quot;1px solid&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th style=&quot;width: 178px;&quot;&gt;메소드&lt;/th&gt;
&lt;th style=&quot;width: 189px;&quot;&gt;기존 데이터&lt;/th&gt;
&lt;th style=&quot;width: 179px;&quot;&gt;API 재요청&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 178px;&quot;&gt;setQueryData&lt;/td&gt;
&lt;td style=&quot;width: 189px;&quot;&gt;기존 데이터 유지&lt;/td&gt;
&lt;td style=&quot;width: 179px;&quot;&gt;재요청 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 178px;&quot;&gt;invalidateQueries&lt;/td&gt;
&lt;td style=&quot;width: 189px;&quot;&gt;무효화&lt;/td&gt;
&lt;td style=&quot;width: 179px;&quot;&gt;재요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 178px;&quot;&gt;refetchQueries&lt;/td&gt;
&lt;td style=&quot;width: 189px;&quot;&gt;유지&lt;/td&gt;
&lt;td style=&quot;width: 179px;&quot;&gt;재요청&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: red;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;** setQueryData의 경우 old =&amp;gt; [...old, new] 이렇게 써서 추가해주면 된다. 아니면 덮어쓰기 됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: red;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: red;&quot; 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;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;color: red; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;지난시간 zustand에 이어 tanstack을 알게되었는데 너무 유용하게 같이 사용할 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: red; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이번에 프로젝트 하면서 두개 다 익숙해지면 좋겠다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>react</category>
      <category>tanstack</category>
      <category>공부</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/107</guid>
      <comments>https://ijooha.tistory.com/107#entry107comment</comments>
      <pubDate>Fri, 21 Feb 2025 09:56:09 +0900</pubDate>
    </item>
    <item>
      <title>[react/공부] zustand</title>
      <link>https://ijooha.tistory.com/106</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;zustand&lt;/b&gt; 알아보기&lt;/span&gt;&lt;/span&gt;&lt;/h2&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;zustand란?&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;zustand는 상태를 관리하는 방법 중 하나로, useState, Context API, RTK와 같은 역할을 하는데 훠어어어얼씬 간편하다. 정말 훨씬.&lt;/p&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;사용법&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;01 설치하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install zustand&lt;/code&gt;&lt;/pre&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: #c66262;&quot;&gt;&lt;b&gt;02 세팅하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;useStore.js&lt;/code&gt; 파일을 만들어준다. (&lt;code&gt;useUserStore&lt;/code&gt; 등 원하는 네이밍을 붙여 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 안에 코드를 작성하는데, RTK의 &lt;code&gt;initialState&lt;/code&gt;, &lt;code&gt;reducer&lt;/code&gt;, &lt;code&gt;action&lt;/code&gt;을 한꺼번에 한 함수에 써준다.&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;import { create } from 'zustand';

const useStore = create((set) =&amp;gt; ({
  count: 0, // 상태 초기값
  increase: () =&amp;gt; set((state) =&amp;gt; ({ count: state.count + 1 })), // 액션
  decrease: () =&amp;gt; set((state) =&amp;gt; ({ count: state.count - 1 })),
  setCount: (value) =&amp;gt; set({ count: value }) // payload가 필요한 경우
}));

export default useStore;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #dddddd;&quot;&gt;이때 payload가 필요한 경우에는 안에 들어가는 함수 안에 인자로 넣어주면 된다.&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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;03 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;사용하기 위해서는 사용하는 컴포넌트에 가서 단순히 구조분해할당으로 내가 넣어뒀던 &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;함수&lt;/code&gt;를 &lt;code&gt;useStore&lt;/code&gt;로 아래와 같이 불러와서 사용하면 되는데,&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import useStore from './useStore';

const Counter = () =&amp;gt; {
  const { count, increase, decrease, setCount } = useStore();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;Count: {count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={increase}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={decrease}&amp;gt;-1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(10)}&amp;gt;Set to 10&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Counter;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이때 함수를 사용하면서 payload가 필요하면 인자로 넣어주면 끝이다!&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;너무 간단한 상태관리 라이브러리를 알게되었다 !&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;앞으로 정말 유용하게 써먹을 것 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에 tanstack과 zustand를 사용하고있는데, 다음 포스팅은 tanstack으로 해야겠다~&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>WEB/react</category>
      <category>zustand</category>
      <category>공부</category>
      <category>상태관리</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/106</guid>
      <comments>https://ijooha.tistory.com/106#entry106comment</comments>
      <pubDate>Thu, 20 Feb 2025 23:36:08 +0900</pubDate>
    </item>
    <item>
      <title>[라이브러리] dayjs, 날짜 라이브러리</title>
      <link>https://ijooha.tistory.com/105</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;span style=&quot;caret-color: #6164c6;&quot;&gt;&lt;b&gt;dayjs 라이브러리 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dayjs란?&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;dayjs는 날짜를 관리해주는 라이브러리이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #dddddd;&quot;&gt;달력을 만들어볼 일이 있어서 찾아봤는데, 리액트에서 제공해주는 달력은 커스터마이징이 어렵고 자유도가 떨어져서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #dddddd;&quot;&gt;그냥 날짜를 가져다 써서 달력을 만들기로 했다! 날짜 라이브러리도 다양했지만 그중 가장 가벼운 dayjs를 쓰기로 했다.&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;pre id=&quot;code_1737697456793&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install dayjs&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;기본 메소드&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #333333; background-color: #dddddd;&quot;&gt;dayjs에는 다양한 메소드가 존재하는데, 가장 기본적인 메소드는 이러하다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 106px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 19px;&quot;&gt;&lt;b&gt;현재 날짜&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 19px;&quot;&gt;&lt;span&gt;dayjs()&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 19px;&quot;&gt;&lt;b&gt;현재 년도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 19px;&quot;&gt;&lt;span&gt;dayjs().year() //month, date, day 등으로도 사용 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 17px;&quot;&gt;&lt;b&gt;날짜 더하기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 17px;&quot;&gt;dayjs().add(1, 'year')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 17px;&quot;&gt;&lt;b&gt;날짜 빼기&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 17px;&quot;&gt;dayjs().subtract(1, 'year')&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 17px;&quot;&gt;&lt;b&gt;특정 날짜 설정&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 17px;&quot;&gt;dayjs().set('year', 2026) //(년도만 2026으로 변경)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.7209%; height: 17px;&quot;&gt;&lt;b&gt;날짜 차이 계산&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 81.2791%; height: 17px;&quot;&gt;dayjs().diff(비교할 날짜, 'date') //비교 날짜와 며칠 차이인지 계산, 시간, 분, 초 단위 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c66262; color: #ffffff;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;응용하기&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&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 data-ke-size=&quot;size16&quot;&gt;한 달이 며칠인지&lt;/li&gt;
&lt;li data-ke-size=&quot;size16&quot;&gt;그 달의 첫 번째 날짜가 무슨 요일인지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;이를 활용해 `.add('month', 1)` 또는 `.subtract('month', 1)`을 이용하면 이전 달과 다음 달을 구현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737698798368&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dayjs().daysInMonth() // 한 달이 며칠인지 반환
dayjs().startOf('month').day() // 해당 달의 첫 번째 요일 (숫자로 반환, 월요일=1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #c66262;&quot;&gt;&lt;b&gt;이제 이를 활용해 달력을 구현해보자!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import styled from &quot;styled-components&quot;;
import dayjs from &quot;dayjs&quot;;
import &quot;dayjs/locale/ko&quot;;
dayjs.locale(&quot;ko&quot;);

const StCalendarGrid = styled.div`
  display: grid;
  grid-template-columns: repeat(7, auto);
  justify-content: start;
  border: 1px solid blue;
`;
const StCalendarBox = styled.div`
  width: 160px;
  height: 160px;
  border: 1px solid red;
`;

const daysName = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];
const emptyDays = dayjs().startOf(&quot;month&quot;).day() - 1;
const daysInMonth = dayjs().daysInMonth();

const Calendar = () =&amp;gt; {
  return (
    
      {daysName.map((day) =&amp;gt; (&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;{day}&lt;/div&gt;
&lt;pre id=&quot;code_1737699207949&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      ))}
      {[
        ...Array(emptyDays).fill(&quot;&quot;), // 빈 칸
        ...Array.from({ length: daysInMonth }, (_, i) =&amp;gt; i + 1), // 날짜
      ].map((el, index) =&amp;gt; (
        {el || &quot;empty&quot;}
      ))}
    
  );
};

export default Calendar;
&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;style3&quot; /&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;라이브러리를 사용할수록 새로운 기능을 쉽게 구현할 수 있어서 흥미롭다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;앞으로 더 많은 라이브러리를 활용해봐야겠다!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>기타</category>
      <category>dayjs</category>
      <category>라이브러리</category>
      <author>ijooha</author>
      <guid isPermaLink="true">https://ijooha.tistory.com/105</guid>
      <comments>https://ijooha.tistory.com/105#entry105comment</comments>
      <pubDate>Wed, 19 Feb 2025 13:13:49 +0900</pubDate>
    </item>
  </channel>
</rss>