<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>뇌 채우기 공간</title>
    <link>https://sso-feeling.tistory.com/</link>
    <description>프로그래밍 언어를 공부한 것을 기록하는 공간입니다</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 10:42:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>자바칩 프라푸치노</managingEditor>
    <image>
      <title>뇌 채우기 공간</title>
      <url>https://tistory1.daumcdn.net/tistory/3148495/attach/b8ff5f5646844fe1976d5d95abb55c87</url>
      <link>https://sso-feeling.tistory.com</link>
    </image>
    <item>
      <title>[Firebase] javascript firestore CRUD하는 방법</title>
      <link>https://sso-feeling.tistory.com/861</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;GET&lt;/h3&gt;
&lt;pre id=&quot;code_1688451598420&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const getList = async () =&amp;gt; {
  const data = (await firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).get()).docs.map(
    (doc) =&amp;gt; {
      return { ...doc.data(), id: doc.id };
    }
  );
  return 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;id를 자동 생성으로 만들게 되면 data안에는 id가 안들어있어서 따로 map으로 붙여서 새로운 배열을 만들어줬다.&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;h3 data-ke-size=&quot;size23&quot;&gt;GET BY ID&lt;/h3&gt;
&lt;pre id=&quot;code_1688451652104&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const getItemById = async (id: string) =&amp;gt; {
  const data = (
    await firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).doc(id).get()
  ).data();
  return data;
};&lt;/code&gt;&lt;/pre&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;h3 data-ke-size=&quot;size23&quot;&gt;POST&lt;/h3&gt;
&lt;pre id=&quot;code_1688451746089&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function postItem(content) {
  return firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).add(content);
}&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;h3 data-ke-size=&quot;size23&quot;&gt;DELETE&lt;/h3&gt;
&lt;pre id=&quot;code_1688451791262&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function deleteBucket(id: string) {
  return firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).doc(id).delete();
}&lt;/code&gt;&lt;/pre&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;h3 data-ke-size=&quot;size23&quot;&gt;UPDATE&lt;/h3&gt;
&lt;pre id=&quot;code_1688451820732&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function completeBucket({ id, content }) {
  return firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).doc(id).update(content);
}&lt;/code&gt;&lt;/pre&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;h3 data-ke-size=&quot;size23&quot;&gt;SET&lt;/h3&gt;
&lt;pre id=&quot;code_1688451875511&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function completeBucket({ id, content }) {
  return firebase.firestore().collection(&quot;MY_COLLECTION_NAME&quot;).doc(id).set(content);
}&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;set은 여기서 파라미터로 들어온 값으로 아예 대체를 하고 update는 업데이트 하지 않은 필드는 그대로 두고 파라미터로 들어온 값만 수정함&lt;/p&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>WEB/재밌어서 만드는 것</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/861</guid>
      <comments>https://sso-feeling.tistory.com/861#entry861comment</comments>
      <pubDate>Tue, 4 Jul 2023 15:26:47 +0900</pubDate>
    </item>
    <item>
      <title>[Vue.js] vue-awesome-swiper vue2.7 setup script에서 내장 함수 쓰는 법</title>
      <link>https://sso-feeling.tistory.com/858</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/surmon-china/vue-awesome-swiper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/surmon-china/vue-awesome-swiper&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1685085596946&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - surmon-china/vue-awesome-swiper:   Swiper component for @vuejs&quot; data-og-description=&quot;  Swiper component for @vuejs. Contribute to surmon-china/vue-awesome-swiper development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/surmon-china/vue-awesome-swiper&quot; data-og-url=&quot;https://github.com/surmon-china/vue-awesome-swiper&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bq2VEP/hySLzHD2ze/jy9K9zQiIVkz9h8dHtGVD0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/surmon-china/vue-awesome-swiper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/surmon-china/vue-awesome-swiper&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bq2VEP/hySLzHD2ze/jy9K9zQiIVkz9h8dHtGVD0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - surmon-china/vue-awesome-swiper:   Swiper component for @vuejs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;  Swiper component for @vuejs. Contribute to surmon-china/vue-awesome-swiper development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;내가 원하는 기능은 autoplay되다가 마우스 오버를 하면 멈췄다가 mouseleave를 하면 다시 autoplay가 되는 기능을 원했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 나오는 코드들은 다 vue2버전인데 나는 2.7의 setup script로 바꾸고 싶었음!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1685085805245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script setup lang='ts'&amp;gt;
const swiperRef = ref();

const onSwiperReady = (swiper) =&amp;gt; {
	swiperRef.value = swiper;
};

const mouseover = () =&amp;gt; {
	swiperRef.value.autoplay.stop();
};

const mouseleave = () =&amp;gt; {
	swiperRef.value.autoplay.start();
};

&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
&amp;lt;swiper
    :options=&quot;swiperOption&quot;
    class=&quot;flex&quot;
    @ready=&quot;onSwiperReady&quot;&amp;gt;
    ...
&amp;lt;/swiper&amp;gt;
&amp;lt;/template&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;swiper에 @ready 함수에 swiperRef를 등록하면 그 안에 등록된 함수들을 사용할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;console을 찍으면 다 나옴!&lt;/p&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>WEB/VUE.js</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/858</guid>
      <comments>https://sso-feeling.tistory.com/858#entry858comment</comments>
      <pubDate>Fri, 26 May 2023 16:27:35 +0900</pubDate>
    </item>
    <item>
      <title>[React] clip-path polygon으로 원형 wheel 만들기 2탄</title>
      <link>https://sso-feeling.tistory.com/856</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1탄은 아래 게시물&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sso-feeling.tistory.com/850&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sso-feeling.tistory.com/850&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1680599180961&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;[css] clip-path polygon으로 원형 wheel 만들기 1탄&quot; data-og-description=&quot;코드펜에서 이런 작업물을 발견했습니다. https://codepen.io/wheatup/pen/GbgyLY Interactive Wheel Menu Using javascript and css(non-svg) to make an hold-and-drag wheel menu.... codepen.io 마우스 클릭을 하면 동그란 휠이 나와서 &quot; data-og-host=&quot;sso-feeling.tistory.com&quot; data-og-source-url=&quot;https://sso-feeling.tistory.com/850&quot; data-og-url=&quot;https://sso-feeling.tistory.com/850&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lTcsy/hySa6lk286/nKlyHnBzWzwtVmg7Bit7b1/img.png?width=800&amp;amp;height=786&amp;amp;face=0_0_800_786,https://scrap.kakaocdn.net/dn/bvyNua/hyR9LiOa6c/kkuyX65mKuHgmTJSMyAps1/img.png?width=800&amp;amp;height=786&amp;amp;face=0_0_800_786,https://scrap.kakaocdn.net/dn/Nm3sp/hySa3hQirK/JEce3B23sYKCcbYLwMAWdK/img.png?width=1000&amp;amp;height=1006&amp;amp;face=0_0_1000_1006&quot;&gt;&lt;a href=&quot;https://sso-feeling.tistory.com/850&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sso-feeling.tistory.com/850&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lTcsy/hySa6lk286/nKlyHnBzWzwtVmg7Bit7b1/img.png?width=800&amp;amp;height=786&amp;amp;face=0_0_800_786,https://scrap.kakaocdn.net/dn/bvyNua/hyR9LiOa6c/kkuyX65mKuHgmTJSMyAps1/img.png?width=800&amp;amp;height=786&amp;amp;face=0_0_800_786,https://scrap.kakaocdn.net/dn/Nm3sp/hySa3hQirK/JEce3B23sYKCcbYLwMAWdK/img.png?width=1000&amp;amp;height=1006&amp;amp;face=0_0_1000_1006');&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;[css] clip-path polygon으로 원형 wheel 만들기 1탄&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;코드펜에서 이런 작업물을 발견했습니다. https://codepen.io/wheatup/pen/GbgyLY Interactive Wheel Menu Using javascript and css(non-svg) to make an hold-and-drag wheel menu.... codepen.io 마우스 클릭을 하면 동그란 휠이 나와서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sso-feeling.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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2탄은 리액트로 코드를 옮기고 hover 할때마다 약간 바운스되면서 커지는 효과를 넣어보겠습니다.&lt;/p&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는 styled-components를 사용하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. styled-components로 Wheel 스타일 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1탄의 코드를 보면 wheel의 스타일은 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680599292109&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.wheel{
  width:500px;
  height : 500px; 
  transform: translate(50%, 50%);
  
}&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;이것을 styled-component로 만들어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680599321904&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Wheel = styled.div`
  width:500px;
  height : 500px; 
  transform: translate(50%, 50%);
`;&lt;/code&gt;&lt;/pre&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;b&gt;2. styled-components로 Child 스타일 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1탄의 child css 는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680599356838&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.wheel .child {
  position: absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 50%;
  opacity: 0.8;
  transform-origin: 0% 100%;
  clip-path: polygon(0 0, 0 99%, 99% 0);
}&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;이것을 styled-component로 바꿔줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680599399835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Child = styled.div`
  position : absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 50%;
  opacity: 0.8;
  transform-origin: 0% 100%;
  clip-path: polygon(0 0, 0 99%, 99% 0);
  `;&lt;/code&gt;&lt;/pre&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;b&gt;3. child에서 props로 rotate각도와 색상, 테두리 색상을 받아서 처리하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;child에서 요소마다 rotate되는 각도가 다르고, 테두리 색상과 배경 색상이 달랐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 props로 받아서 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680599472648&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Child = styled.div`
  position : absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 50%;
  opacity: 0.8;
  transform-origin: 0% 100%;
  clip-path: polygon(0 0, 0 99%, 99% 0);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, ${(
    props
  ) =&amp;gt; props.border} 30%, ${(props) =&amp;gt; props.border} 30.5%, ${(props) =&amp;gt;
  props.bg} 31%, ${(props) =&amp;gt; props.bg} 50%, ${(props) =&amp;gt;
  props.border} 50.25%, ${(props) =&amp;gt;
  props.border} 51.5%, transparent 51.75%, transparent);
  transform: rotate(${(props) =&amp;gt; props.rotate}deg);
`;&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;pre id=&quot;code_1680599492866&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &amp;lt;Wheel&amp;gt;
        &amp;lt;Child rotate=&quot;-22.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#C89EC4&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;22.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#EE7785&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;67.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#84B1ED&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;112.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#AACD6E&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;157.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#ABD0CE&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;202.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#feee7d&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;247.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#cbe86b&quot;&amp;gt;&amp;lt;/Child&amp;gt;
        &amp;lt;Child rotate=&quot;292.5&quot; border=&quot;#67D5B5&quot; bg=&quot;#6a60a9&quot;&amp;gt;&amp;lt;/Child&amp;gt;
      &amp;lt;/Wheel&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. hover시에 애니메이션 주기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;styled-component 에서 애니메이션을 props를 사용하면서 주는 방법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680599537992&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const bounce = (rotate) =&amp;gt; keyframes`
  0% {
     transform: scale(1.1) rotate(${rotate}deg);
  }
  50% {
    transform: scale(1.13) rotate(${rotate}deg);
  }
  100% {
    transform: scale(1.1) rotate(${rotate}deg);
  }
`;&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;pre id=&quot;code_1680599549393&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Child = styled.div`
  position : absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 50%;
  opacity: 0.8;
  transform-origin: 0% 100%;
  clip-path: polygon(0 0, 0 99%, 99% 0);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, ${(
    props
  ) =&amp;gt; props.border} 30%, ${(props) =&amp;gt; props.border} 30.5%, ${(props) =&amp;gt;
  props.bg} 31%, ${(props) =&amp;gt; props.bg} 50%, ${(props) =&amp;gt;
  props.border} 50.25%, ${(props) =&amp;gt;
  props.border} 51.5%, transparent 51.75%, transparent);
  transform: rotate(${(props) =&amp;gt; props.rotate}deg);

   &amp;amp;:hover{
    animation:  ${(props) =&amp;gt; bounce(props.rotate)} 0.2s 0.1s ease-out;
    transform : rotate(${(props) =&amp;gt; props.rotate}deg) scale(1.1);
   }
    
  
`;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/437007612&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bnrK7i/hySa1EkOkM/GjKo4gblygT7u6WEUQPPY0/img.jpg?width=1020&amp;amp;height=1000&amp;amp;face=0_0_1020_1000,https://scrap.kakaocdn.net/dn/bTSMkI/hySa1YD2rm/B744g3PlQTiD1YVGnfljC0/img.jpg?width=1020&amp;amp;height=1000&amp;amp;face=0_0_1020_1000&quot; data-video-width=&quot;400&quot; data-video-height=&quot;400&quot; data-video-origin-width=&quot;400&quot; data-video-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/437007612?service=daum_tistory&quot; width=&quot;400&quot; height=&quot;400&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&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;결과는 이렇게 완성되었습니다 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>WEB/재밌어서 만드는 것</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/856</guid>
      <comments>https://sso-feeling.tistory.com/856#entry856comment</comments>
      <pubDate>Tue, 4 Apr 2023 18:19:21 +0900</pubDate>
    </item>
    <item>
      <title>[Git] pull request 에서 Run yarn install --frozen-lockfile 에러</title>
      <link>https://sso-feeling.tistory.com/855</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;깃헙 pr에서 여기서 에러가 났다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑의 사진은 success이지만 에러가 나면 x표시가 나면서 디테일 보기가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vhwv8/btr73xo8lXS/CyVJk7Q36dWtnaI5k5sx31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vhwv8/btr73xo8lXS/CyVJk7Q36dWtnaI5k5sx31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vhwv8/btr73xo8lXS/CyVJk7Q36dWtnaI5k5sx31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvhwv8%2Fbtr73xo8lXS%2FCyVJk7Q36dWtnaI5k5sx31%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;490&quot; height=&quot;38&quot; data-origin-width=&quot;490&quot; data-origin-height=&quot;38&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;Run yarn install --frozen-lockfile 과정에서 에러가 났다고 한다.&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;챗 gpt 한테 물어본 결과&lt;/p&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;yarn install --frozen-lockfile&lt;/b&gt; 명령어는 &lt;b&gt;yarn.lock&lt;/b&gt; 파일에서 의존성 패키지들을 설치하는 명령어입니다. 만약 이 과정에서 에러가 발생한다면 다음과 같은 방법들을 시도해 볼 수 있습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;에러 메시지를 분석하기: 에러 메시지를 자세히 읽어보면 어떤 종류의 에러가 발생했는지 알 수 있습니다. 에러 메시지에서 어떤 패키지나 파일에서 문제가 발생했는지, 또는 어떤 종류의 충돌이 발생했는지 확인해보세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;yarn.lock&lt;/b&gt; 파일 확인하기: &lt;b&gt;yarn.lock&lt;/b&gt; 파일이 있는지 확인하고, 이 파일이 최신 상태인지 확인하세요. &lt;b&gt;yarn.lock&lt;/b&gt; 파일이 없다면, &lt;b&gt;yarn install&lt;/b&gt; 명령어를 실행해보세요.&lt;/li&gt;
&lt;li&gt;캐시 삭제하기: &lt;b&gt;yarn cache clean&lt;/b&gt; 명령어를 실행하여 캐시를 삭제한 후, 다시 &lt;b&gt;yarn install&lt;/b&gt; 명령어를 실행해보세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;node_modules&lt;/b&gt; 폴더 삭제하기: &lt;b&gt;node_modules&lt;/b&gt; 폴더를 삭제한 후, 다시 &lt;b&gt;yarn install&lt;/b&gt; 명령어를 실행해보세요.&lt;/li&gt;
&lt;li&gt;패키지 버전 업데이트하기: &lt;b&gt;yarn upgrade [package]&lt;/b&gt; 명령어를 사용하여 패키지를 최신 버전으로 업데이트한 후, 다시 &lt;b&gt;yarn install&lt;/b&gt; 명령어를 실행해보세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;yarn.lock&lt;/b&gt; 파일 업데이트하기: &lt;b&gt;yarn upgrade --latest&lt;/b&gt; 명령어를 사용하여 &lt;b&gt;yarn.lock&lt;/b&gt; 파일을 최신 상태로 업데이트한 후, 다시 &lt;b&gt;yarn install&lt;/b&gt; 명령어를 실행해보세요.&lt;/li&gt;
&lt;/ol&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;node_modules와 yarn.lock 파일을 삭제하고 yarn install을 했더니 해결되었다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Git</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/855</guid>
      <comments>https://sso-feeling.tistory.com/855#entry855comment</comments>
      <pubDate>Tue, 4 Apr 2023 15:55:15 +0900</pubDate>
    </item>
    <item>
      <title>[에러노트] Type 'undefined' is not assignable to type 'Element'.</title>
      <link>https://sso-feeling.tistory.com/852</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;vue에서 lottie-web을 써서 아래 코드를 작성함&lt;/p&gt;
&lt;pre id=&quot;code_1679533255985&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const lottieRef = ref&amp;lt;Element | null&amp;gt;(null);

onMounted(() =&amp;gt; {
    lottie.loadAnimation({
        container: lottieRef.value,
        renderer: 'svg',
        loop: true,
        autoplay: true,
        animationData: animationLoading,
    });
    
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 container 부분에서 빨간줄이 떴다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679533284823&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; Type 'undefined' is not assignable to type 'Element'.&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;undefined를 잡으면 null 문제라고 또 떴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 해결하는 방법은&lt;/p&gt;
&lt;pre id=&quot;code_1679533329795&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const lottieRef = ref&amp;lt;Element | null&amp;gt;(null);

onMounted(() =&amp;gt; {
    if(!lottieRef.value) return;

    lottie.loadAnimation({
        container: lottieRef.value,
        renderer: 'svg',
        loop: true,
        autoplay: true,
        animationData: animationLoading,
    });
    
});&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;</description>
      <category>에러노트</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/852</guid>
      <comments>https://sso-feeling.tistory.com/852#entry852comment</comments>
      <pubDate>Thu, 23 Mar 2023 10:02:43 +0900</pubDate>
    </item>
    <item>
      <title>[React] react-query</title>
      <link>https://sso-feeling.tistory.com/851</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. react-query&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React-Query는 React 애플리케이션에서 API 데이터를 쉽게 가져오고 관리할 수 있도록 도와주는 라이브러리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React-Query를 사용하려면, 먼저 React-Query 라이브러리를 설치해야합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679452330243&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-query&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로, React-Query의 &lt;b&gt;useQuery&lt;/b&gt; hook을 사용하여 데이터를 가져올 수 있습니다. &lt;b&gt;useQuery&lt;/b&gt;는 3가지 인자를 받습니다.&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;queryKey&lt;/b&gt;: 요청에 사용할 고유 키입니다. 이 값은 문자열 또는 배열일 수 있습니다. 배열을 사용하면 여러 개의 쿼리를 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;queryFn&lt;/b&gt;: 실제 데이터를 가져오는 함수입니다. 이 함수는 Promise를 반환해야하며, 데이터를 가져오는 로직이 포함되어야합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;options&lt;/b&gt;: &lt;b&gt;useQuery&lt;/b&gt; hook을 호출하는 데 사용되는 옵션 객체입니다.&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;pre id=&quot;code_1679452352191&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useQuery } from 'react-query';

function App() {
  const { isLoading, error, data } = useQuery('todos', () =&amp;gt;
    fetch('https://jsonplaceholder.typicode.com/todos').then((res) =&amp;gt;
      res.json()
    )
  );

  if (isLoading) return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;An error has occurred: {error.message}&amp;lt;/div&amp;gt;;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Todos&amp;lt;/h1&amp;gt;
      {data.map((todo) =&amp;gt; (
        &amp;lt;p key={todo.id}&amp;gt;{todo.title}&amp;lt;/p&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예제에서는 &lt;b&gt;useQuery&lt;/b&gt;를 사용하여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSONPlaceholder API에서 Todos 데이터를 가져오고, 로딩 상태를 표시하고, 오류를 처리하고, 데이터를 렌더링합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React-Query는 다양한 기능과 옵션을 제공하여 데이터 가져오기와 관리를 훨씬 더 쉽게 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 데이터 캐싱, refetching, infinite scrolling 등을 쉽게 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;(get은 useQuery)&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. useMutation&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useMutation&lt;/b&gt; hook은 React-Query의 기능 중 하나로,&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;다음은 &lt;b&gt;useMutation&lt;/b&gt; hook을 사용한 예제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제에서는 특정 ID를 가진 사용자를 삭제하는 API를 호출하고, 성공 또는 실패 시 사용자에게 알림 메시지를 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;(post, update, delete는 useMutation)&lt;/b&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_1679452417311&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useMutation } from 'react-query';

function App() {
  const [deleteUserId, setDeleteUserId] = useState('');
  const { mutate, isLoading, isSuccess, isError, error } = useMutation(
    (id) =&amp;gt;
      fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
        method: 'DELETE',
      }).then((res) =&amp;gt; res.json()),
    {
      onSuccess: () =&amp;gt; {
        alert('User deleted successfully!');
        setDeleteUserId('');
      },
      onError: (error) =&amp;gt; {
        alert('Error deleting user: ' + error.message);
      },
    }
  );

  const handleDeleteUser = () =&amp;gt; {
    mutate(deleteUserId);
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Delete User&amp;lt;/h1&amp;gt;
      &amp;lt;label&amp;gt;
        User ID:
        &amp;lt;input
          type=&quot;number&quot;
          value={deleteUserId}
          onChange={(e) =&amp;gt; setDeleteUserId(e.target.value)}
        /&amp;gt;
      &amp;lt;/label&amp;gt;
      &amp;lt;button onClick={handleDeleteUser}&amp;gt;Delete&amp;lt;/button&amp;gt;
      {isLoading &amp;amp;&amp;amp; &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}
      {isSuccess &amp;amp;&amp;amp; &amp;lt;div&amp;gt;User deleted successfully!&amp;lt;/div&amp;gt;}
      {isError &amp;amp;&amp;amp; &amp;lt;div&amp;gt;Error deleting user: {error.message}&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;위의 예제에서는 &lt;b&gt;useMutation&lt;/b&gt; hook을 사용하여 &lt;b&gt;mutate&lt;/b&gt; 함수를 만들고, 해당 함수를 클릭 이벤트 처리기에 연결합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;mutate&lt;/b&gt; 함수는 사용자가 입력한 ID를 인자로 전달하고, API에서 데이터를 삭제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useMutation&lt;/b&gt; hook은 &lt;b&gt;isLoading&lt;/b&gt;, &lt;b&gt;isSuccess&lt;/b&gt;, &lt;b&gt;isError&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;onSuccess&lt;/b&gt;와 &lt;b&gt;onError&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;pre id=&quot;code_1679452469027&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useMutation } from 'react-query';

function useDeleteUser() {
  const [isLoading, setIsLoading] = useState(false);
  const [isSuccess, setIsSuccess] = useState(false);
  const [isError, setIsError] = useState(false);
  const [error, setError] = useState(null);

  const deleteUser = useMutation(
    (id) =&amp;gt;
      fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
        method: 'DELETE',
      }).then((res) =&amp;gt; res.json()),
    {
      onSuccess: () =&amp;gt; {
        setIsLoading(false);
        setIsSuccess(true);
        setIsError(false);
        setError(null);
      },
      onError: (error) =&amp;gt; {
        setIsLoading(false);
        setIsSuccess(false);
        setIsError(true);
        setError(error);
      },
    }
  );

  const handleDeleteUser = (id) =&amp;gt; {
    setIsLoading(true);
    setIsSuccess(false);
    setIsError(false);
    setError(null);

    deleteUser.mutate(id);
  };

  return {
    isLoading,
    isSuccess,
    isError,
    error,
    handleDeleteUser,
  };
}

function App() {
  const [deleteUserId, setDeleteUserId] = useState('');
  const { isLoading, isSuccess, isError, error, handleDeleteUser } =
    useDeleteUser();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Delete User&amp;lt;/h1&amp;gt;
      &amp;lt;label&amp;gt;
        User ID:
        &amp;lt;input
          type=&quot;number&quot;
          value={deleteUserId}
          onChange={(e) =&amp;gt; setDeleteUserId(e.target.value)}
        /&amp;gt;
      &amp;lt;/label&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; handleDeleteUser(deleteUserId)}&amp;gt;Delete&amp;lt;/button&amp;gt;
      {isLoading &amp;amp;&amp;amp; &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}
      {isSuccess &amp;amp;&amp;amp; &amp;lt;div&amp;gt;User deleted successfully!&amp;lt;/div&amp;gt;}
      {isError &amp;amp;&amp;amp; &amp;lt;div&amp;gt;Error deleting user: {error.message}&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;위의 예제 코드를 &lt;b&gt;useDeleteUser&lt;/b&gt;라는 custom hook으로 추상화하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 추상화된 hook은 다른 컴포넌트에서도 사용할 수 있으며,&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;useDeleteUser&lt;/b&gt; hook은 &lt;b&gt;deleteUser&lt;/b&gt; mutation과 &lt;b&gt;handleDeleteUser&lt;/b&gt; 함수를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;deleteUser&lt;/b&gt; mutation을 사용하여 API 호출을 수행하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;handleDeleteUser&lt;/b&gt; 함수는 &lt;b&gt;deleteUser.mutate&lt;/b&gt;를 호출하여 &lt;b&gt;deleteUser&lt;/b&gt; mutation을 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 &lt;b&gt;isLoading&lt;/b&gt;, &lt;b&gt;isSuccess&lt;/b&gt;, &lt;b&gt;isError&lt;/b&gt;, &lt;b&gt;error&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. mutate&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;mutate&lt;/b&gt; 함수는 &lt;b&gt;useMutation&lt;/b&gt; hook에서 반환되는 객체의 메서드 중 하나로,&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;&lt;b&gt;mutate&lt;/b&gt; 함수는 mutation에 전달된 인수를 사용하여 API 호출을 수행하고, mutation 상태를 업데이트합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;mutate&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_1679452533076&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mutate(
  variables?: Variables, 
  options?: MutateOptions&amp;lt;Data, Error, Variables&amp;gt;
): Promise&amp;lt;Data&amp;gt;&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;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;variables&lt;/b&gt;: mutation에 전달될 변수입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;options&lt;/b&gt;: &lt;b&gt;mutate&lt;/b&gt; 함수에 전달할 옵션입니다. &lt;b&gt;useMutation&lt;/b&gt; hook의 &lt;b&gt;options&lt;/b&gt; 객체와 유사합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Promise&amp;lt;Data&amp;gt;&lt;/b&gt;: &lt;b&gt;mutate&lt;/b&gt; 함수는 Promise를 반환하며, Promise가 성공하면 API에서 반환한 데이터를 포함한 객체가 반환됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;mutate&lt;/b&gt; 함수에 &lt;b&gt;variables&lt;/b&gt;와 &lt;b&gt;options&lt;/b&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;variables&lt;/b&gt;는 mutation에 전달할 인수를 담은 객체입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;options&lt;/b&gt;는 &lt;b&gt;useMutation&lt;/b&gt; hook의 &lt;b&gt;options&lt;/b&gt;와 동일한 옵션을 가지며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;onSuccess&lt;/b&gt;, &lt;b&gt;onError&lt;/b&gt;, &lt;b&gt;onSettled&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;mutate&lt;/b&gt; 함수를 호출하면 React Query는 &lt;b&gt;캐시된 데이터를 업데이트&lt;/b&gt;하고, &lt;b&gt;새로운 데이터를 가져와 캐시&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, &lt;b&gt;useQuery&lt;/b&gt; hook과 마찬가지로 더 나은 사용자 경험을 위해 optimistic updates를 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;i&gt;API 호출이 완료되지 않았을 때도 미리 데이터를 변경하여 UI를 업데이트함&lt;/i&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;h3 data-ke-size=&quot;size23&quot;&gt;코드 해석&lt;/h3&gt;
&lt;pre id=&quot;code_1679452558315&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const useABCQuery = (params: ABCRequestParams) =&amp;gt; {
  const queryKey = [ABC_API_PATH, params];

  return useQuery({
    queryKey,
    queryFn: () =&amp;gt; getABCApi(params)
  })
}&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;useQuery&lt;/b&gt; hook은 첫 번째 인수로 query key를, 두 번째 인수로는 &lt;b&gt;queryFn&lt;/b&gt;을 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;query key&lt;/b&gt;는 해당 쿼리를 식별하는 데 사용되며, 여기서는&lt;b&gt; [ABC_API_PATH, params]&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;queryFn&lt;/b&gt;은 쿼리를 실행하는 함수로, 여기서는 &lt;b&gt;getABCApi&lt;/b&gt; 함수를 사용하여 API를 호출하고 데이터를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;useABCQuery&lt;/b&gt; hook은 &lt;b&gt;params&lt;/b&gt;에 따라&amp;nbsp; API에서 데이터를 가져와서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Query의 캐시 기능을 사용하여 데이터를 관리하는 데 사용됩니다.&lt;/p&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 전역관리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Query에서 관리하는 데이터는 전역으로 관리됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Query는 컴포넌트 트리의 상위 레벨에서 &lt;b&gt;QueryClient&lt;/b&gt;를 생성하고, 이를 사용하여 쿼리 결과를 저장하고 캐시합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 React Query를 사용하는 모든 컴포넌트는 동일한 &lt;b&gt;QueryClient&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 Query가 &lt;i&gt;동일한 데이터를 중복으로 불러오지 않도록 보장&lt;/i&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;또한 React Query는 브라우저의 캐시와 같은 기존의 캐시 시스템을 보완하여 더욱 효율적인 데이터 관리를 제공합니다.&lt;/p&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. queryClient&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1679452589798&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { QueryClient, QueryClientProvider, useQuery } from 'react-query';

const queryClient = new QueryClient();

function App() {
  return (
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h1&amp;gt;Books&amp;lt;/h1&amp;gt;
        &amp;lt;BookList /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  );
}

function BookList() {
  const { isLoading, error, data } = useQuery('books', fetchBooks);

  if (isLoading) return &amp;lt;p&amp;gt;Loading...&amp;lt;/p&amp;gt;;

  if (error) return &amp;lt;p&amp;gt;Error: {error.message}&amp;lt;/p&amp;gt;;

  return (
    &amp;lt;ul&amp;gt;
      {data.map((book) =&amp;gt; (
        &amp;lt;li key={book.id}&amp;gt;
          &amp;lt;h2&amp;gt;{book.title}&amp;lt;/h2&amp;gt;
          &amp;lt;p&amp;gt;{book.author}&amp;lt;/p&amp;gt;
        &amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}

async function fetchBooks() {
  const response = await fetch('/api/books');
  const data = await response.json();
  return data;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제에서는 &lt;b&gt;QueryClient&lt;/b&gt;를 생성하여 &lt;b&gt;QueryClientProvider&lt;/b&gt; 컴포넌트에 전달합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 컴포넌트는 React Query의 쿼리 클라이언트를 프로바이더로 제공하여 애플리케이션 전체에서 쿼리를 관리합니다.&lt;/p&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;BookList&lt;/b&gt; 컴포넌트에서는 &lt;b&gt;useQuery&lt;/b&gt; hook을 사용하여 &lt;b&gt;fetchBooks&lt;/b&gt; 함수를 호출하고, 이를 &lt;b&gt;book&lt;/b&gt;라는 쿼리 키로 캐시합니다. &lt;b&gt;isLoading&lt;/b&gt; 및 &lt;b&gt;error&lt;/b&gt; 상태를 통해 데이터를 불러오는 동안 로딩 화면과 에러 메시지를 표시할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 데이터가 로드되면 &lt;b&gt;data&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;fetchBooks&lt;/b&gt; 함수에서는 실제로 &lt;b&gt;/api/books&lt;/b&gt; API를 호출하여 데이터를 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 데이터는 &lt;b&gt;QueryClient&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;이와 같이 React Query의 &lt;b&gt;QueryClient&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. getQueryData, setQueryData&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1679452616333&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const useABCQueryData = () =&amp;gt; {
  const queryClient = useQueryClient()
  
  // getter
  const getQueryData = () =&amp;gt; {
    return queryClient.getQueryData&amp;lt;ABCQueryData&amp;gt;(queryKey)
  }

  // setter
  const setQueryData = (updater: Updater&amp;lt;ABCQueryData | undefined, ABCQueryData | undefined&amp;gt;) =&amp;gt; {
    queryClient.setQueryData(updater)
  }


  return {
    getQueryData,
    setQueryData
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 React Query에서 &lt;b&gt;useQueryClient&lt;/b&gt; hook을 사용하여 쿼리 클라이언트 객체를 가져와서 사용하는 예제입니다.&lt;/p&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;getQueryData&lt;/b&gt; 함수는 &lt;i&gt;해당 쿼리 키에 대한 데이터를 가져오는 메서드&lt;/i&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;setQueryData&lt;/b&gt; 함수는 &lt;i&gt;해당 쿼리 키에 대한 데이터를 설정하는 메서드&lt;/i&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;updater&lt;/b&gt;는 이전 데이터를 받아 새로운 데이터를 반환하는 함수이며, 업데이트를 수행하는 방법을 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useABCQueryData&lt;/b&gt; hook에서는 &lt;b&gt;getQueryData&lt;/b&gt;와 &lt;b&gt;setQueryData&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;pre id=&quot;code_1679452632418&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useABCQuery } from 'path/to/useABCQuery';
import { useABCQueryData } from 'path/to/useABCQueryData';

function MyComponent() {
  const { data, isLoading } = useABCQuery();

  const { getQueryData, setQueryData } = useABCQueryData();

  const handleClick = () =&amp;gt; {
    const currentData = getQueryData();

    // currentData에서 원하는 정보를 가공하여 새로운 데이터 생성
    const newData = { ...currentData, additionalInfo: 'some info' };

    // 기존 데이터 업데이트
    setQueryData(newData);
  };

  return (
    &amp;lt;&amp;gt;
      {isLoading &amp;amp;&amp;amp; &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}
      {!isLoading &amp;amp;&amp;amp; data &amp;amp;&amp;amp; (
        &amp;lt;div&amp;gt;
          {/* 데이터 렌더링 */}
        &amp;lt;/div&amp;gt;
      )}
      &amp;lt;button onClick={handleClick}&amp;gt;Update Data&amp;lt;/button&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 &lt;b&gt;useABCQuery&lt;/b&gt; hook을 사용하여 데이터를 가져오고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;useABCQueryData&lt;/b&gt; hook을 사용하여 &lt;b&gt;setQueryData&lt;/b&gt;와 &lt;b&gt;getQueryData&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;handleClick&lt;/b&gt; 함수에서는 &lt;b&gt;getQueryData&lt;/b&gt; 함수를 사용하여 현재 캐시된 데이터를 가져온 후,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 데이터를 가공하여 &lt;b&gt;newData&lt;/b&gt;를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;b&gt;setQueryData&lt;/b&gt; 함수를 사용하여 &lt;b&gt;newData&lt;/b&gt;를 캐시에 업데이트합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;setQueryData&lt;/b&gt;와 &lt;b&gt;getQueryData&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7. queryFn&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;queryFn&lt;/b&gt;은 &lt;b&gt;useQuery&lt;/b&gt; hook에서 데이터를 가져오는 함수를 지정하는 옵션입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 &lt;b&gt;Promise&lt;/b&gt;를 반환해야 하며, 해당 &lt;b&gt;Promise&lt;/b&gt;가 resolve되면 데이터가 캐시에 저장됩니다.&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;queryFn&lt;/b&gt;은 보통 API 호출을 하여 데이터를 가져오는 함수로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 호출을 하는 함수를 queryFn으로 지정하면, 해당 함수는 쿼리를 호출할 때마다 API를 호출하여 데이터를 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, &lt;b&gt;queryFn&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;queryFn&lt;/b&gt;을 사용하여 API 호출을 하는 예시 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679452662144&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useQuery } from 'react-query';
import axios from 'axios';

interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

const fetchTodos = async (userId: number): Promise&amp;lt;Todo[]&amp;gt; =&amp;gt; {
  const { data } = await axios.get(`https://jsonplaceholder.typicode.com/todos?userId=${userId}`);
  return data;
};

const MyComponent = () =&amp;gt; {
  const { data, isLoading, error } = useQuery(['todos', 1], () =&amp;gt; fetchTodos(1));

  if (isLoading) {
    return &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;;
  }

  if (error) {
    return &amp;lt;div&amp;gt;Error: {error.message}&amp;lt;/div&amp;gt;;
  }

  return (
    &amp;lt;ul&amp;gt;
      {data.map((todo) =&amp;gt; (
        &amp;lt;li key={todo.id}&amp;gt;
          {todo.title} - {todo.completed ? 'completed' : 'not completed'}
        &amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위 코드에서는 &lt;b&gt;useQuery hook&lt;/b&gt;을 사용하여 API에서 todos 데이터를 가져옵니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;queryKey&lt;/b&gt;로 ['todos', 1]을 사용하고, &lt;b&gt;queryFn&lt;/b&gt;으로 fetchTodos 함수를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;fetchTodos 함수는 userId를 인자로 받으며, 해당 userId로 API를 호출하여 데이터를 가져옵니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;fetchTodos&lt;/b&gt; 함수는 &lt;b&gt;Promise&lt;/b&gt;를 반환하므로, 해당 Promise가 resolve되면 데이터가 캐시에 저장되고, &lt;/span&gt;&lt;/p&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;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;참고 : 위 설명들은 챗 gpt가 설명해준 내용입니다.&lt;/p&gt;</description>
      <category>WEB/REACT</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/851</guid>
      <comments>https://sso-feeling.tistory.com/851#entry851comment</comments>
      <pubDate>Wed, 22 Mar 2023 12:12:02 +0900</pubDate>
    </item>
    <item>
      <title>[css] clip-path polygon으로 원형 wheel 만들기 1탄</title>
      <link>https://sso-feeling.tistory.com/850</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;코드펜에서 이런 작업물을 발견했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://codepen.io/wheatup/pen/GbgyLY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://codepen.io/wheatup/pen/GbgyLY&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679041801233&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;Interactive Wheel Menu&quot; data-og-description=&quot;Using javascript and css(non-svg) to make an hold-and-drag wheel menu....&quot; data-og-host=&quot;codepen.io&quot; data-og-source-url=&quot;https://codepen.io/wheatup/pen/GbgyLY&quot; data-og-url=&quot;https://codepen.io/wheatup/details/GbgyLY&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJPhv1/hyRXr41SCZ/0YhyKOJRMlMLL0An47wq41/img.jpg?width=1000&amp;amp;height=562&amp;amp;face=0_0_1000_562,https://scrap.kakaocdn.net/dn/kxwcJ/hyRXxRHqbJ/ZdYXuJvIaOwtCHu3RI6WLk/img.jpg?width=1000&amp;amp;height=562&amp;amp;face=0_0_1000_562&quot;&gt;&lt;a href=&quot;https://codepen.io/wheatup/pen/GbgyLY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codepen.io/wheatup/pen/GbgyLY&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJPhv1/hyRXr41SCZ/0YhyKOJRMlMLL0An47wq41/img.jpg?width=1000&amp;amp;height=562&amp;amp;face=0_0_1000_562,https://scrap.kakaocdn.net/dn/kxwcJ/hyRXxRHqbJ/ZdYXuJvIaOwtCHu3RI6WLk/img.jpg?width=1000&amp;amp;height=562&amp;amp;face=0_0_1000_562');&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;Interactive Wheel Menu&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Using javascript and css(non-svg) to make an hold-and-drag wheel menu....&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codepen.io&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;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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;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;916&quot; data-origin-height=&quot;900&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sPtB7/btr4suqtu7c/UOJwBK7rUuPw4GgjHvHJMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sPtB7/btr4suqtu7c/UOJwBK7rUuPw4GgjHvHJMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sPtB7/btr4suqtu7c/UOJwBK7rUuPw4GgjHvHJMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsPtB7%2Fbtr4suqtu7c%2FUOJwBK7rUuPw4GgjHvHJMk%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;437&quot; height=&quot;429&quot; data-origin-width=&quot;916&quot; data-origin-height=&quot;900&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그런데 무엇보다 이 원형 모양을 css로 어떻게 만들었는지 궁금해서 css를 분석해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 테두리있는 조각난 원링 모양 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;각각의 버튼에 기본적으로 이러한 css가 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;예상컨대 이것이 핵심인 것 같았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679042006956&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;background-image: 
radial-gradient(circle at 0% 100%, 
transparent, 
transparent 29.5%, 
var(--color-border) 30%, 
var(--color-border) 30.5%, 
var(--color) 31%, 
var(--color) 50%, 
var(--color-border) 50.25%,
var(--color-border) 51.5%,
transparent 51.75%,
transparent);&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: #000000; font-family: 'Nanum Gothic';&quot;&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7BHMm/btr4vImS7j6/JkzdYrec3yhTG0cbaiUdA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7BHMm/btr4vImS7j6/JkzdYrec3yhTG0cbaiUdA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7BHMm/btr4vImS7j6/JkzdYrec3yhTG0cbaiUdA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7BHMm%2Fbtr4vImS7j6%2FJkzdYrec3yhTG0cbaiUdA1%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;469&quot; height=&quot;442&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;1084&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;pre id=&quot;code_1679041611633&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;hi&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1679041592411&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.hi{
  width:500px;
  height : 500px; 
  transform: translate(50%, 50%);
  background-image: radial-gradient(circle at 0% 100%, orange, gray 29.5%, pink 30%, blue 30.5%, yellow 31%, red 50%, purple 50.25%, green 51.5%, skyblue 51.75%, #DDF10B);
}&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: #000000; font-family: 'Nanum Gothic';&quot;&gt;div를 하나 만들고 background image에 색깔을 다르게 설정해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;gray 29.5는 gray가 100퍼센트가 되면&amp;nbsp; 아래와 같이 div를 끝까지 채우게 되는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;29.5퍼센트까지만 그려서 반원형을 만든 것이었습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/69iwI/btr4pZRJRuY/bzlRIoEA3HrztP6oiTV0I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/69iwI/btr4pZRJRuY/bzlRIoEA3HrztP6oiTV0I0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/69iwI/btr4pZRJRuY/bzlRIoEA3HrztP6oiTV0I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F69iwI%2Fbtr4pZRJRuY%2FbzlRIoEA3HrztP6oiTV0I0%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;436&quot; height=&quot;439&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1006&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;마찬가지로 pink 30, blue 30.5 .. 등등 도 반원형을 만드는 코드입니다.&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: #000000; font-family: 'Nanum Gothic';&quot;&gt;0.5씩 늘려서 테두리를 만들고 있습니다.&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그래서 다시 원래 코드에 transparent가 있는 부분에 transparent를 넣는다면 아래와 같이 됩니다.&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;820&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDa5O0/btr4sW735m4/GKEj9Hg8gkImnyLalz6o0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDa5O0/btr4sW735m4/GKEj9Hg8gkImnyLalz6o0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDa5O0/btr4sW735m4/GKEj9Hg8gkImnyLalz6o0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDa5O0%2Fbtr4sW735m4%2FGKEj9Hg8gkImnyLalz6o0K%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;314&quot; height=&quot;317&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;828&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;원래 작업물을 보면 테두리는 색이 1개인데 왜 2가지로 나누어졌는지가 의문이 들었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그래서 두가지로 나누지 않고 테두리 부분을 1가지 색으로 바꿔보겠습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqz7pC/btr4sSYT1H4/1tfbPkk3jP3SzmB88vckU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqz7pC/btr4sSYT1H4/1tfbPkk3jP3SzmB88vckU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqz7pC/btr4sSYT1H4/1tfbPkk3jP3SzmB88vckU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdqz7pC%2Fbtr4sSYT1H4%2F1tfbPkk3jP3SzmB88vckU0%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;353&quot; height=&quot;355&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;838&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1679042454044&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  background-image: radial-gradient(circle at 0% 100%, 
  transparent, transparent 29.5%, 
  pink 30.5%, 
  red 50%,
  green 51.5%, 
  transparent 51.75%, transparent);&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: #000000; font-family: 'Nanum Gothic';&quot;&gt;테두리 부분을 0.5씩 나누지 않고 그냥 1 차이를 두고 한가지 색상으로 설정을 해두었는데요,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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: #000000; font-family: 'Nanum Gothic';&quot;&gt;그렇다면 같은 색상으로 0.5씩 나누어서 줘보겠습니다 (원본 작업물과 같음)&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;834&quot; data-origin-height=&quot;808&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWADJF/btr4uIVmhwv/T94z7WYBuAs0K8qxRlKmXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWADJF/btr4uIVmhwv/T94z7WYBuAs0K8qxRlKmXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWADJF/btr4uIVmhwv/T94z7WYBuAs0K8qxRlKmXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWADJF%2Fbtr4uIVmhwv%2FT94z7WYBuAs0K8qxRlKmXK%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;355&quot; height=&quot;344&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;808&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;오 이제 테두리 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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;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: #000000; font-family: 'Nanum Gothic';&quot;&gt;그리하여 다음 색상과의 텀이 없도록 숫자를 조정하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679279632938&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    background-image: radial-gradient(circle at 0% 100%, 
    transparent, transparent 29.5%, 
    pink 29.5%, pink 30.5%, 
    red 30.5%, red 50%, 
    green 50%, green 51.5%, 
    transparent 5.5%, transparent);&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;1124&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RRKvB/btr4Rz4tOwt/twmreLPACkUgk7e1wQ5Cb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RRKvB/btr4Rz4tOwt/twmreLPACkUgk7e1wQ5Cb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RRKvB/btr4Rz4tOwt/twmreLPACkUgk7e1wQ5Cb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRRKvB%2Fbtr4Rz4tOwt%2FtwmreLPACkUgk7e1wQ5Cb1%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;359&quot; height=&quot;300&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;940&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;그랬더니 이제 진한 테두리가 되었습니다.&lt;/span&gt;&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;2. 원링을 8개 만들기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;하지만 이제 보니 이 비율이라면 다른색상 휠 4개밖에 못만들겠군요. (4분의 1 원이기 때문에)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;어떻게 8개로 원을 만들었는지 다시 코드를 확인해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679363788933&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;clip-path: polygon(0 0, 0 99%, 99% 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;clip-path polygon이라는 코드가 있었네요. 이건 처음봅니다..!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679363822218&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;clip-path - CSS: Cascading Style Sheets | MDN&quot; data-og-description=&quot;The clip-path CSS property creates a clipping region that sets what part of an element should be shown. Parts that are inside the region are shown, while those outside are hidden.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dqgvFO/hyRZdtoRtz/bdaTjcrkS4vSMkNNfkNWQk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dqgvFO/hyRZdtoRtz/bdaTjcrkS4vSMkNNfkNWQk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;clip-path - CSS: Cascading Style Sheets | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The clip-path CSS property creates a clipping region that sets what part of an element should be shown. Parts that are inside the region are shown, while those outside are hidden.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&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;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;폴리곤은 다각형을 만드는 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f2f2f2; color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;polygon(시계방향 꼭지점)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f2f2f2; color: #000000; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;clip-path: polygon(좌측 상단, 우측 상단, 우측 하단, 좌측 하단);&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzkk5i/btr5cSwyg5X/83RYsWcIQGLAC9DKWhKc71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzkk5i/btr5cSwyg5X/83RYsWcIQGLAC9DKWhKc71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzkk5i/btr5cSwyg5X/83RYsWcIQGLAC9DKWhKc71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzkk5i%2Fbtr5cSwyg5X%2F83RYsWcIQGLAC9DKWhKc71%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;410&quot; height=&quot;362&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;794&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;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;이렇게 값을 주는 건데&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;위 코드는 예상하기로는 아래와 같이 삼각형대로 잘라서 삼각형 안에 있는 모습만 보여주도록 하는 코드인 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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;802&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIJglm/btr5d2yyKmC/kfaTwhe22NqfhTunZM60Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIJglm/btr5d2yyKmC/kfaTwhe22NqfhTunZM60Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIJglm/btr5d2yyKmC/kfaTwhe22NqfhTunZM60Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIJglm%2Fbtr5d2yyKmC%2FkfaTwhe22NqfhTunZM60Y0%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;445&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;770&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;3. 결과&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;자 결론은..!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;div 8개를 만들고 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;각각의 div에 동일한 clip-path를 주고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;각자 rotate를 시켜주면 8개의 wheel을 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;(8개이므로 360 나누기 8 을 해서 45도씩 회전시킵니다.)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&amp;lt;완성&amp;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;1010&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chy2v2/btr5fN8Kiyy/hEZ23gKK2DNkpmGmVDr9l1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chy2v2/btr5fN8Kiyy/hEZ23gKK2DNkpmGmVDr9l1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chy2v2/btr5fN8Kiyy/hEZ23gKK2DNkpmGmVDr9l1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchy2v2%2Fbtr5fN8Kiyy%2FhEZ23gKK2DNkpmGmVDr9l1%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;539&quot; height=&quot;470&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&amp;lt;코드&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;html&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679387760886&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;wheel&quot;&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&amp;lt;/div&amp;gt;
	&amp;lt;div class=&quot;child&quot;&amp;gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;css&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679387801267&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.wheel{
  width:500px;
  height : 500px; 
  transform: translate(50%, 50%);
  
}
.wheel .child {
  position: absolute;
  top: 0;
  right: 0;
  width: 50%;
  height: 50%;
  opacity: 0.8;
  transform-origin: 0% 100%;
  clip-path: polygon(0 0, 0 99%, 99% 0);
}

.wheel .child:nth-child(1) {
  transform: rotate(-22.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, pink 30%, pink 30.5%, red 31%, red 50%, green 50.25%, green 51.5%, transparent 51.75%, transparent);

}
.wheel .child:nth-child(2) {
  transform: rotate(22.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, yellow 30%, yellow 30.5%, blue 31%, blue 50%, purple 50.25%, purple 51.5%, transparent 51.75%, transparent);

}
.wheel .child:nth-child(3) {
  transform: rotate(67.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, pink 30%, pink 30.5%, red 31%, red 50%, green 50.25%, green 51.5%, transparent 51.75%, transparent);
}
.wheel .child:nth-child(4) {
  transform: rotate(112.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, yellow 30%, yellow 30.5%, blue 31%, blue 50%, purple 50.25%, purple 51.5%, transparent 51.75%, transparent);
}
.wheel .child:nth-child(5) {
  transform: rotate(157.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, pink 30%, pink 30.5%, red 31%, red 50%, green 50.25%, green 51.5%, transparent 51.75%, transparent);
}

.wheel .child:nth-child(6) {
  transform: rotate(202.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, yellow 30%, yellow 30.5%, blue 31%, blue 50%, purple 50.25%, purple 51.5%, transparent 51.75%, transparent);
}

.wheel .child:nth-child(7) {
  transform: rotate(247.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, pink 30%, pink 30.5%, red 31%, red 50%, green 50.25%, green 51.5%, transparent 51.75%, transparent);
}

.wheel .child:nth-child(8) {
  transform: rotate(292.5deg);
  background-image: radial-gradient(circle at 0% 100%, transparent, transparent 29.5%, yellow 30%, yellow 30.5%, blue 31%, blue 50%, purple 50.25%, purple 51.5%, transparent 51.75%, transparent);
}&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: #000000; font-family: 'Nanum Gothic';&quot;&gt;다음 포스팅에서는 react 컴포넌트로 만들어서 변수로 rotate를 하고 background image를 설정 해보겠습니다 ~!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&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;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;</description>
      <category>WEB/재밌어서 만드는 것</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/850</guid>
      <comments>https://sso-feeling.tistory.com/850#entry850comment</comments>
      <pubDate>Tue, 21 Mar 2023 17:44:08 +0900</pubDate>
    </item>
    <item>
      <title>[TIL] 20230315 volta로 노드 버전 바꾸기/ vue attrs / boolean vs Boolean</title>
      <link>https://sso-feeling.tistory.com/849</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. node 버전이 안바뀌는 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 프로젝트에서는 노드를 14버전을 써야해서 노드 버전을 바꿔야했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 버전을 바꾸어도 변경이 안되었는데 그 이유는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volta에서 노드를 잡고 있어서 그렇다&lt;/p&gt;
&lt;pre id=&quot;code_1679041202070&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;volta install node@14&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;h3 data-ke-size=&quot;size23&quot;&gt;2. vue $attrs&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679041223153&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;[Vue.js] 새로운 v-model 살펴보기#4 ($attrs, $listeners)&quot; data-og-description=&quot;2021/01/22 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#1 (vue3에서 바뀐 점) 2021/01/28 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#2 (다수의 v-model 사용하기) 2021/01/31 - [개발일기/Vue.js] - [Vue&quot; data-og-host=&quot;hasudoki.tistory.com&quot; data-og-source-url=&quot;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&quot; data-og-url=&quot;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bytr22/hyRXClaVZF/rqZy6NCSj4zE0AVlOre0qK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bD9Q5q/hyRXypwy6R/VLwdHWo3GtiiCTHljarTo0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bExTCt/hyRXFvt1hJ/wjTPQTDIoUBs2qJYACkcm0/img.jpg?width=2270&amp;amp;height=944&amp;amp;face=0_0_2270_944&quot;&gt;&lt;a href=&quot;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hasudoki.tistory.com/entry/Vuejs-%EC%83%88%EB%A1%9C%EC%9A%B4-v-model-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B04-attrs-listeners&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bytr22/hyRXClaVZF/rqZy6NCSj4zE0AVlOre0qK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bD9Q5q/hyRXypwy6R/VLwdHWo3GtiiCTHljarTo0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bExTCt/hyRXFvt1hJ/wjTPQTDIoUBs2qJYACkcm0/img.jpg?width=2270&amp;amp;height=944&amp;amp;face=0_0_2270_944');&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;[Vue.js] 새로운 v-model 살펴보기#4 ($attrs, $listeners)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2021/01/22 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#1 (vue3에서 바뀐 점) 2021/01/28 - [개발일기/Vue.js] - [Vue.js] 새로운 v-model 살펴보기#2 (다수의 v-model 사용하기) 2021/01/31 - [개발일기/Vue.js] - [Vue&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hasudoki.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vue 에서 부모가 class와 style을 제외하고 모든 속성을 넘겨주는 것&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;3. boolean 과&amp;nbsp; Boolean 타입의 차이점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679041261175&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;What's the difference between boolean and Boolean in Java?&quot; data-og-description=&quot;I would like to understand the difference between the Boolean and boolean types in Java, specifically as they relate to GWT. I know that methods are not supported but I want more info if it is avai...&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&quot; data-og-url=&quot;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Jp8Gi/hyRXvGkLLT/I8QGl9ChCkn8d6WM8dKaI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/1295170/whats-the-difference-between-boolean-and-boolean-in-java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Jp8Gi/hyRXvGkLLT/I8QGl9ChCkn8d6WM8dKaI1/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&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;What's the difference between boolean and Boolean in Java?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I would like to understand the difference between the Boolean and boolean types in Java, specifically as they relate to GWT. I know that methods are not supported but I want more info if it is avai...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pythontoomuchinformation.tistory.com/493&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pythontoomuchinformation.tistory.com/493&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679041267902&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;Boolean과 boolean의 차이 = 참조타입과 원시타입의 차이&quot; data-og-description=&quot;우선, Boolean과 boolean의 차이를 알아보자. Boolean (참조타입; reference type) true, false, null 값을 가진다. &amp;there4; Null 체크를 필요로할 때 참조형을 사용하자. boolean (원시타입; primitive type) true, false 값을 가진&quot; data-og-host=&quot;pythontoomuchinformation.tistory.com&quot; data-og-source-url=&quot;https://pythontoomuchinformation.tistory.com/493&quot; data-og-url=&quot;https://pythontoomuchinformation.tistory.com/493&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rGlSY/hyRXvTSxPp/AF3mWb1Oe1u8Iemqu8fhPk/img.jpg?width=600&amp;amp;height=400&amp;amp;face=0_0_600_400,https://scrap.kakaocdn.net/dn/bglnp7/hyRXDYGVoN/KofcIZIrPwzgWhBAhCZbHk/img.jpg?width=600&amp;amp;height=400&amp;amp;face=0_0_600_400&quot;&gt;&lt;a href=&quot;https://pythontoomuchinformation.tistory.com/493&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pythontoomuchinformation.tistory.com/493&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rGlSY/hyRXvTSxPp/AF3mWb1Oe1u8Iemqu8fhPk/img.jpg?width=600&amp;amp;height=400&amp;amp;face=0_0_600_400,https://scrap.kakaocdn.net/dn/bglnp7/hyRXDYGVoN/KofcIZIrPwzgWhBAhCZbHk/img.jpg?width=600&amp;amp;height=400&amp;amp;face=0_0_600_400');&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;Boolean과 boolean의 차이 = 참조타입과 원시타입의 차이&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;우선, Boolean과 boolean의 차이를 알아보자. Boolean (참조타입; reference type) true, false, null 값을 가진다. &amp;there4; Null 체크를 필요로할 때 참조형을 사용하자. boolean (원시타입; primitive type) true, false 값을 가진&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pythontoomuchinformation.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boolean은 true, false의 값을 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Boolean은 추가로. null값을 가진다.&lt;/p&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>TIL</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/849</guid>
      <comments>https://sso-feeling.tistory.com/849#entry849comment</comments>
      <pubDate>Fri, 17 Mar 2023 17:22:40 +0900</pubDate>
    </item>
    <item>
      <title>[TIL] 20230306 패키지 잠금/ vue setup / vue filter/react custom hook</title>
      <link>https://sso-feeling.tistory.com/848</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. package-lock.json / 패키지 잠금&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package-lock.json&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://oneroomtable.tistory.com/entry/packagejson-파일이란-무엇이며-어떤-역할을-할까요&quot;&gt;https://oneroomtable.tistory.com/entry/packagejson-파일이란-무엇이며-어떤-역할을-할까요&lt;/a&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;a href=&quot;https://www.daleseo.com/js-package-locks/&quot;&gt;https://www.daleseo.com/js-package-locks/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678178924393&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;패키지 잠금 파일 (package-lock.json, yarn.lock)&quot; data-og-description=&quot;Engineering Blog by Dale Seo&quot; data-og-host=&quot;www.daleseo.com&quot; data-og-source-url=&quot;https://www.daleseo.com/js-package-locks/&quot; data-og-url=&quot;https://www.daleseo.com/js-package-locks/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLkcIO/hyRRLJe0wY/KLz7p4grph5Zj7KyYXKCOK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.daleseo.com/js-package-locks/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.daleseo.com/js-package-locks/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLkcIO/hyRRLJe0wY/KLz7p4grph5Zj7KyYXKCOK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;패키지 잠금 파일 (package-lock.json, yarn.lock)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Engineering Blog by Dale Seo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.daleseo.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;작업 시점에 따라서 패키지를 설치할 때 작업자마다 다른 버전을 설치하게 될 수도 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;package-lock.json에 명시가 되어있으면 모든 작업자가 같은 버전의 패키지를 설치할 수 있도록 보장받을 수 있다.&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;2. Vue setup&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/#computed-watch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/#computed-watch&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678178993386&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;vue3 composition api 사용법, vue, computed, reactive, ref, watch, watchEffect, props, vuex, composable&quot; data-og-description=&quot;vue3 composition api 사용법, vue, computed, reactive, ref, watch, watchEffect, props, vuex, composable&quot; data-og-host=&quot;kyounghwan01.github.io&quot; data-og-source-url=&quot;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/#computed-watch&quot; data-og-url=&quot;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Vsg3m/hyRRG2eRzQ/K85LTxBSz8GrZzvnq1y9vk/img.png?width=460&amp;amp;height=460&amp;amp;face=0_0_460_460&quot;&gt;&lt;a href=&quot;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/#computed-watch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kyounghwan01.github.io/blog/Vue/vue3/composition-api/#computed-watch&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Vsg3m/hyRRG2eRzQ/K85LTxBSz8GrZzvnq1y9vk/img.png?width=460&amp;amp;height=460&amp;amp;face=0_0_460_460');&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;vue3 composition api 사용법, vue, computed, reactive, ref, watch, watchEffect, props, vuex, composable&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;vue3 composition api 사용법, vue, computed, reactive, ref, watch, watchEffect, props, vuex, composable&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kyounghwan01.github.io&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;h3 data-ke-size=&quot;size23&quot;&gt;3. Vue filter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://v2.ko.vuejs.org/v2/guide/filters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://v2.ko.vuejs.org/v2/guide/filters.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678179004516&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;필터 &amp;mdash; Vue.js&quot; data-og-description=&quot;Vue.js - 프로그레시브 자바스크립트 프레임워크&quot; data-og-host=&quot;v2.ko.vuejs.org&quot; data-og-source-url=&quot;https://v2.ko.vuejs.org/v2/guide/filters.html&quot; data-og-url=&quot;https://v2.ko.vuejs.org/v2/guide/filters.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mFXSH/hyRRKXREyT/Vi5Uwbw3QKNY0v6g9KLdJ0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/j4dm3/hyRRNfYGPG/k99N19nKB9cNZZ46SpR9XK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://v2.ko.vuejs.org/v2/guide/filters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://v2.ko.vuejs.org/v2/guide/filters.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mFXSH/hyRRKXREyT/Vi5Uwbw3QKNY0v6g9KLdJ0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/j4dm3/hyRRNfYGPG/k99N19nKB9cNZZ46SpR9XK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&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;필터 &amp;mdash; Vue.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Vue.js - 프로그레시브 자바스크립트 프레임워크&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;v2.ko.vuejs.org&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;h3 data-ke-size=&quot;size23&quot;&gt;4. react custom hook&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko-de-dev-green.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ko-de-dev-green.tistory.com/71&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678179020977&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;custom hook 이란? React hooks custom hook 이란?&quot; data-og-description=&quot;custom hook 이란? React hooks custom hook 이란? 오늘은 짧게 리액트 훅에서 커스텀 훅을 알아보겠습니다. 커스텀 훅이란 말 그대로 개발자가 스스로 커스텀 한 훅을 말합니다. 예를 들면 useState, useEffect, &quot; data-og-host=&quot;ko-de-dev-green.tistory.com&quot; data-og-source-url=&quot;https://ko-de-dev-green.tistory.com/71&quot; data-og-url=&quot;https://ko-de-dev-green.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QPmf9/hyRRDEqY2P/PkdkOtPKu07Awm9RaP8JOk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/eD2sB/hyRRCZPgHN/i3XDnPQncpdba5TJMsjnX1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cSNToa/hyRRNfYHHY/qlKb8dNNYIKF8PbosVaTa1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://ko-de-dev-green.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko-de-dev-green.tistory.com/71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QPmf9/hyRRDEqY2P/PkdkOtPKu07Awm9RaP8JOk/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/eD2sB/hyRRCZPgHN/i3XDnPQncpdba5TJMsjnX1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cSNToa/hyRRNfYHHY/qlKb8dNNYIKF8PbosVaTa1/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;custom hook 이란? React hooks custom hook 이란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;custom hook 이란? React hooks custom hook 이란? 오늘은 짧게 리액트 훅에서 커스텀 훅을 알아보겠습니다. 커스텀 훅이란 말 그대로 개발자가 스스로 커스텀 한 훅을 말합니다. 예를 들면 useState, useEffect,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko-de-dev-green.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;h3 data-ke-size=&quot;size23&quot;&gt;5. 임의의 랜덤값 생성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jookipedia.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jookipedia.tistory.com/22&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678179058337&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;임의의 랜덤값 생성하기&quot; data-og-description=&quot;개발하는 과정에서 임의의 랜던값을 생성해서 PK값인 ID 값으로 사용 할때가 종종 발생하여 오늘은 임의의 랜던 값 생성 하는 방법에 대하여 정리한다. RandomStringUtils를 이용한 랜덤 문자열 생성 -&quot; data-og-host=&quot;jookipedia.tistory.com&quot; data-og-source-url=&quot;https://jookipedia.tistory.com/22&quot; data-og-url=&quot;https://jookipedia.tistory.com/22&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bTwfvs/hyRRPLFh0u/lCXC6kK8KqFB0MVYTRkL90/img.png?width=800&amp;amp;height=222&amp;amp;face=0_0_800_222,https://scrap.kakaocdn.net/dn/y2pii/hyRRPrk80G/WLFs5PjyKkrRIzhbsIXWU0/img.png?width=800&amp;amp;height=222&amp;amp;face=0_0_800_222&quot;&gt;&lt;a href=&quot;https://jookipedia.tistory.com/22&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jookipedia.tistory.com/22&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bTwfvs/hyRRPLFh0u/lCXC6kK8KqFB0MVYTRkL90/img.png?width=800&amp;amp;height=222&amp;amp;face=0_0_800_222,https://scrap.kakaocdn.net/dn/y2pii/hyRRPrk80G/WLFs5PjyKkrRIzhbsIXWU0/img.png?width=800&amp;amp;height=222&amp;amp;face=0_0_800_222');&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;임의의 랜덤값 생성하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개발하는 과정에서 임의의 랜던값을 생성해서 PK값인 ID 값으로 사용 할때가 종종 발생하여 오늘은 임의의 랜던 값 생성 하는 방법에 대하여 정리한다. RandomStringUtils를 이용한 랜덤 문자열 생성 -&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jookipedia.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;</description>
      <category>TIL</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/848</guid>
      <comments>https://sso-feeling.tistory.com/848#entry848comment</comments>
      <pubDate>Tue, 7 Mar 2023 17:51:48 +0900</pubDate>
    </item>
    <item>
      <title>[React/next/ts] react로  라이브러리 없이 달력 구현하는 법</title>
      <link>https://sso-feeling.tistory.com/847</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;달력 만드는 것이 너무 어려워서 챗 gpt한테 코드 좀 작성해달라했는데..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vvjmY/btr0Dht8a5q/Z5pZGTfxWELX068Kwcx8N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vvjmY/btr0Dht8a5q/Z5pZGTfxWELX068Kwcx8N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vvjmY/btr0Dht8a5q/Z5pZGTfxWELX068Kwcx8N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvvjmY%2Fbtr0Dht8a5q%2FZ5pZGTfxWELX068Kwcx8N0%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;1856&quot; height=&quot;1376&quot; data-origin-width=&quot;1856&quot; data-origin-height=&quot;1376&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;프리미엄이 아니라서 끝까지 볼 수 없었다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) 요일 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWsuqt/btr0DjrWZu3/2RDJvrT8lTLZojvYjzb7QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWsuqt/btr0DjrWZu3/2RDJvrT8lTLZojvYjzb7QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWsuqt/btr0DjrWZu3/2RDJvrT8lTLZojvYjzb7QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWsuqt%2Fbtr0DjrWZu3%2F2RDJvrT8lTLZojvYjzb7QK%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;556&quot; height=&quot;527&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1118&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;이 달력 만드는 것 중에 가장 쉬운 부분은 여기다. 그래서 이거부터 하겠음.&lt;/p&gt;
&lt;pre id=&quot;code_1677224129875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const DayoftheWeek = () =&amp;gt; {
  const date = [&quot;일&quot;, &quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;];

  return (
    &amp;lt;thead className=&quot;days rows flex justify-center my-[10px]&quot;&amp;gt;
      &amp;lt;tr&amp;gt;
        {date.map((p) =&amp;gt; {
          return (
            &amp;lt;th className=&quot;col w-[50px] text-center&quot; key={p}&amp;gt;
              {p}
            &amp;lt;/th&amp;gt;
          );
        })}
      &amp;lt;/tr&amp;gt;
    &amp;lt;/thead&amp;gt;
  );
};

export default DayoftheWeek;&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;요일 배열을 만들어주고 map돌려서 보여주면 된다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2) 현재 월에서 뒤로가기 앞으로 가기 구현하기&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pRhjx/btr0BDKXMP7/Lfp7dMkebIBAAby6qcaxNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pRhjx/btr0BDKXMP7/Lfp7dMkebIBAAby6qcaxNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pRhjx/btr0BDKXMP7/Lfp7dMkebIBAAby6qcaxNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpRhjx%2Fbtr0BDKXMP7%2FLfp7dMkebIBAAby6qcaxNk%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;454&quot; height=&quot;549&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 구현할 것은 2023년 2월 (현재 달) 에서 이전 달로 이동, 다음 달로 이동하는 것을 만들어보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677224242268&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { addMonths, startOfMonth, startOfWeek, subMonths } from &quot;date-fns&quot;;
import { useState } from &quot;react&quot;;
import CalendarHeader from &quot;./CalendarHeader&quot;;
import CalendarTable from &quot;./CalendarTable&quot;;

const Calendar = () =&amp;gt; {
//현재 보고 있는 달
  const [currentMonth, setCurrentMonth] = useState(new Date());
  const [selectedDate, setSelectedDate] = useState(new Date());

//이전 달로 이동(currentMonth가 이전 달로 바뀜)
  const prevMonth = () =&amp;gt; {
    setCurrentMonth(subMonths(currentMonth, 1));
  };
  
//다음 달로 이동(currentMonth가 다음 달로 바뀜)
  const nextMonth = () =&amp;gt; {
    setCurrentMonth(addMonths(currentMonth, 1));
  };
  const onDateClick = (day: React.SetStateAction&amp;lt;Date&amp;gt;) =&amp;gt; {
    setSelectedDate(day);
  };
  const monthStart = startOfMonth(currentMonth);
  const startDate = startOfWeek(monthStart);

  return (
    &amp;lt;div className=&quot;flex flex-col justify-center&quot;&amp;gt;
      &amp;lt;CalendarHeader
        currentMonth={currentMonth}
        prevMonth={prevMonth}
        nextMonth={nextMonth}
      /&amp;gt;
      &amp;lt;CalendarTable currentMonth={currentMonth} selectedDate={selectedDate} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default Calendar;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드가 캘린더 전체 코드인데, 이번에 구현하고자 하는 부분이 CalendarHeader 컴포넌트 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CalendarTable은 일단 무시하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 컨포넌트에서 현재 달을 구하고 prevMonth와 nextMonth로 가는 메서드를 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 같은 currentMonth를 밑에오는 CanlendarTable컴포넌트와 공유해야하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677224343083&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { format } from &quot;date-fns&quot;;

import ArrowBackIosIcon from &quot;@mui/icons-material/ArrowBackIos&quot;;
import ArrowForwardIosIcon from &quot;@mui/icons-material/ArrowForwardIos&quot;;

interface CalendarHeaderProps {
  currentMonth: Date;
  prevMonth?: () =&amp;gt; void;
  nextMonth?: () =&amp;gt; void;
}
const CalendarHeader = ({
  currentMonth,
  prevMonth,
  nextMonth,
}: CalendarHeaderProps) =&amp;gt; {
  return (
    &amp;lt;div className=&quot;flex justify-center m-[20px]&quot;&amp;gt;
      &amp;lt;button onClick={prevMonth}&amp;gt;
        &amp;lt;ArrowBackIosIcon sx={{ fontSize: &quot;12px&quot; }} /&amp;gt;
      &amp;lt;/button&amp;gt;
      &amp;lt;span className=&quot;m-[20px] text-[20px]&quot;&amp;gt;
        {format(currentMonth, &quot;yyyy&quot;)}년{' '}
        &amp;lt;span&amp;gt;{format(currentMonth, &quot;M&quot;)}월&amp;lt;/span&amp;gt;
      &amp;lt;/span&amp;gt;
      &amp;lt;button onClick={nextMonth}&amp;gt;
        &amp;lt;ArrowForwardIosIcon sx={{ fontSize: &quot;12px&quot; }} /&amp;gt;
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default CalendarHeader;&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;CalendarHeader는 이런 모습이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arrow버튼을 두어서 클릭을 할 때마다 위에서 본 부모의 메서드를 호출해서 사용하고 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) 달력에 날짜 표시하기&lt;/b&gt;&lt;/h3&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;[1] 현재 보고 있는 달이 시작하는 날을 구한다. (2월 1일이 수요일이라는 사실을 구한다.)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[2] 현재 보고 있는 달이 끝나는 날을 구한다. (2월이 28일까지 있고 그것은 화요일이라는 사실)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[3] 맨 첫번째 칸의 날짜를 구한다(1월 29일이다)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[4] 맨 마지막 칸의 날짜를 구한다(3월 4일이다)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[5] 3번에서 구한 처음 날부터 7개까지 한 배열로 묶는다. 그걸 끝날때 까지 반복한다.&lt;/b&gt;&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;예를 들면 아래와 같은 배열이 만들어진다.&lt;/p&gt;
&lt;pre id=&quot;code_1677224975591&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[[29, 30, 31, 1, 2, 3, 4],
 [5, 6, 7, 8, 9, 10, 11],
 [12, 13, 14, 15, 16, 17, 18],
 [19, 20, 21, 22, 23, 24, 25],
 [26, 27, 28, 1, 2, 3, 4],
]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[7] 그것을 렌더링한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[8] 오늘 날짜랑 비교해서 오늘은 다른 색을 넣어준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[9] 현재 보고 있는 달과 비교해서 달이 다르면 투명한 글자를 넣어준다.&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_1677225046906&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const CalendarTable = ({ currentMonth, selectedDate }: CalendarProps) =&amp;gt; {
  return (
    &amp;lt;table className=&quot;calendar text-[16px]&quot;&amp;gt;
      &amp;lt;DayoftheWeek /&amp;gt;
      &amp;lt;Tbody&amp;gt;
        &amp;lt;Tr currentMonth={currentMonth} selectedDate={selectedDate} /&amp;gt;
      &amp;lt;/Tbody&amp;gt;
    &amp;lt;/table&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까봤던 CalendarTable 컴포넌트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;table 태그로 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DayoftheWeek 컴포넌트는 위에서 했던 요일 만드는 컴포넌트이다.&lt;/p&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;Tbody부터 확인해보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677225092836&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface TbodyProps {
  children: ReactNode;
}

const Tbody = ({ children }: TbodyProps) =&amp;gt; {
  return &amp;lt;tbody className=&quot;body&quot;&amp;gt;{children}&amp;lt;/tbody&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별거없이 tbody 태그에 children만 넣어주고 있다.&lt;/p&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;Tr태그로 가보자.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677225144835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface CalendarProps {
  currentMonth: Date;
  selectedDate: Date;
}
interface WholeDateArray {
  date: Date;
  formattedDate: string;
}

const Tr = ({
  currentMonth,
  selectedDate,
}: PropsWithChildren&amp;lt;CalendarProps&amp;gt;) =&amp;gt; {
  const monthStart = startOfMonth(currentMonth); //현재 보고 있는 달의 시작하는 날
  const monthEnd = endOfMonth(monthStart); //현재 보고 있는 달의 끝나는 날
  const startDate = startOfWeek(monthStart); //현재 보고 있는 달력에서 맨 앞칸
  const endDate = endOfWeek(monthEnd); //현재 보고 있는 달력에서 마지막 칸

 // 한달에 몇 주인지 체크
  const countOfWeek = Math.ceil(differenceInDays(endDate, startDate) / 7);

  let day = startDate;

//이차원 배열 
  let wholeDate: WholeDateArray[][] = [];
  for (let i = 0; i &amp;lt; countOfWeek; i++) {
    let arr: WholeDateArray[] = [];
    //7번 반복
    for (let j = 0; j &amp;lt; 7; j++) {
    //추후에 날짜를 선택해서 저장할 것을 고려하여 date정보와 format된 정보를 객체로 저장했다.
      arr.push({
        date: day,
        formattedDate: format(day, &quot;d&quot;),
      });

	//날짜를 다음날로 옮긴다.
      day = addDays(day, 1);
    }
    
    //위에서 만든 길이 7짜리 배열을 이차원 배열에 넣음
    wholeDate.push(arr);
  }

  return (
    &amp;lt;&amp;gt;
      {wholeDate.map((p) =&amp;gt; {
        return (
          &amp;lt;tr className=&quot;row flex justify-center&quot; key={Math.random()}&amp;gt;
            &amp;lt;Td weekDate={p} currentMonth={currentMonth}&amp;gt;&amp;lt;/Td&amp;gt;
          &amp;lt;/tr&amp;gt;
        );
      })}
    &amp;lt;/&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Td태그로 가보자&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677225377331&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface TdProps {
  weekDate: WholeDateArray[];
  currentMonth: Date;
}

const Td = ({ weekDate, currentMonth }: TdProps) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      {weekDate.map((p) =&amp;gt; {
        const isToday =
          format(new Date(), &quot;yyyy-M-d&quot;) === format(p.date, &quot;yyyy-M-d&quot;);

        const isThisMonth =
          format(currentMonth, &quot;yyyy-M&quot;) === format(p.date, &quot;yyyy-M&quot;);
        return (
          &amp;lt;td
            key={p.formattedDate}
            className={`w-[50px] text-center h-[80px] ${
              !isThisMonth &amp;amp;&amp;amp; &quot;text-transparent&quot;
            }`}
          &amp;gt;
            &amp;lt;span className={`${isToday &amp;amp;&amp;amp; &quot;text-[#663399]&quot;}`}&amp;gt;
              {p.formattedDate}
            &amp;lt;/span&amp;gt;
          &amp;lt;/td&amp;gt;
        );
      })}
    &amp;lt;/&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4) 결과 화면&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/436041161&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cE1rzc/hyRJRDfu7K/eGkXK8JQgOnsYoywhIBXu1/img.jpg?width=780&amp;amp;height=1700&amp;amp;face=0_0_780_1700,https://scrap.kakaocdn.net/dn/8xHCJ/hyRJN8FzAh/g3J1SScJ9lRC1lPqkRcKC1/img.jpg?width=780&amp;amp;height=1700&amp;amp;face=0_0_780_1700&quot; data-video-width=&quot;300&quot; data-video-height=&quot;654&quot; data-video-origin-width=&quot;780&quot; data-video-origin-height=&quot;1700&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/436041161?service=daum_tistory&quot; width=&quot;300&quot; height=&quot;654&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&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;&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;style3&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;size16&quot;&gt;그런데 props로 넘기는 것도 너무 많고 코드가 복잡해서 전역 상태를 사용해볼까 싶다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 번에는 더 깔끔한 코드로 리팩토링을 해서 와보겠다.&amp;nbsp;&lt;/p&gt;</description>
      <category>WEB/재밌어서 만드는 것</category>
      <category>react calendar</category>
      <category>react calendar구현</category>
      <category>react로 달력</category>
      <author>자바칩 프라푸치노</author>
      <guid isPermaLink="true">https://sso-feeling.tistory.com/847</guid>
      <comments>https://sso-feeling.tistory.com/847#entry847comment</comments>
      <pubDate>Fri, 24 Feb 2023 17:03:14 +0900</pubDate>
    </item>
  </channel>
</rss>