<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>young0_0.log</title>
        <link>https://velog.io/</link>
        <description>그냥하기.😎</description>
        <lastBuildDate>Mon, 17 Jun 2024 04:33:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>young0_0.log</title>
            <url>https://velog.velcdn.com/images/young0_0/profile/7bbd2ae4-e2dc-44b1-b2a3-174047c14358/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. young0_0.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/young0_0" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[react] Auto slide 만들기]]></title>
            <link>https://velog.io/@young0_0/react-Auto-slide-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@young0_0/react-Auto-slide-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 17 Jun 2024 04:33:33 GMT</pubDate>
            <description><![CDATA[<h1 id="auto-slide-라이브러리-없이-도전">Auto slide 라이브러리 없이 도전.</h1>
<p><code>~~정답이 아닐수 있음~~</code></p>
<h3 id="원했던-느낌">원했던 느낌</h3>
<p>클릭하면 탭처럼보 보이고, 그냥 있을 경우에는 autoPlay가 되도록 만들고 싶다.</p>
<h2 id="setinterval-활용">setInterval 활용</h2>
<p>아래의 설명은 챗GPT를 활용하여 정리한 내용이다.</p>
<h3 id="setinterval-이란">setInterval 이란?</h3>
<p>setInterval은 일정 시간 간격마다 특정 코드를 반복해서 실행할 수 있게 해주는 함수이다.</p>
<pre><code class="language-js">const intervalId = setInterval(() =&gt; {
  console.log(&#39;2초마다 콘솔이 찍힌다.&#39;);
}, 2000);</code></pre>
<p><strong>clearInterval</strong>
setInterval은 고유한 식별자(ID)를 반환한다. 이 ID는 나중에 clearInterval을 사용하여 해당 인터벌을 중지할 때 사용된다.</p>
<pre><code class="language-js">const intervalId = setInterval(() =&gt; {
  console.log(&#39;This message will be logged every 2 seconds&#39;);
}, 2000);

// 인터벌을 중지하려면 clearInterval을 사용합니다.
clearInterval(intervalId);</code></pre>
<h3 id="react-에서-활용">react 에서 활용</h3>
<p>react 컴포넌트에서는 setInterval을 useEffect 훅 안에서 설정하고, 컴포넌트가 언마운트될 때 이를 정리하는 것이 일반적이다. 이렇게 하면 메모리 누수와 불필요한 상태 업데이트를 방지할 수 있다.</p>
<pre><code class="language-js">  const [activeItem, setActiveItem] = useState(1);

  useEffect(() =&gt; {
    const slider = setInterval(() =&gt; {
      setActiveItem((prevItem) =&gt; {
        const nextItem = prevItem + 1;  // 2초마다 1씩 더한다.
        return nextItem &gt; 3 ? 1 : nextItem; // item이 3 이상이면 다시 1로 돌아 간다. 아니라면 1을 더한다.
      });
    }, 2000);

    // 컴포넌트가 언마운트될 때 인터벌을 중지하여 메모리 누수를 방지한다.
    return () =&gt; clearInterval(slider);
  }, [activeItem]);
</code></pre>
<p><strong>언마운트?</strong>
컴포넌트가 더 이상 화면에 렌더링되지 않고 제거될 때를 의미. 예를 들어, 특정 조건이 변경되어 해당 컴포넌트가 더 이상 필요하지 않게 될 때나, 사용자가 페이지를 이동해서 해당 컴포넌트가 포함된 화면을 떠날 때 발생한다.</p>
<h2 id="전체코드">전체코드</h2>
<pre><code class="language-js">  const [activeItem, setActiveItem] = useState(1);

  const reasonItems = [
    {
      id: 1,
      number: &quot;01&quot;,
      title: &quot;탭1&quot;,
      content: &quot;test1&quot;,
      img: &quot;/img1.jpg&quot;,
    },
    {
      id: 2,
      number: &quot;02&quot;,
      title: &quot;탭2&quot;,
      content: &quot;test2&quot;,
      img: &quot;/img2.jpg&quot;,
    },
    {
      id: 3,
      number: &quot;03&quot;,
      title: &quot;탭3&quot;,
      content: &quot;test3&quot;,
      img: &quot;/img3.jpg&quot;,
    },
  ];

  const activeReasonItem = (id: number) =&gt; {
    setActiveItem(id);
  };


  useEffect(() =&gt; {
    const slider = setInterval(() =&gt; {
      setActiveItem((prevItem) =&gt; {
        const nextItem = prevItem + 1;
        return nextItem &gt; 3 ? 1 : nextItem;
      });
    }, 2000);
    return () =&gt; clearInterval(slider);
  }, [activeItem]);

//탭메뉴
&lt;ul &gt;
  {reasonItems.map(({ number, title, id }) =&gt; (
    &lt;li
    key={id}
    onClick={() =&gt; activeReasonItem(id)}
    className={`${activeItem === id &amp;&amp; `bg-[#3171ef] text-white `}`}&gt;
      &lt;span className=&quot;font-light mr-[2.08vw] 2xl:mr-[40px]&quot;&gt;
      {number}
      &lt;/span&gt;
      {title}
    &lt;/li&gt;
))}
&lt;/ul&gt;

//콘텐츠
  {reasonItems.map(
    ({ number, title, content, img, id }) =&gt;
        activeItem === id &amp;&amp; (
         &lt;div key={id} &gt;
            &lt;span&gt;{number}&lt;/span&gt;
            &lt;h2&gt;{title}&lt;/h2&gt;
            &lt;p&gt;{content}&lt;/p&gt;
            &lt;/div&gt;
            &lt;Image
            src={img}
            alt={title}
            width={460}
            height={400}
          /&gt;
      &lt;/div&gt;
    ))}</code></pre>
<h2 id="완성">완성</h2>
<p>클릭했을 경우에 해당 콘텐츠가 보이고 그냥 있을 경우 2초마다 autoplay가 된다.
<img src="https://velog.velcdn.com/images/young0_0/post/cec7fcee-8c26-413a-9c76-6f7355cdb0d2/image.gif" alt=""></p>
<p>위 내용은 챗지피티 + 예제코드로 간단하게 만든 탭 메뉴입니다.</p>
<p>참고한사항:<a href="https://codesandbox.io/p/sandbox/react-slider-css-autoplay-1gms7?file=%2Fsrc%2FApp.js%3A64%2C13">https://codesandbox.io/p/sandbox/react-slider-css-autoplay-1gms7?file=%2Fsrc%2FApp.js%3A64%2C13</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] NEXTJS Favicon과 Open graph 적용]]></title>
            <link>https://velog.io/@young0_0/TIL-NEXTJS-Favicon%EA%B3%BC-Open-graph-%EC%A0%81%EC%9A%A9</link>
            <guid>https://velog.io/@young0_0/TIL-NEXTJS-Favicon%EA%B3%BC-Open-graph-%EC%A0%81%EC%9A%A9</guid>
            <pubDate>Thu, 07 Mar 2024 09:47:46 GMT</pubDate>
            <description><![CDATA[<h1 id="favicon-과-open-graph">favicon 과 open graph</h1>
<h2 id="favicon-이란">favicon 이란?</h2>
<p><img src="https://velog.velcdn.com/images/young0_0/post/c8ea9cbb-530c-4768-ab41-325ef20d75af/image.png" alt="">
파비콘이란 웹페이지에 접속했을 때, 상단 탭에서 보여지는 아이콘이다.
파비콘은 즐겨찾기에 웹페이지를 등록할 때도 사용되며, 웹 브라우저 주소창에도 보여지게 된다.</p>
<p>주소창에 웹파이트를 소개하는 글자를 읽지 않아도 모양이나 색깔등으로 어떤 웹사이트인지 인식할 수 있도록 하는 것이 파비콘이다.</p>
<blockquote>
<p>크기는 16<em>16 / 32</em>32 /48<em>48 / 646</em>64 픽섹 처럼 정사각형을 유지한다.
파일 형식은 ico, png, svg 파일 형식을 지원한다.</p>
</blockquote>
<h2 id="open-graph">Open graph</h2>
<p><img src="https://velog.velcdn.com/images/young0_0/post/f709517a-8dca-408c-8fc1-0acb6d2a3a41/image.png" alt=""></p>
<p>오픈 그래프란 웹사이트의 링크를 소셜미디어와 같은 다른 플랫폼에 공유할 때 웹사이트에 대한 정보가 정확하고 효율적으로 해당 플랫폼에서 보여질 수 있도록 하기 위해 웹사이트의 제목, 설명, 이미지, 대표 url 주소에 대한 메타정보를 사전에 웹사이트 안에 구성해 놓은 프로토콜을 의미한다.</p>
<blockquote>
<p>오픈그래프 종류
기본</p>
</blockquote>
<ul>
<li>og:title : 웹사이트 제목</li>
<li>og:type : 웹사이트 종류</li>
<li>og:image : 대표이미지</li>
<li>og:url : 웹사이트 정식 url</li>
</ul>
<h1 id="nextjs-에-적용하기">nextjs 에 적용하기</h1>
<p>nextjs 폴더에서 src/app/layout.tsx 파일을 열고</p>
<h2 id="파비콘">파비콘</h2>
<p>icons를 추가 하고, public 폴더에 추가한 favicon 이미지를 경로에 맞게 추가한다.
그후 favicon.ico 를 삭제한다.</p>
<pre><code class="language-js">export const metadata: Metadata = {
  title: &quot;Frontend-developer&quot;,
  description: &quot;프론트엔드 개발자 포트폴리오 입니다.&quot;,
  icons: {
    icon: &quot;/young_favicon.svg&quot;,
  },
};
</code></pre>
<p><img src="https://velog.velcdn.com/images/young0_0/post/30cb1a5e-f208-4121-9de4-9390da9b989e/image.png" alt=""></p>
<h2 id="og-tag-오픈-그래프">og tag (오픈 그래프)</h2>
<p>파비콘 추가한 동일한 layout.tsx 파일에 추가한다.</p>
<pre><code class="language-js">export const metadata: Metadata = {
  title: &quot;Frontend-developer&quot;,
  description: &quot;프론트엔드 개발자 포트폴리오 입니다.&quot;,
  icons: {
    icon: &quot;/young_favicon.svg&quot;,
  },
  openGraph: {
    siteName: &quot;frontend-developer portfolio&quot;,
    title: &quot;youg&#39;s portfolio&quot;,
    description: &quot;프론트엔드자 000의 포트폴리오 입니다.&quot;,
    images: &quot;/opengraph-image.jpg&quot;,
    url: &quot;https://young02-portfolio.vercel.app/&quot;,
  },
};
</code></pre>
<p>이렇게만 추가 하면 아래와 같은 에러가 뜨는데 
<img src="https://velog.velcdn.com/images/young0_0/post/9aa04428-bdbb-4c64-814f-e7ef05af8058/image.png" alt=""></p>
<p>메타데이터에 기본 url을 설정해 주면 해결이 된다.
**  metadataBase: new URL(&quot;<a href="https://young02-portfolio.vercel.app/&quot;">https://young02-portfolio.vercel.app/&quot;</a>),**</p>
<pre><code class="language-js">export const metadata: Metadata = {
  title: &quot;Frontend-developer&quot;,
  description: &quot;프론트엔드 개발자 포트폴리오 입니다.&quot;,
  metadataBase: new URL(&quot;https://young02-portfolio.vercel.app/&quot;),
  icons: {
    icon: &quot;/young_favicon.svg&quot;,
  },
  openGraph: {
    siteName: &quot;frontend-developer portfolio&quot;,
    title: &quot;youg&#39;s portfolio&quot;,
    description: &quot;프론트엔드자 성태영의 포트폴리오 입니다.&quot;,
    images: &quot;/opengraph-image.jpg&quot;,
    url: &quot;https://young02-portfolio.vercel.app/&quot;,
  },
};</code></pre>
<h1 id="확인">확인</h1>
<p>변경된 것을 확인 할 수 있다!
<img src="https://velog.velcdn.com/images/young0_0/post/483a8c76-62f7-4c4f-bb71-0bfd518bd5d8/image.png" alt="">
<img src="https://velog.velcdn.com/images/young0_0/post/5b9c2198-6abd-48bf-92cf-8b592fc5be3e/image.png" alt=""></p>
<p>출처: 
<a href="https://ko.wix.com/blog/post/what-is-favicon-how-to-make">파비콘</a>
<a href="https://www.ktpdigitallife.com/%EC%98%A4%ED%94%88%EA%B7%B8%EB%9E%98%ED%94%84-%EB%9C%BB-%EB%A7%81%ED%81%AC%EC%9D%98-%EB%AF%B8%EB%A6%AC%EB%B3%B4%EA%B8%B0-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%EC%84%B1/">og-tag</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]UTC와 한국표준시(KST)]]></title>
            <link>https://velog.io/@young0_0/TILUTC%EC%99%80-%ED%95%9C%EA%B5%AD%ED%91%9C%EC%A4%80%EC%8B%9CKST</link>
            <guid>https://velog.io/@young0_0/TILUTC%EC%99%80-%ED%95%9C%EA%B5%AD%ED%91%9C%EC%A4%80%EC%8B%9CKST</guid>
            <pubDate>Wed, 22 Nov 2023 09:36:13 GMT</pubDate>
            <description><![CDATA[<h2 id="utc와-한국표준시kst">UTC와 한국표준시(KST)</h2>
<h3 id="utc">UTC</h3>
<p>국제적인 표준 시간의 기준으로 쓰이는 시각</p>
<h3 id="한국표준시kst">한국표준시(KST)</h3>
<p>일본 표준시와 같은 동경 135도를 기준으로 하여 UTC 보다 9시간 빠른 표준시(UTC+9)이다.</p>
<h3 id="글-작성이유">글 작성이유</h3>
<p><img src="https://velog.velcdn.com/images/young0_0/post/3f71746a-17e5-4275-bbea-04d198763aa9/image.png" alt="">
서버에서 날짜 데이터를 전달 받는데 String 값으로 전달 받았다.
날짜 데이터는 UTC를 기준으로 하고 있어 한국시간으로 다시 변경하여 프론트에서 보여지게 해야한다.</p>
<h3 id="해결방법">해결방법</h3>
<ol>
<li>받아오는 string 날짜 데이터를 UTC 시간으로 변경하기 위해 new Date()객체로 변환한다. </li>
<li>UTC로 변경된 날짜에 9시간을 더한다. (1시간은 60분 1분은 60초 이므로 9시간을 밀리초로 변환하려면 9<em>60</em>60*1000을 한다.)</li>
<li>한국표준시로 변경된 날짜를 다시 보여지고자하는 연도,월,일,시간,분,초변환 한다.</li>
</ol>
<pre><code class="language-js">export const formatDate = (utcDateString: string): string =&gt; {
  const utcDate: Date = new Date(utcDateString)
  const kstDate: Date = new Date(utcDate.getTime() + 9 * 60 * 60 * 1000)

  // 한국 시간대에 맞게 날짜 포맷팅
  const yyyy = kstDate.getUTCFullYear()
  const MM = String(kstDate.getUTCMonth() + 1).padStart(2, &quot;0&quot;) // getUTCMonth는 0부터 시작하므로 1을 더합니다.
  const dd = String(kstDate.getUTCDate()).padStart(2, &quot;0&quot;)
  const hh = String(kstDate.getUTCHours()).padStart(2, &quot;0&quot;) // getUTCHours는 이미 UTC+9을 더한 시간을 반환합니다.
  const mm = String(kstDate.getUTCMinutes()).padStart(2, &quot;0&quot;)
  const ss = String(kstDate.getUTCSeconds()).padStart(2, &quot;0&quot;)

  return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] 카테고리 새로고침 시 유지]]></title>
            <link>https://velog.io/@young0_0/react-%EC%B9%B4%ED%85%8C%EA%B3%A0%EB%A6%AC-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8-%EC%8B%9C-%EC%9C%A0%EC%A7%80</link>
            <guid>https://velog.io/@young0_0/react-%EC%B9%B4%ED%85%8C%EA%B3%A0%EB%A6%AC-%EC%83%88%EB%A1%9C%EA%B3%A0%EC%B9%A8-%EC%8B%9C-%EC%9C%A0%EC%A7%80</guid>
            <pubDate>Tue, 17 Oct 2023 07:15:01 GMT</pubDate>
            <description><![CDATA[<h2 id="내가-원했던-기능">내가 원했던 기능</h2>
<p>카테고리를 따로 localstorage 나 sessionstorage 에 저장 하지 않고 새로고침을 하더라도 유지 하고 싶었다.</p>
<h2 id="참고-했던-레퍼런스">참고 했던 레퍼런스</h2>
<p>카테고리의 종류도 다양하고 새로고침을 하였을 때 유지 되며 localstorage 나 sessionstorage 저장하지 않고 리액트로 제작된 페이지를 찾다 보니 인프런과 비슷하다 생각하여 참고 하기로 하였다. 
그런데 이 방법이 정답이 아닐수 있다. 레퍼런스와 비슷해 지기 위해 노력 하였다.
<img src="https://velog.velcdn.com/images/young0_0/post/d544077a-73df-41af-871b-c1939e406bfa/image.gif" alt=""></p>
<h3 id="참고한-이유">참고한 이유</h3>
<ol>
<li>react 프로젝트로 참고 하기 좋았음</li>
<li>localstorage 나 sessionstorage 저장하지 않음</li>
<li>url query를 활용</li>
</ol>
<h2 id="구현">구현</h2>
<h3 id="1-카테고리-ui-구현">1. 카테고리 UI 구현</h3>
<p><img src="https://velog.velcdn.com/images/young0_0/post/6ff147ef-dc2d-4bb2-98ca-83037b547041/image.png" alt=""></p>
<pre><code class="language-js">const [updateData, setUpdateData] = useState&lt;number&gt;(2)
const [view, setView] = useState(false)

const handleUpdateTime = (time: number) =&gt; {
  setUpdateData(time)
  setView((prev) =&gt; !prev)
}

const handleView = () =&gt; {
   setView((prev) =&gt; !prev)
}


 &lt;div className=&quot;relative mb-[16px] flex items-center gap-6&quot;&gt;
   &lt;div className=&quot;inline-flex items-center justify-center gap-[15px]  rounded border-2 border-[#BDBDBD] bg-primary-50 px-4 py-[12px] text-sm drop-shadow-5xl lg:py-[8px] lg:text-xl&quot;&gt;
        &lt;span&gt;{updateData}초&lt;/span&gt;

        &lt;button onClick={handleView} className=&quot;relative h-[9px] w-[19px]&quot;&gt;
          &lt;Image src=&quot;/image/menu-arrow.webp&quot; alt=&quot;arrow&quot; fill className=&quot;absolute&quot; /&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      {view &amp;&amp; (
        &lt;ul className=&quot;absolute top-[100%] z-30 w-[99px] rounded bg-primary-50 text-center text-sm shadow-md lg:right-0 lg:text-xl&quot;&gt;
          {updateTimes.map((item) =&gt; (
            &lt;li key={item.id} onClick={() =&gt; handleUpdateTime(item.time)} className=&quot;py-1&quot;&gt;
              {item.time}초
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
      )}
&lt;/div&gt;</code></pre>
<h3 id="2-해당-카테고리-클릭시-url-query로-저장하기">2. 해당 카테고리 클릭시 url query로 저장하기</h3>
<p><img src="https://velog.velcdn.com/images/young0_0/post/5fd250ea-ce25-41fc-aee3-02c8b1f680e2/image.png" alt=""></p>
<ul>
<li>nextjs를 사용하여 useRouter()을 사용하였다.</li>
<li>router.query에 저장된 times 가져온다.<pre><code class="language-js">const router = useRouter()
const { times } = router.query
</code></pre>
</li>
</ul>
<p>const handleUpdateTime = (time: number) =&gt; {
   setUpdateData(time)
   setView((prev) =&gt; !prev)</p>
<p>  //time을 받아서 url query에 저장한다.
  router.push(<code>/dashboard/${slug}/${valve}?times=${time}</code>)
}</p>
<pre><code>### 3. useEffect로 qeury 불러오기
![](https://velog.velcdn.com/images/young0_0/post/1987d5c8-62ed-4d92-9131-f921e55cbf6b/image.gif)

- query에 저장된 times 가 있으면 UpdateData에 number로 state로 변경해준다.
- 만약 times가 없을 경우 기본 2초로 지정해준다.

```js
useEffect(() =&gt; {
    if (times) {
      setUpdateData(Number(times))
    } else {
      setUpdateData(2)
    }
}, [times])</code></pre><h2 id="결과">결과</h2>
<p>처음엔 useEffect를 하지 않아서 새로고침해서 남지 않았는데 
useEffect로 times가 바뀔때 마다 렌더링 되도록 했더니 성공하였다!
결과가 확실하게 맞는지는 모르지만 내가 원한 대로 되어서 기쁘다! :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테_입문] 문제풀이2]]></title>
            <link>https://velog.io/@young0_0/%EC%BD%94%ED%85%8C%EC%9E%85%EB%AC%B8-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B42</link>
            <guid>https://velog.io/@young0_0/%EC%BD%94%ED%85%8C%EC%9E%85%EB%AC%B8-%EB%AC%B8%EC%A0%9C%ED%92%80%EC%9D%B42</guid>
            <pubDate>Mon, 04 Sep 2023 02:16:20 GMT</pubDate>
            <description><![CDATA[<p>2일차 입문 문제 풀이입니다.
내가 푼 문제와 다른풀이를 비교합니다.</p>
<h2 id="문제-1">문제 1</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120891?language=javascript">https://school.programmers.co.kr/learn/courses/30/lessons/120891?language=javascript</a></p>
<h3 id="나의-풀이">나의 풀이</h3>
<pre><code class="language-js"> function solution(order){
     var answer = 0;
       // 숫자를 문자열로 변경한다.
       const str = String(order)

    // 조건에 맞는지 확인후 맞으면 1개씩 더한다.
    for(let item of str){
           if(item === &#39;3&#39; || item === &#39;6&#39; || item === &#39;9&#39;){
            answer++
        }
    }
 }</code></pre>
<h3 id="다른풀이">다른풀이</h3>
<pre><code class="language-js">let value = order.toString().match(/[369]/g).length ?? []
return value.length</code></pre>
<ul>
<li>문자열로 변환하고 정규식 표현식을 사용하여 해당 값을 찾고 갯수를 반환</li>
<li>null 경우 ??를 활용하여 변경한다.</li>
</ul>
<pre><code class="language-js"> order.toString().split(&#39;&#39;).filter(v =&gt; v == &#39;3&#39; || v == &#39;6&#39; || v== &#39;9&#39; ?true:false)</code></pre>
<ul>
<li><p>숫자 -&gt; 문자열 -&gt; 배열 을 하고 filter를 통해서 해당 조건을 확인하고 length 반환</p>
</li>
<li><p>v =&gt; v == &#39;3&#39; || v == &#39;6&#39; || v== &#39;9&#39; ?true:false 을 new set을 활용</p>
</li>
</ul>
<pre><code class="language-js"> const s = new Set(&#39;369&#39;)
 order.toString().split(&#39;&#39;).filter(v =&gt; s.has(v) ).length</code></pre>
<h2 id="문제-2">문제 2</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120887">https://school.programmers.co.kr/learn/courses/30/lessons/120887</a></p>
<h3 id="내-풀이">내 풀이</h3>
<pre><code class="language-js">function solution(i, j, k) {
    var answer = 0;
    var str = Array(j).fill(1).map((_,indx) =&gt; indx+1 ).slice(i-1).join(&#39;&#39;)
    for(let num of str){
       if(Number(num) === k){
          answer++
       }
    }
    return answer;
}</code></pre>
<ul>
<li>j 갯수만큼 index 순서대로 1~j 만큼 넣는다.</li>
<li>slice로 i의갯수만큼 자른다. </li>
<li>문자열로 만든다.</li>
<li>문자열로 만든 것을 순회하면서 k와 같으면 1씩 더한다. </li>
</ul>
<h3 id="다른풀이-1">다른풀이</h3>
<pre><code class="language-js">function solution(i,j,k){
    let s = &#39;&#39;
    for(i; i &lt;=j; i++){
        s +=i
    }
    return s.split(k).length-1
}</code></pre>
<ul>
<li>i~j 까지 순회하여 문자열로 만든다.</li>
<li>s에 문자열 저장 한 것을 split 으로 k기준 배열을 만들고 갯수를 세면 정답보다 1큰수 이므로 -1 을 해준다.<pre><code class="language-js">function solution(i,j,k){
  return Array(j-i+1).fill(i).map((v,idx)=&gt; v+idx).join(&#39;&#39;).split(k).length-1
}</code></pre>
</li>
<li>Array를 통해 map을 통해 i부터 j까지의 수를 배열로 만든다.</li>
<li>join을 통해 문자열로 만든후 다시 1을 기준으로 split를 통해 k기준으로 배열을 만들고 갯수-1을 하면 해당 답을 리턴한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테_입문] 문제풀이]]></title>
            <link>https://velog.io/@young0_0/%EC%BD%94%ED%85%8C%EC%9E%85%EB%AC%B8-%EC%A7%9D%EC%88%98%EC%9D%98%ED%95%A9</link>
            <guid>https://velog.io/@young0_0/%EC%BD%94%ED%85%8C%EC%9E%85%EB%AC%B8-%EC%A7%9D%EC%88%98%EC%9D%98%ED%95%A9</guid>
            <pubDate>Thu, 31 Aug 2023 05:37:44 GMT</pubDate>
            <description><![CDATA[<p>프로그래밍적 사고를 하기 위해 0단계부터 풀고 다른사람의 풀이를 공부합니다.</p>
<h2 id="문제-1">문제 1.</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120831">https://school.programmers.co.kr/learn/courses/30/lessons/120831</a></p>
<h3 id="내가-푼-풀이">내가 푼 풀이</h3>
<pre><code class="language-js">
function solution(n){
    let answer = 0;
      // 1~n 만큼 반복하며 
      for(let i = 1; i &lt;= n; i++){
          // i를 2로 나눴을 때 0 (짝수) 일경우 한개씩 더한다.
        if(i % 2 ===0){
            answer +=i
        }
    }
}    </code></pre>
<h3 id="다른사람-풀이">다른사람 풀이</h3>
<p>n만큼 배열로 만들어서 짝수를찾아서 더해준다.</p>
<pre><code class="language-js">
function solution (n) {
    return Array(n).fill().map((_,i) =&gt; i+1).filter(v=&gt;v%2 === 0).reduce((a,c)=&gt;a+c,0)
}
</code></pre>
<ul>
<li>Array(n).fill().map((_,i) =&gt; i+1)<ul>
<li>n개 만큼 배열을 만들고 그 배열을 map으로 돌려 i~n번만큼 배열에 넣는다.(_ 는 value 값 활용하지 않을 것이므로 사용)</li>
</ul>
</li>
<li>fillter( v =&gt; v % 2 === 0)<ul>
<li>배열의 value 값에서 2의 짝수만 필터로 구한다.</li>
</ul>
</li>
<li>reduce((a,c)=&gt; a+c)<ul>
<li>reduce로 누산값 과 현재값을 더한다.</li>
<li>빈배열일 경우 초기값을 넣지 않으면 에러가 난다.<h2 id="문제-2">문제 2.</h2>
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/120817">https://school.programmers.co.kr/learn/courses/30/lessons/120817</a></li>
</ul>
</li>
</ul>
<h3 id="내풀이">내풀이</h3>
<pre><code class="language-js">function solution(numbers) {
    var answer = 0;
    numbers.map((val)=&gt; {
        answer +=val/numbers.length
    })
    return answer;
}</code></pre>
<ul>
<li>map으로 전체순회해서 value값을 각각 더하고 numbers의 갯수 를 나눈다.<h3 id="다른-문제-풀이">다른 문제 풀이</h3>
<pre><code class="language-js">function solution(numbers) {    
  return numbers.reduce((a,c) =&gt; a+c,0) / numbers.length
}
</code></pre>
</li>
</ul>
<pre><code>- reduce 를 통해 누산값 + 초기값 더하고 numbers 갯수로 나눈다.
## 문제 3.
https://school.programmers.co.kr/learn/courses/30/lessons/120585

### 문제풀이
```js
function solution(array, height) {
    var answer = 0;
    array.map(n =&gt; {
        if(n &gt; height){
            return answer++
        }
    })
    return answer;
}</code></pre><ul>
<li>배열을 map으로 순회하고 키가 큰 사람을 하나씩 더했다.</li>
</ul>
<h3 id="다른사람-문제풀이">다른사람 문제풀이</h3>
<pre><code class="language-js">function solution(array, height) {
    return array.filter(v=&gt; v &gt; height).length
}</code></pre>
<ul>
<li>filter 로 해당 조건에 맞는 값을 구하고 배열의 길이를 구함</li>
</ul>
<h2 id="문제-4">문제 4.</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120824?language=javascript">https://school.programmers.co.kr/learn/courses/30/lessons/120824?language=javascript</a></p>
<h3 id="내-풀이">내 풀이</h3>
<pre><code class="language-js">    function solution(num_list) {
    var answer = [];
    var odd = 0;
    var even = 0;

    num_list.filter(v =&gt; v % 2 === 0 ? even++ : odd++)
    answer.push(even,odd)
    return answer;
}</code></pre>
<h3 id="다른-풀이">다른 풀이</h3>
<pre><code class="language-js">function solution(num_list) {
  var answer = [0,0];
  for(let num of num_list){
    answer[num %2] += 1
  }
  return answer;
}</code></pre>
<ul>
<li>답의 배열을 첫번째 두번째로 만들고 배열을 돌다가 짝수 와 홀수 인지를 확인하고 
각각 맞다면 answer[0] 이면 짝수 answer[1] 이면 홀수 각각 +1 로 더해서 넣는다. </li>
</ul>
<h2 id="문제5">문제5</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120826?language=javascript">https://school.programmers.co.kr/learn/courses/30/lessons/120826?language=javascript</a></p>
<h3 id="내풀이-1">내풀이</h3>
<pre><code class="language-js">function solution(my_string, letter) {
    var answer = &#39;&#39;;
    for(let i of my_string){
       if(i !== letter){
           answer +=i
       }
    }
    return answer;
}</code></pre>
<ul>
<li>문자열을 for문으로 순회를 돌고 letter과 다른값을 answer에 차례대로 저장</li>
</ul>
<h3 id="다른풀이">다른풀이</h3>
<pre><code class="language-js">function solution(my_string, letter) {
    return my_string.split(letter).join(&#39;&#39;);
}</code></pre>
<ul>
<li>letter 기준으로 배열을 만들면 &#39;&#39;빈 문자열이 나온다.</li>
<li>&#39;&#39;빈문자열 기준으로 다시 문자열로 변경한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react]react-query 정리]]></title>
            <link>https://velog.io/@young0_0/reactreact-query-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@young0_0/reactreact-query-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 28 Jul 2023 03:51:44 GMT</pubDate>
            <description><![CDATA[<h1 id="react-query란">React-query란</h1>
<ul>
<li><code>서버 상태 가져오기</code></li>
<li><code>캐싱</code></li>
<li><code>동기화 및 업데이트</code></li>
</ul>
<p>등 을 쉽게 다룰 수 있도록 도와주는 라이브러리.
클라이언트상태와 서버상태를 명확히 구분하기 위해서 만들어졌다.</p>
<h2 id="react-query의-주요기능">react-query의 주요기능</h2>
<blockquote>
<ol>
<li>캐싱</li>
<li>동일한 데이터 중복 요청을 단일 요청으로 통합</li>
<li>백그라운드에서 오래된 데이터 업데이트</li>
<li>데이터 상태 확인 (오래된 상태, 업데이트상태-빠르게 반영)</li>
<li>페이지네이션, 데이터 지연 로드 와 같은 성능 최적화(페이지네이션,인피니티스크롤)</li>
<li>서버상태의 메모리 및 가비지 수집 관리</li>
<li>구조 공유를 사용하여 쿼리 결과 메모화</li>
</ol>
</blockquote>
<h2 id="기본설정">기본설정</h2>
<pre><code class="language-js">import {QueryClient} from &#39;@tanstack/react-query&#39;

//기본 옵션 
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: Infinity,
      // ...
    },
  },
});

function App() {
  return (
    // react-query연결
   &lt;QueryClientProvider client={queryClient}&gt;
    &lt;App/&gt;
   &lt;/QueryClientProvider&gt;;
  );
}</code></pre>
<ul>
<li>QueryClient를 사용하여 캐시와 상호작용 할수 있다.</li>
<li>QueryClient에서 모든 query/ mutation에 기본 옵션을 추가 할수있다.</li>
<li>QueryClientProvider 를 최상단에 감싸고 client prop으로 QueryClient 인스턴스를 연결 시킨다.(이 context는 앱에서 비동기 요청을 알아서 처리하는 background 계층이된다.) </li>
</ul>
<h2 id="용어-정리">용어 정리</h2>
<blockquote>
<ul>
<li><code>caching</code>: 특정 데이터의 <strong>복사본을 저장</strong>하여 이후 동일한 데이터의 재접근 속도를 높이는 것</li>
</ul>
</blockquote>
<ul>
<li><code>fresh</code> : 새롭게 추가된 쿼리 인스턴스이며 만료되지 않은 쿼리.(컴포넌트가 마운트, 업데이트 되어도 데이터 재요청을 하지 않고 항상 캐시된 데이터를 가져온다.) </li>
<li><code>fetching</code>: 요청 상태인 쿼리 (대기중)</li>
<li><code>stale</code> : 데이터 패칭이 완료되어 만료된 쿼리 (컴포넌트가 마운트, 업데이트 되면 캐시된 데이터가 환횐다.)</li>
<li><code>inactive</code>: 비활성화된 쿼리(5분뒤 가지비 콜렉터가 캐시를 제거한다.)</li>
</ul>
<h2 id="캐싱-라이프-사이클">캐싱 라이프 사이클</h2>
<ol>
<li>A라는 queryKey를 가진 A 쿼리 인스턴스가 mount 됨</li>
<li>네트워크를 통해 데이터를 가져오고(<code>fetch</code>),가져오는 데이터는 A라는 queryKey로 캐싱함</li>
<li>이 데이터는 신선한(<code>fresh</code>) 상태에서 <code>staleTime</code>(기본값 0) 이후 오래된 (<code>stale</code>)상태로 변경됨</li>
<li>A쿼리 인스턴스가 unmout됨</li>
<li>캐시는 <code>cacheTime</code>(기본 5분)만큼 유지하다가 가비지 컬렉션 됨</li>
<li>만약 <code>cacheTime</code>이 지나기전, A 쿼리 인스턴스가 신선한(<code>fresh</code>)상태라면 새롭게 mount 되면 캐시된 데이터 보여줌</li>
</ol>
<h2 id="데이터-갱신">데이터 갱신</h2>
<p>기본값으로 설정된 경우 오래된 쿼리는 자동으로 데이터를 다시 가져온다.</p>
<ul>
<li>쿼리를 사용한 컴포넌트가 마운트 되었을때 (refetchOnMout)</li>
<li>윈도우가 다시 포커스 되었을 때 (refetchOnWindowFocus)</li>
<li>네트워크가 다시 연결되었을 때(refetchOnReconnect)</li>
<li>refetchInterval 설정 하여 반복적으로 refetch 되도록 설정 했을 때<h2 id="usequery-기본-문법">useQuery 기본 문법</h2>
<pre><code class="language-js">// 방법1
const {data,isLoading,...} = useQuery(queryKey,queryFn,{
//options
}
</code></pre>
</li>
</ul>
<p>//방법2
const result = userQuery({
    queryKey,
    queryFn,
    {// option
    }
})
result.data
result.isLoading</p>
<p>// 예제
const getAllSuperHero = async ()=&gt;{
    return await axios.get(&#39;<a href="http://localhost:4000/superheros&#39;">http://localhost:4000/superheros&#39;</a>)
}</p>
<p>const {data, isLoading} = useQuery([&#39;super-heros&#39;],getAllSuperHeor)</p>
<pre><code>### 1. queryKey
```js
 const getSuperHero = async ({queryKey}:any) =&gt;{
   const heroId = queryKey[1]
   return await axios.get(`http://localhost:4000/superheroes/${heroId}`)
 }

 const useSuperHeroData = (heroId:string)=&gt;{
     return useQuery([&#39;super-hero&#39;, heroId] ,getSuperHero)
 }</code></pre><ul>
<li>[&#39;super-heroes&#39;] 배열 지정</li>
<li>querykey 기반으로 데이터를 캐싱 관리한다.<ul>
<li>쿼리가 특정 변수에 의존하면 배열에 이어서 넣어주면 된다. [&#39;super-hero&#39;, heroId]</li>
<li>qeuryClient.setQueryData과 같이 특정 쿼리에 접근이 필요할때 초기에 설정해둔 포맷을 지켜줘야 제대로 쿼리에 접근 할수 있다.</li>
</ul>
</li>
</ul>
<h3 id="2-queryfn">2. queryFn</h3>
<pre><code class="language-js">const getSuperHero = async (heroId: string) =&gt; {
  return await axios.get(`http://localhost:4000/superheroes/${heroId}`);
};

const useSuperHeroData = (heroId: string) =&gt; {
  return useQuery([&quot;super-hero&quot;, heroId], () =&gt; getSuperHero(heroId));
};</code></pre>
<ul>
<li>Promise를 반환하는 함수를 넣어야 한다.</li>
<li>queryKey 와 queryFn 예제의 차이<ul>
<li>queryKey 예제는 2번째 queryFn에 getSuperHero 함수를 바로 넘겨주고, getSuperHero에서 매개 변수로 객체를 받아와 해당 객체의 queryKey를 활용</li>
<li>queryFn 예제는 그냥 2번째 queryFn에 화살표 함수를 사용하고, getSuperHero의 인자로 heroId를 넘겨주고 있다.</li>
</ul>
</li>
</ul>
<h3 id="주요-리턴-데이터">주요 리턴 데이터</h3>
<pre><code class="language-js">const { status, isLoading, isError, error, data, isFetching, ... } = useQuery(
  [&quot;colors&quot;, pageNum],
  () =&gt; fetchColors(pageNum)
);
</code></pre>
<ul>
<li><code>status</code> : 상태를 표현하는 4가지 값<blockquote>
<ul>
<li>idle: 쿼리 데이터가 없고 비었을때 </li>
<li>loading : 캐시된 데이터가 없고 로딩중</li>
<li>error: 요청 에러</li>
<li>success: 요청성공</li>
</ul>
</blockquote>
</li>
<li><code>data</code>: 쿼리 함수가 리턴한 Promise에서 resolve된 데이터</li>
<li><code>isLoading</code>: 캐싱 된 데이터가 없을때, 즉,처음 실행된 쿼리 일때 로딩 여부에 따라 true/false 로 반환</li>
<li><code>isFetching</code>:캐싱 된 데이터가 있더라도 쿼리가 실행되면 로딩 여부에 따라 true/false로 반환된다.</li>
<li><code>error</code>: 쿼리 함수에 오류가 발생한 경우, 쿼리에 대한 오류 객체</li>
<li><code>isError</code> : 에러가 발생한 경우 true</li>
</ul>
<h2 id="주요-옵션">주요 옵션</h2>
<h3 id="retry">retry</h3>
<pre><code class="language-js">const {isLoading, isFetching, data, isError, error} = useQuery([&#39;super-hero&#39;], getSuperHero,{
    retry:10
}</code></pre>
<p>query/mutation 작업이 실패하면 자동으로 재시도를 한다. <strong>Query 기본값은 3번</strong> 이며, <strong>Mutation의 기본값은 0</strong>이다. retryDelay설정을 통해 간격을 설정 할 수 있다.</p>
<ul>
<li>false: 실패한 쿼리는 다시 시도 하지 않는다.</li>
<li>true: 실패한 쿼리를 무한으로 재요청 시도</li>
<li>number: 숫자 만큼 시도<pre><code class="language-js">const {isLoading, isFetching, data, isError, error} = useQuery([&#39;super-hero&#39;], getSuperHero,{
cacheTime: 5*60*1000  
staleTime: 1*60*1000  
}</code></pre>
<h3 id="staletime">staleTime</h3>
데이터가 오래된 것으로 인식하게 되는 시간.(fresh -&gt; stale) ms로 저장되는데 <strong>기본값 은 0</strong> 이며 데이터가 오래 되었다고 판단되면 다시 데이터를 가지고 온다. </li>
<li>fresh 상태일 때는 쿼리 인스턴스가 새롭게 mount 되어도 네트워크 요청(fetch)가 일어 나지 않는다.</li>
<li>0: 데이터를 가져온 즉시 오래된 데이터로 인식하여 캐시 된 데이터를 우선 사용한 후 API를 다시 호출하여 새로운 데이터를 응답 받으면 데이터를 교체한다.</li>
<li>5000 : <ul>
<li>5초 이전 데이터를 요청한 경우: 최신 데이터로 판단하여 API를 다시 호출하지 않고 캐시된 데이터를 사용한다.<ul>
<li>5초 이후 데이터를 요청한 경우 : 캐시 된 데이터를 오래된 데이터로 판단 하여 캐시 된 데이터를 우선 사용한 후, API를 다시 호출하여 새로운 데이터를 응답 받으면 데이터를 교체하고 응답 받은 데이터를 캐시한다.<h3 id="cachetime">cacheTime</h3>
데이터를 얼마나 오랫동안 보관 할 것인지 나타내는 시간. ms단위로 저장되는데 <strong>기본값 은 5분(5 x 60 x 1000)</strong>. 쿼리 인스턴스가 unmount 되면 데이터는 비활성화(inactive) 상태가 되는데, 비활성화 된 데이터는 cacheTime에 설정된 시간이 지난후 가비지 컬렉션이된다.</li>
</ul>
</li>
</ul>
</li>
<li>cacheTime이 지나기 전에 쿼리 인스턴스가 다시 mount되면, 데이터를 fetch하는 동안 캐시 데이터를 보여준다.</li>
<li>5000:<ul>
<li>비활성화 된 데이터를 5초 이전에 요청한 경우: 캐시 된 데이터를 우선 사용한 후 API를 호출하여 새로운 데이터를 응답 받으면 응답 받은 데이터를 다시 캐시한다.</li>
<li>비활성화 된 데이터를 5초 이후에 요청한 경우: 데이터가 이미 가비지 컬렉션 되었기 때문에, 캐시 데이터를 사용하지 못하고 API 응답 데이터를 기다린 후 데이터를 응답 받은 데이터를 사용하고 캐시한다.<h3 id="refetchonmout">refetchOnMout</h3>
<pre><code class="language-js">const {isLoading, isFetching, data, isError, error} = useQuery([&#39;super-hero&#39;],
getSuperHero,{
refetchOnMount: true
}</code></pre>
데이터가 stale 상태일 경우, mount마다 refetch를 실행하는 옵션 <strong>기본값 true</strong></li>
</ul>
</li>
<li>aways : 마운트 시마다 매번 refetch 실행</li>
<li>false : 최초 fetch 이후 refetch 하지 않는다.<h3 id="refetchonwindowfocus">refetchOnWindowFocus</h3>
<pre><code class="language-js">const {isLoading, isFetching, data, isError, error} = useQuery([&#39;super-hero&#39;],
getSuperHero,{
  refetchOnWindowFocus: true
}</code></pre>
데이터가 stale 상태일 경우 윈도우 포커싱 될때마다 refetch 옵션 <strong>기본값 true</strong></li>
<li>aways : 항상 윈도우 포커싱 될 때마다 refetch를 실행한다.<h3 id="polling">Polling</h3>
<pre><code class="language-js">const {isLoading, isFetching, data, isError, error} = useQuery([&#39;super-hero&#39;],
getSuperHero,{
  refetchInterval:2000,
    refetchIntervalInbackground:true
}</code></pre>
리얼타임 웹을 위한 기법으로 일정한 주기(특정시간)를 가지고 서버와 응답을 주고 받는 방식</li>
<li><code>refetchInterval</code>: ms(시간)을 값으로 넣어주면 일정 시간 마다 자동으로 refetch </li>
<li><code>refetchIntervalInBackground</code> : refetchInterval과 함께 사용하는 옵션, 탭/창이 백그라운드에 있는 동안 refetch(브라우저에 focus되지 않아도 refetch 시켜준다.)<h3 id="enabled-refetch">enabled refetch</h3>
<pre><code class="language-js">const {isLoading, isFetching, data, isError, error, refetch} = useQuery([&#39;super-hero&#39;]
,getSuperHero,{
enabled:false
})
</code></pre>
</li>
</ul>
<p>const handleClickRefetch = useCallback(()=&gt;{
refetch()
},[refetch])</p>
<p>return(
    <div>
      {data?.data.map((hero:Data)=&gt;(
          <div key={hero.id}>{hero.name}</div>
    ))}
    <button onClick={handleClickRefetch}>Fetch</button>
      </div>
)</p>
<pre><code>쿼리가 자동으로 실행되지 않도록 할 때 설정. false를 주면 자동으로 실행되지 않는다. useQuery리턴 데이터 중 status가 idle 상태로 시작한다.
- refetch는 쿼리를 수동으로 다시 요청하는 기능이다. 
- 버튼 클릭이나 특정 이벤트를 통해 요청을 시도할 때 같이 사용된다.
- `enabled:false` : queryClient가 쿼리를 다시가져오는 방법 중 invalidateQueries와 refetchQueries를  무시한다.

### select
```js
const { isLoading, isFetching, data, isError, error, refetch } = useQuery(
  [&quot;super-hero&quot;],
  getSuperHero,
  {
    onSuccess,
    onError,
   select(data){
     const superHeroNames = data.data.map((hero:Data)=&gt;hero.name)
     return superHeroNames;
  }
);

return (
  &lt;div&gt;
    &lt;button onClick={handleClickRefetch}&gt;Fetch Heroes&lt;/button&gt;
    {data.map((heroName: string, idx: number) =&gt; (
      &lt;div key={idx}&gt;{heroName}&lt;/div&gt;
    ))}
  &lt;/div&gt;
);</code></pre><p>쿼리 함수에서 반환된 데이터의 일부를 변환하거나 선택할 수 있다.</p>
<h3 id="keeppreviousdata">KeepPreviousData</h3>
<pre><code class="language-js">const fetchColors = async (pageNum:number) =&gt;{
    return await axios.get(`http://localhost:4000/colors_limit=2&amp;_page=${pageNum}`)
}

const {isLoading, isError, error, data, isFetching, isPreviousData}= useQuery([&#39;colors&#39;, pageNum],
                                                                              ()=&gt;fetchColors(pageNum),{
    keepPreviousData: true
})</code></pre>
<ul>
<li>true: 쿼리 키가 변경되어서 새로운 데이터를 요청하는 동안에도 마지막 data값을 유지한다.</li>
<li>페이지네이션 기능을 구현할 때 편리하다. (캐싱되지 않은 페이지를 가져올때 깜빡거리는 현상 방지)</li>
<li>isPreviousData 값으로 현재의 쿼리 키에 해당하는 값인지 확인할 수있다. (아직 새로운 데이터가 캐싱 되지 않았따면, 이전 데이터이므로 true를 반환하고 새로운 데이터가 정상적으로 받아져 왔다면 이전데이터가 아니므로 false 이다.)</li>
</ul>
<h2 id="usequeries">useQueries</h2>
<ul>
<li>병렬쿼리란 동시에 여러 쿼리를 요청하는 방법. (동시성 극대화)<pre><code class="language-JS">const queryResults = useQueries({
queries:[
  {
    querykey: [&#39;super-hero&#39;,1],
    queryFn : () =&gt; fetchSuperHero(1),
    staleTime:Infinity,
  },
{
  querykey:[&#39;super-hero&#39;,2]
  queryFn : () =&gt; fetchSuperHero(2),
  staleTime:0,
 }
]
})
</code></pre>
</li>
</ul>
<pre><code>
## QueryClient
QueryClient 인스턴스는 React query에 유용한 기능을 담고 있다.
```js
import {useQueryClient} from &#39;@tanstak/react-query&#39;

const Todos = ()=&gt;{
    const QueryClient = userQueryClient()
}</code></pre><h3 id="쿼리-무효화-invalidatequeries">쿼리 무효화 (invalidateQueries)</h3>
<p>쿼리를 무효화 하여 데이터를 다시 가져오게 할 수 있다. </p>
<pre><code class="language-js">import {useQueryClient} from &#39;@tanstak/react-query&#39;

const Todos = ()=&gt;{
    const QueryClient = userQueryClient()

    const mutation = useMutation({
      mutationFn : addTodo,
     onSuccess(data) {
      queryClient.invalidateQueries([&quot;todo&quot;]); // 이 key에 해당하는 쿼리가 무효화!
      console.log(data);
    },
    onError(err) {
      console.log(err);
    },
 })
}</code></pre>
<ul>
<li>화면을 최신 상태로 유지하는 가장 간단한 방법</li>
<li>Mutation과 함께 사용 되는 경우 많다.  <h3 id="쿼리-취소">쿼리 취소</h3>
<pre><code class="language-js">const query = useQuery([&quot;super-heroes&quot;], {
/* ...options */
});
</code></pre>
</li>
</ul>
<p>const queryClient = useQueryClient();</p>
<p>const onCancelQuery = (e) =&gt; {
  e.preventDefault();</p>
<p>  queryClient.cancelQueries([&quot;super-heroes&quot;]);
};</p>
<p>return <button onClick={onCancelQuery}>Cancel</button>;</p>
<pre><code>
- 쿼리를 수동으로 취소하고 싶은 경우
    - 요청 시간이 오래 걸리는 경우 사용자가 취소버튼으로 중지하는 경우
    - HTTP 요청이 끝나지 않았을 때, 페이지를 벗어날 경우 불필요한 네트워크 리소스 개선
- queryFn promise도 취소한다.
### 수동 쿼리 업데이트
```js
const queryClient = useQueryClient()

//예제1
useMutation(addSuperHero, {
    onSuccess(data) {
      queryClient.setQueryData([&quot;super-heroes&quot;], (oldData: any) =&gt; {
        return {
          ...oldData,
          data: [...oldData.data, data.data],
        };
      });
    },
    onError(err) {
      console.log(err);
    },
});

//예제2 낙관적 업데이트
useMutation({
  mutaitionFn: uptateTodo,
  onMutate : async(newTodo) =&gt;{
    //optimistic update 한것이 덮어써지지 않도록 쿼리 취소
      await queryClient.cancelQueries({querykey:[&#39;todo&#39;]})
    // 에러 발생시 복원을 위해 기존 데이터 저장
    const previousTodos = queryClient.getQueryData([&#39;todos&#39;])
    //예상되는 변경 값으로 업데이트
    queryClient.setQueryData([&#39;todos&#39;],(old)=&gt;[...old, newTodo])
    return {previousTodos}                        
  },
  // mutation이 실패하면 onMutate에서 반환된 context를 사용하여 롤백 진행
  onError:(err, newTodo, context)=&gt;{
    // context를 통해 기존 값 쿼리 업데이트
        queryClient.setQueryData([&#39;todos&#39;], context.previousTodos)
  }
   // 오류 또는 성공 후에는 항상 리프레쉬
  onSettled:()=&gt;{
    queryClient.invalidateQueries({queryKey:[&#39;todos&#39;]})
 }
})</code></pre><p>때때로 수동으로 쿼리를 업데이트 해 주는 것이 더 좋은 사용성을 제공할 수 있다.
qeuryClient.setQueryData를 사용하면 된다.</p>
<ul>
<li><code>낙관적 업데이트(Optimistic Update)</code>: Mutation으로 상태를 변경후 데이터 노출이 늦어진다면 수동으로 먼저 쿼리를 업데이트 하여 사용자에게 빠르게 변경된 결과를 제공하는 것. (인터넷 속도가 느리거나 서버가 느릴 때이다. 유저가 행한 액션을 기다릴 필요 없이 바로 업데이트되는 것처럼 보이기 때문에 사용자 경험(UX) 측면에서 좋다.)<h3 id="쿼리-미리-가져오기">쿼리 미리 가져오기</h3>
<pre><code class="language-js">const perfetchNextPosts = async (nextPage:number)=&gt;{
  const queryClient = useQueryCleint();
 await queryClient.prefetchQuery(
   [&#39;posts&#39;,nextPage],
   ()=&gt;fetchPost(nextPage),
   {
       //options...
   }
 )
}
</code></pre>
</li>
</ul>
<p>useEffect(()=&gt;{
    const nextPage = currentPage +1
    if(netxtPage &lt; maxPage){
        prefetchNextPosts(nextPage)
    }
},[currentPage])</p>
<pre><code>미래에 사용 될 수 있는 쿼리를 미리 가져올 수 다. `queryClient.prefetchQuery`로 가져오는 데이터가 이미 캐싱되어 있다면 데이터를 가져오지 않는다.
- 미리 가져온 쿼리를 캐시를 해두기 때문에 Query를 통해 데이터를 가져올 때 캐시된 데이터를 사용하여 빠른 결과를 얻을 수 있다,
- ex: 1페이지에서 2페이지로 이동했을 때 3페이지의 데이터를 queryClient.prefetchQuery로 미리 캐시해 둔다면 3페이지로 전환할 때 빠른 결과 값을 가져올 수 있다(페이지네이션 - ux측면에서 좋다.)

## useMutation
```js
const CreateTodo = () =&gt; {
  const mutation = useMutation(createTodo, {
    onMutate() {
      /* ... */
    },
    onSuccess(data) {
      console.log(data);
    },
    onError(err) {
      console.log(err);
    },
    onSettled() {
      /* ... */
    },
  });

  const onCreateTodo = (e) =&gt; {
    e.preventDefault();
    mutation.mutate({ title });
  };

  return &lt;&gt;...&lt;/&gt;;
};</code></pre><ul>
<li>서버의 데이터 post,patch,pus,delete와 같이 수정하고자 할때 사용한다.</li>
<li><code>onMutate</code> :mutation 함수가 실행되기 전에 실행되고, mutation 함수가 받을 동일한변수가 전달된다.</li>
<li><code>onSuccess</code>, <code>onError</code> : 성공시, 실패시</li>
<li><code>onSettled</code> : 성공하든 에러가 발생되든 상관없이 마지막 실행<blockquote>
<p>mutation 과 mutationAsync 차이 (mutation 사용이 좀더 유리함.)</p>
<ul>
<li>mutation : onSuccess,onError,onSettled 와 같은 콜백 함수로 처리 할수 있다.</li>
<li>mutationAsync: Promise 반환하기 때문에 then,Async await로 처리해야 한다.(에러핸들링을 직접 다뤄야 한다.)</li>
</ul>
</blockquote>
</li>
</ul>
<p>참고 
<a href="https://beomy.github.io/tech/react/tanstack-query-v4/#errorboundary">https://beomy.github.io/tech/react/tanstack-query-v4/#errorboundary</a>
<a href="https://github.com/ssi02014/react-query-tutorial#infinite-queries">https://github.com/ssi02014/react-query-tutorial#infinite-queries</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React]프로젝트시 가독성을 위한 컴포넌트 작성법]]></title>
            <link>https://velog.io/@young0_0/React%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%8B%9C-%EA%B0%80%EB%8F%85%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9E%91%EC%84%B1%EB%B2%95</link>
            <guid>https://velog.io/@young0_0/React%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%8B%9C-%EA%B0%80%EB%8F%85%EC%84%B1%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9E%91%EC%84%B1%EB%B2%95</guid>
            <pubDate>Wed, 26 Jul 2023 07:17:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/young0_0/post/c0907559-c168-4513-afef-dac78bf9ce5a/image.png" alt=""></p>
<p>외주 프로젝트를 하면서 코치님께 배운 가독성을 위한 컴포넌트 작성법 정리해 보려고 한다.</p>
<h1 id="작성하게된-계기">작성하게된 계기</h1>
<p>외주 프로젝트를 하면서 내가 짠 코드를 다른 사람이 보면서 이해 할수 있게 짜는 법에 대해 배웠다.
사실 내가 짠 코드도 이게 컴포넌트 인지, 스타일 컴포넌트인지 (styled-components)인지 헷갈릴때가 많았다.
<img src="https://velog.velcdn.com/images/young0_0/post/0d0ee521-3a67-48b3-adfe-e1fdad1cb36d/image.png" alt=""></p>
<p>위 이미지에서 본것 처럼 <code>&lt;StyledDiv&gt;</code>는 style-component 이고 <code>&lt;TodoList&gt;</code>는 그냥 컴포넌트 이다. 지금은 몇줄 안되는 코드 이지만 코드가 길어지고 styled-components가 아래로 밀려나게 된다면 <code>&lt;StyledDiv&gt;</code>가 styled-component 인지 확신이 필요하게 된다.</p>
<h2 id="해결방법">해결방법</h2>
<h3 id="1-폴더파일-분리">1. 폴더/파일 분리</h3>
<p>먼저 폴더를 구분하여 해당 컴포넌트와 스타일컴포넌트를 분리한다.
<img src="https://velog.velcdn.com/images/young0_0/post/c883ffa5-c434-4cd0-a9b6-6447864f4364/image.png" alt=""></p>
<h3 id="2스타일분리">2.스타일분리</h3>
<p>스타일 컴포넌트를 style.ts파일로 분리한다.
<img src="https://velog.velcdn.com/images/young0_0/post/68a7857b-cab2-4b2d-a321-8254ac1a495e/image.png" alt=""></p>
<h3 id="3s-dot-naming-convention">3.S-dot naming convention</h3>
<p>스타일 컴포넌트를 분리할때 S라는 이름으로 요약하여 구분해주는 방식 으로 styled-componets를 가독성있게 볼수 있게 해준다.
<img src="https://velog.velcdn.com/images/young0_0/post/02ad7679-d588-4ffb-afb3-ae19f3435801/image.png" alt=""></p>
<blockquote>
<h3 id="impot-">impot *</h3>
<p>가져올 것이 많으면 <code>import * as &lt;obj&gt;</code> 처럼 객체 형태로 원하는 것들을 가지고 올수 있다.
<strong>as</strong>를 사용하면 이름을 바꿔서 모듈을 가져 올수 있다.</p>
</blockquote>
<h2 id="느낀점">느낀점</h2>
<p>확실히 가독성이 좋아져 코드를 분석하기 좋게되었다! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] selectbox UL 로 만들기]]></title>
            <link>https://velog.io/@young0_0/react-selectbox-UL-%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@young0_0/react-selectbox-UL-%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 30 Jun 2023 03:52:46 GMT</pubDate>
            <description><![CDATA[<h1 id="selectbox-만들기">selectbox 만들기</h1>
<p><img src="https://velog.velcdn.com/images/young0_0/post/01a7086d-15f7-492d-b093-5980bdebd2f8/image.png" alt=""></p>
<p>selet 태그가 아닌 ul로 selectbox 만들어보기.
style은 tailwind 이다.</p>
<h2 id="ui-제작">ui 제작</h2>
<pre><code class="language-jsx"> const dummyData = [
    { feel_id: 1, feel: CategoryEmoji.happy, desc: &#39;행복&#39; },
    { feel_id: 2, feel: CategoryEmoji.sad, desc: &#39;슬픔&#39; },
    { feel_id: 3, feel: CategoryEmoji.calm, desc: &#39;평온&#39; },
    { feel_id: 4, feel: CategoryEmoji.exciting, desc: &#39;신남&#39; },
    { feel_id: 5,feel: CategoryEmoji.depressed,desc: &#39;감동&#39;,isActive: false,},
    { feel_id: 6, feel: CategoryEmoji.angry, desc: &#39;화남&#39;, isActive: false },
  ];

 &lt;ul&gt;
      &lt;li
        key={emoji.feel_id}
        className={[
          &#39;flex cursor-pointer flex-col text-gray  opacity-50 transition-all  delay-300 ease-in-out hover:text-purple hover:opacity-100 &#39;,

        ].join(&#39; &#39;)}
      &gt;
        &lt;span className=&quot;text-2xl&quot;&gt;{emoji.feel}&lt;/span&gt;
        &lt;span className=&quot;mt-1 text-xs&quot;&gt;{emoji.desc}&lt;/span&gt;
      &lt;/li&gt;
 &lt;/ul&gt;</code></pre>
<h2 id="선택했을-경우-선택한-부분만-변하게-하기">선택했을 경우 선택한 부분만 변하게 하기</h2>
<p>여러가지 감정중에 한감정을 선택 했을 경우 opacity:1, color:purple 로 변경</p>
<pre><code class="language-js">const [selectValue, setSelectValue] = useState&lt;number&gt;(1)

// 클릭했을 때 바뀌는 부분
const handleClick = (id:number)=&gt;{
    setSelected(id)
}
&lt;ul&gt;
      &lt;li
        onClick={()=&gt;handleClick(feed_id)}
        key={emoji.feel_id}
        className={[
          &#39;flex cursor-pointer flex-col text-gray  opacity-50 transition-all  delay-300 ease-in-out hover:text-purple hover:opacity-100 &#39;,
        `${
            selectValue === emoji.feel_id
              ? &#39;font-bold text-purple opacity-100&#39;
              : &#39;text-gray&#39;
          } `,
        ].join(&#39; &#39;)}
      &gt;
        &lt;span className=&quot;text-2xl&quot;&gt;{emoji.feel}&lt;/span&gt;
        &lt;span className=&quot;mt-1 text-xs&quot;&gt;{emoji.desc}&lt;/span&gt;
      &lt;/li&gt;
 &lt;/ul&gt;
</code></pre>
<p>각각의 <code>&lt;li&gt;</code>를 클릭했을때 feed_id를 전달 한다.
selectValue가 각각 feed_id와 같으면 opacity:1, color:purple 로 변경한다.</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/513c00aa-92dd-4dc5-a88c-196f644c6220/image.gif" alt=""></p>
<h3 id="느낀점">느낀점</h3>
<p>처음 만들때 true/false로 만들려고 하니 전체적으로 모두가 바뀌는 상황이 발생했다.
각 클릭했을때 각 고유의 값을 전달하면 쉽게 해결될 일이였는데 너무 어렵게 생각 해서 
생각보다 시간이 오래걸렸다. 생각을 좀더 정리하고 코드를 짜는 습관을 만들어야 할것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react + ts] 이미지 미리보기 ]]></title>
            <link>https://velog.io/@young0_0/react-ts-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%AF%B8%EB%A6%AC%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@young0_0/react-ts-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%AF%B8%EB%A6%AC%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Fri, 30 Jun 2023 02:56:41 GMT</pubDate>
            <description><![CDATA[<h1 id="이미지-미리보기-파일-업로드">이미지 미리보기 파일 업로드</h1>
<h2 id="파일-업로드">파일 업로드</h2>
<p>파일을 선택하는 input 창이 안보이게 하고 뒷 배경을 클릭했을 경우 뜨게 하는 방법을 하려고 한다.
css 는 tailwind를 사용 하였다.</p>
<pre><code class="language-jsx">&lt;div className=&quot;relative flex h-full flex-col items-center  justify-center overflow-hidden rounded-2xl bg-beige&quot;&gt;
  &lt;label 
      className=&quot;flex h-full w-full cursor-pointer flex-col items-center justify-center&quot;&gt;
    &lt;span&gt;사진을 추가해 주세요&lt;/span&gt;
    &lt;input  type=&quot;file&quot; accept=&quot;image/*&quot; /&gt;
  &lt;/label&gt;
&lt;/div&gt;</code></pre>
<p>나중에 input file를 안보이게하고 그 부분에 이미지를 업로드 했을경우 클릭했을 때 이미지 업로드 창이 뜨게 하기 위해 label에 전체를 감쌌다.</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/7d23704c-07a4-4295-8db2-cf74ba5142c1/image.png" alt=""></p>
<blockquote>
<p><strong>input file</strong> </p>
</blockquote>
<ul>
<li>저장장치의 파일을 하나 혹은 여러개 선택할수 있다. </li>
<li>File API를 사용해 조작할 수 있다.</li>
<li><code>accept</code>: 허용하는 파일 유형을 나타내는 하나이사의 고유한 파일 유형 지정자</li>
</ul>
<h3 id="이미지-미리보기">이미지 미리보기</h3>
<p>이미지를 업로드 하고 미리 보기 </p>
<pre><code class="language-jsx">//type
export interface EditorDataType {
  file?: string | null;
}

const [editorData, setEditorData] = useState&lt;editorDataType&gt;(null)
const fileRef = useRef&lt;HTMLInputElement&gt;(null);


//이미지 미리보기
const handleUploadFile = () =&gt; {
  const fileImg = fileRef?.current?.files?.[0];
    if (fileImg) {
      const reader = new FileReader();
      reader.readAsDataURL(fileImg);
      reader.onloadend = () =&gt; {
        setEditorData(reader.result as string);
      };
    }
  };

  //이미지 영역
 &lt;div className=&quot;relative flex h-full flex-col items-center  justify-center overflow-hidden rounded-2xl bg-beige&quot;&gt;
    &lt;label
       onChange={handleUploadFile}
       className=&quot;flex h-full w-full cursor-pointer flex-col items-center justify-center&quot;&gt;

         &lt;span className=&quot;mt-2&quot;&gt;사진을 추가 하세요&lt;/span&gt;
      {/* 업로드 된 이미지 */}
         {file &amp;&amp; &lt;img src={file} className=&quot;write-img&quot; /&gt;}
         &lt;input
          className=&quot;hidden&quot;
          type=&quot;file&quot;
           accept=&quot;image/*&quot;
           ref={fileRef}
         /&gt;
   &lt;/label&gt;
&lt;/div&gt; </code></pre>
<h3 id="filereader">FileReader</h3>
<p>File 혹은 Blob 객체를 이용해 파일의 내용을(혹은 raw data버퍼로) 읽고 사용자의 컴퓨터에 저장하는 것을 가능하게 해준다.</p>
<h4 id="filereaderonload">FileReader.onload</h4>
<p>FileReader가 성공적으로 파일을 읽어 들었을 때 의 이벤트 핸들러</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/ef69c01a-9ff3-4a40-bd3f-4b4933bd314a/image.png" alt=""></p>
<h3 id="filereaderreadasdataurl">FileReader.readAsDataURL()</h3>
<p>File 혹은 Blob 을 읽은 뒤 base64로 인코딩한 문자열을 FileReader 인스턴스의 result라는 속성에 담아준다.
이 메서드를 사용해 우리의 이미지를 base64로 인코딩하여 state 안에 넣어준다.</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/40f7fb60-1921-4634-8119-4e747841bd2e/image.gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] head 바꾸기]]></title>
            <link>https://velog.io/@young0_0/react-head-%EB%B0%94%EA%BE%B8%EA%B8%B0</link>
            <guid>https://velog.io/@young0_0/react-head-%EB%B0%94%EA%BE%B8%EA%B8%B0</guid>
            <pubDate>Wed, 28 Jun 2023 12:21:15 GMT</pubDate>
            <description><![CDATA[<h1 id="react-에서-title-바꾸기">react 에서 title 바꾸기</h1>
<p><img src="https://velog.velcdn.com/images/young0_0/post/65a76543-8bec-4060-98d7-508d760b8b21/image.png" alt=""></p>
<h2 id="head">head</h2>
<p>html <code>&lt;title&gt;</code> 요소는 브라우저의 제목 표시줄이나 페이지 탭 보이는 문서 제목을 정의한다.
<code>&lt;head&gt; 안에서 사용해야 한다.</code></p>
<h2 id="사용해야-하는-이유">사용해야 하는 이유</h2>
<h3 id="seo">SEO</h3>
<p>페이지 제목은 SEO(검색엔진)에 큰영향을 준다. 상세한 제목이 더 좋은 검색 결과를 가져온다.
검색엔진이 결과 페이지의 순서를 결정하는 구성 요소 중 하나가 페이지 제목의 내용이다.</p>
<h2 id="react-에서-사용-하는-방법">react 에서 사용 하는 방법</h2>
<h3 id="1-head-tag-안에-title-meta-tag">1. head tag 안에 title, meta tag</h3>
<p>public/index.html 에 <code>&lt;head&gt;</code>태그 안에 홈페이지의 제목을 지정할수 있는 <code>&lt;title&gt;&lt;/title&gt;</code> 와 홈페이지를 설명할수 있는<code>&lt;meta name=&quot;description&quot; content=&quot;~~~&quot;/&gt;</code> 가 있다. 
그 부분을 수정해 주면 된다.</p>
<h3 id="2-각-page의-title-변경하기">2. 각 page의 title 변경하기</h3>
<p>각 page의 title을 수정하기 위해서는  src/pages/Home.js 같이 src/pages의 각 page에 작성하면 된다.</p>
<pre><code class="language-js">useEffect(()=&gt;{
  const titleElement = document.getElementByTagName(&#39;title&#39;)[0]
  title.Element.innerHTML = `my diary`
},[])</code></pre>
<p>index.html의 title 태그를 변경할 수 없으니 react가 마운트 됐을 때 title이라는 태그를 불러온다. title의 배열중 첫번째 title 태그를 가져와서 텍스트를 변경해준다.
각 페이지 마다 변경해주면 페이지를 이동할때 마다 아래와 같이 변경된다.</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/87b7368e-b995-410e-b4a3-70932be15134/image.gif" alt=""></p>
<h3 id="3-favicon-변경">3. favicon 변경</h3>
<p>public/favicon.ico 의 이미지를 favicon.ico 동일한 이름으로 이미지를 변경한다.
favicon을 만들어 주는 방법은 따로 있다!(구글링) 
<img src="https://velog.velcdn.com/images/young0_0/post/7322bebe-1332-4a66-b190-11dd1e0e3ddc/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[web Storage API]]></title>
            <link>https://velog.io/@young0_0/web-Storage-API</link>
            <guid>https://velog.io/@young0_0/web-Storage-API</guid>
            <pubDate>Wed, 28 Jun 2023 05:05:47 GMT</pubDate>
            <description><![CDATA[<h1 id="web-storage-api">web Storage Api</h1>
<p>web storage API는 부라우저에서 키/값 쌍을 쿠키보다 훨씬 직관적으로 저장할수 있는 방법을 제공한다.</p>
<h2 id="web-storage-개념과-사용법">Web Storage 개념과 사용법</h2>
<p>두가지 방식은 다음과 같다.</p>
<h3 id="sessionstorage">sessionStorage</h3>
<ul>
<li>각각의 출저에 대해 동립적인 저장 공간을 페이지 세션이 유지되는 동안 <strong>(브라우저가 열려 있는 동안)</strong> 제공한다.<blockquote>
<ul>
<li>세션에 한정해, 브라우저또는 탭이 닫힐 때 까지만 데이터를 저장한다.</li>
<li>데이터를 절대 서버로 전송하지 않는다.</li>
<li>저장 공간이 쿠키보다 크다 (최대 5MB)    </li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="localstorage">localstorage</h3>
<ul>
<li>브라우저를 닫았다 열어도 데이터가 남았있다.<blockquote>
<ul>
<li>유효기간 없이 데이터를 저장하고, Javasctipt를 사용하거나 브라우저 캐시 또는 로컬 저장 데이터를 지워야만 사라진다.</li>
<li>저장 공간이 셋 중 제일 크다.</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="localstorage-react-예제">localstorage react 예제</h2>
<h3 id="1-localstorage-저장">1. localstorage 저장</h3>
<p>localstorage에 key/value 로 저장한다.</p>
<pre><code class="language-js">  useEffect(()=&gt;{
    localstorage.setItem(&#39;item1&#39;,10) // key:item1, value:number
    localstorage.setItem(&#39;item2&#39;,&#39;10&#39;) // key:item2, value:string
    localstorage.setItem(&#39;item3&#39;,{value:30}) // key:item3, value:object
 },[])</code></pre>
<p>객체로 저장할경우 확인하게 되면 [object Object]로 나타나게 되는데 해결 하기 위해 <strong>JSON.stringify() 메소드로 직렬화(문자 화)</strong> 해줘야 한다.
<img src="https://velog.velcdn.com/images/young0_0/post/8e8600fc-303d-4ca1-aa42-f0e59ebce035/image.png" alt=""></p>
<pre><code class="language-js">  useEffect(()=&gt;{
    localstorage.setItem(&#39;item1&#39;,10) // key:item1, value:number
    localstorage.setItem(&#39;item2&#39;,&#39;10&#39;) // key:item2, value:string
    localstorage.setItem(&#39;item3&#39;,JSON.stringify({value:30})) // key:item3, value:object
 },[])</code></pre>
<p><img src="https://velog.velcdn.com/images/young0_0/post/c9093b66-2108-4ecb-a4bb-e3e5a3cfff9c/image.png" alt=""></p>
<h3 id="2localstorage-저장한-값-꺼내기">2.localstorage 저장한 값 꺼내기</h3>
<p>localstorage에 저장된 key값을 꺼내온다.</p>
<pre><code class="language-js">  useEffect(() =&gt; {
    const item1 = localStorage.getItem(&quot;item1&quot;);
    const item2 = localStorage.getItem(&quot;item2&quot;);
    const item3 = localStorage.getItem(&quot;item3&quot;);

    // 객체로 console.log 찍기
    console.log({ item1, item2, item3 });
  }, []);</code></pre>
<p>item1 은 number로 저장했지만 string 값으로 가져온다. <strong>(기본적으로 localstorage에 들어가는 값들은 string으로 바뀐다.)</strong></p>
<p>그래서 number을 가져올때는 <strong>parseInt()</strong> 메소드를 활용하고
객체는 <strong>JSON.parse()</strong> 메소드를 활용하여 직렬화 한다.
<img src="https://velog.velcdn.com/images/young0_0/post/457a5b73-8390-4de3-b765-5c4014c64797/image.png" alt=""></p>
<pre><code class="language-js">useEffect(() =&gt; {
    const item1 = parseInt(localStorage.getItem(&quot;item1&quot;));
    const item2 = localStorage.getItem(&quot;item2&quot;);
    const item3 = JSON.parse(localStorage.getItem(&quot;item3&quot;));

    console.log({ item1, item2, item3 });
  }, []);
</code></pre>
<p><img src="https://velog.velcdn.com/images/young0_0/post/b285c35e-b2c5-4ffb-8784-8f8cac2d2faf/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[react] img 경로 설정 / 상황에 맞는 className 지정]]></title>
            <link>https://velog.io/@young0_0/react-img-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@young0_0/react-img-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Mon, 26 Jun 2023 05:37:33 GMT</pubDate>
            <description><![CDATA[<h2 id="1public-폴더에서-이미지-가져오기">1.public 폴더에서 이미지 가져오기</h2>
<p><img src="https://velog.velcdn.com/images/young0_0/post/30df9048-8ce8-40ba-a99a-041ba373db6b/image.png" alt=""></p>
<pre><code class="language-js">&lt;img src={process.env.PUBLIC_URL + `/assets/emotion1.png`} alt=&quot;img&quot;/&gt;</code></pre>
<p>process.env.PUBLIC_URL 를 사용하면 어떤 곳에 있던 /public 디렉토리를 가리키게 된다.
public 폴더를 바로 가져올수 있는 명령어 이다.</p>
<h2 id="2상황에-맞는-class명-지정하기">2.상황에 맞는 class명 지정하기</h2>
<p><img src="https://velog.velcdn.com/images/young0_0/post/3f2d1b40-2813-4c8b-b28d-fb97963194bc/image.png" alt="">
className은 배열로 여러가지를 넣을수 있는데 type에 따라 다르게 설정할수 있다.
배열로 클래스 명을 설정하고 사용하기 위해서는 join메소드를 사용하여 string으로 수정해 줘야 한다.</p>
<h3 id="component">component</h3>
<pre><code class="language-js">
const CustomButton = ({text,type, onClick})=&gt;{

  return(    
    &lt;button class={[&#39;CustomButton&#39; ,`CustomButton_${type}`].join(&#39; &#39;)}onClick={onClick}&gt;{text}&lt;/button&gt;
)
}

//type 전달이 없을땐 default를 전달한다.

CustomButton.defaultProps = {
    type:&#39;default&#39;
}
export default CustomButton</code></pre>
<h3 id="css">css</h3>
<pre><code class="language-css">.CustomButton_default {
  background-color: #ececec;
}

.CustomButton_positive {
  background-color: #64c964;
}
.CustomButton_negative {
  background-color: #fd565f;
  color: white;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js]IMAGE]]></title>
            <link>https://velog.io/@young0_0/NextIMAGE</link>
            <guid>https://velog.io/@young0_0/NextIMAGE</guid>
            <pubDate>Mon, 05 Jun 2023 08:21:22 GMT</pubDate>
            <description><![CDATA[<h2 id="lazy">lazy</h2>
<blockquote>
<p><code>&lt;img&gt;</code> 나 <code>&lt;IMAGE&gt;</code> 태그 lazy를 사용하면 해당 태그 영역에서 불러와 네크워크 비용을 줄일수 있다. (이미지를 미리 다운로드 하지 않는다)</p>
</blockquote>
<h2 id="장점">장점</h2>
<h3 id="1-webp-형식으로-변환">1. webp 형식으로 변환</h3>
<p>   <img src="https://velog.velcdn.com/images/young0_0/post/46fc3773-450f-4da1-818d-af2805efd4ac/image.png" alt=""></p>
<ul>
<li><code>&lt;IMAGE&gt;</code>태그를 사용하면 서버에서 이미지 용량 초적화를 해준다.</li>
<li>quality라는 태그를 통해서 최적화를 변경 할수 있다.</li>
</ul>
<h3 id="2-placeholder--blur-로-이미지-최적화">2. placeholder = ‘blur’ 로 이미지 최적화</h3>
<p><img src="https://velog.velcdn.com/images/young0_0/post/5a7d81fc-2c80-4fa9-9133-56be06565b04/image.png" alt=""></p>
<ul>
<li>static한 이미지 이기 때문에 (public)서버에서자동으로 해준다.</li>
</ul>
<h3 id="3-nextimage-외부-에서-받아올때">3. next/image 외부 에서 받아올때</h3>
<ul>
<li>외부에서 받아오는 이미지이기 때문에 width 와 height 를 알지 못해 에러가 날수 있다.- 빌드타임에 미리 최적화 할수 없다. 정적으로 이미지를 제공할 수 없다.<h3 id="4외부링크인터넷이미지이미지를-연결할때">4.외부링크(인터넷이미지)이미지를 연결할때</h3>
</li>
<li>next.config.js</li>
<li>도메인 연결 해준다. / 연결후엔 다시 개발환경을 끄고 다시 실행해야한다.</li>
</ul>
<p><code>images: {
    domains: [&#39;lecture-1.vercel.app&#39;],
}</code></p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/fe16cbb2-35c7-4916-ba1f-3d8b39285a18/image.png" alt=""></p>
<ul>
<li><a href="https://nextjs.org/docs/api-reference/next/image#remote-patterns">https://nextjs.org/docs/api-reference/next/image#remote-patterns</a> (path 네임을 정확하게 하고 싶으면 remote로 한다.)</li>
</ul>
<h3 id="5-이미지-크기-layout-태그">5. 이미지 크기 layout 태그</h3>
<pre><code>&lt;figure&gt;
        &lt;div style={{ width: 500, height: 100, position: &#39;relative&#39; }}&gt;
          &lt;LegacyImage
            src=&quot;https://lecture-1.vercel.app/example.jpg&quot;
            alt=&quot;fill image&quot;
            layout=&quot;fill&quot;
            objectFit=&quot;cover&quot;
          /&gt;
        &lt;/div&gt;
        &lt;figcaption&gt;fill image&lt;/figcaption&gt;
&lt;/figure&gt;</code></pre><h2 id="legacyimage">LegacyImage</h2>
<blockquote>
<p>12버전이며 13에서 의 <code>&lt;IMAGE&gt;</code> 태그와 비슷하지만 다르다.
<code>&lt;LegacyImage&gt;</code> 태그로 하게되면 span 태그 등 가독성과, 웹접근성에 좋지 않다. </p>
</blockquote>
<h3 id="13버전에서-업데이트-된것">13버전에서 업데이트 된것</h3>
<ol>
<li>webp로 용량을 최적화 해줌</li>
<li>blur 이미지를 자동으로 생성해주고</li>
<li>layout shift 를 자동으로 막아주고</li>
<li>lazy loading도 지원해 준다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[로그인 구현]]></title>
            <link>https://velog.io/@young0_0/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@young0_0/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Mon, 05 Jun 2023 08:10:06 GMT</pubDate>
            <description><![CDATA[<h2 id="로그인-구현-과정">로그인 구현 과정</h2>
<h3 id="로그인-시-서버에-바디에-받은-accesstoken을--쿠키에-저장하고-유저-정보는-recoil에-저장한다">로그인 시 서버에 바디에 받은 accessToken을  쿠키에 저장하고 유저 정보는 recoil에 저장한다.</h3>
<pre><code class="language-tsx">const loginMutation = useMutation(
    (data: LoginInfor) =&gt; {
      return axios
        .post(`${process.env.NEXT_PUBLIC_API_KEY}/auth/signin`, data)
        .then((res) =&gt; {
                    const data = res.data;
                    //쿠키에 access 토큰 저장 //7일동안 
          document.cookie = `accessToken=${encodeURIComponent( data.accessToken)}; exprires=${getCookieExpiration(7)}`;
                    //recoil에도 유저 정보를 저장한다.
                    const data = res.data;
          setUserInfor(data);
          return res.data;
        });
    },
  );</code></pre>
<h3 id="getcookieexpiration-함수를-통해-7일간-저장한다">getCookieExpiration 함수를 통해 7일간 저장한다.</h3>
<p><strong><code>getCookieExpiration</code></strong> 함수는 쿠키의 만료 날짜를 계산합니다. 사용자가 입력한 정보를 <strong><code>encodeURIComponent</code></strong> 를 사용하여 인코딩한 후, <strong><code>document.cookie</code></strong>에 문자열 형태로 설정</p>
<p><img src="https://velog.velcdn.com/images/young0_0/post/e9226bd7-d73b-4b42-b59c-770d7882d632/image.png" alt=""></p>
<pre><code class="language-jsx">const getCookieExpiration = (days: number) =&gt; {
    const date = new Date();
    date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
    return date.toUTCString();
};</code></pre>
<h3 id="저장한-유저-정보-활용하기">저장한 유저 정보 활용하기.</h3>
<ol>
<li>리코일에 저장하기</li>
</ol>
<pre><code class="language-jsx">import {atom} from &#39;recoil&#39;
export const userState = atom({
    key: &#39;userState&#39;,
    default:null
})</code></pre>
<ol>
<li>유저 정보 업데이트하기:유저가 로그인 성공하면 userState에 저장한다.</li>
</ol>
<pre><code class="language-jsx">import {userSetRecoilState] from &#39;recoil&#39;

function handleLoginSuccess(userInfo){
    const setUser = useSetRecoilState(userState);
    setUser(userInfo)
}</code></pre>
<ol>
<li>로그인 유저 정보 확인하기: useRecoilValue 훅을 사용하여 userState 값을 가져온다.</li>
</ol>
<pre><code class="language-jsx">import {useRecoilValue} from &#39;recoil&#39;

function UserInfo(){
    const user = useRecoilValue(userState)

    if(user) {
        return &lt;div&gt;로그인 유저 : {user.name}&lt;/div&gt;
    }else{
        return &lt;div&gt; 로그인되지 않음&lt;/div&gt;
    }
}</code></pre>
<h3 id="로그아웃-하면-정보-없애기">로그아웃 하면 정보 없애기</h3>
<pre><code class="language-tsx">const user = useRecoilValue(userInformation);
  const resetUerState = useResetRecoilState(userInformation);
  const [logout, setLogout] = useRecoilState&lt;boolean&gt;(logoutModalState);

  const handleLogout = () =&gt; {
    document.cookie = `accessToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; `;
    //recoil 상태 초기화
        resetUerState();
        //로그아웃 완료팝업
    setLogout((prev: boolean) =&gt; !prev);
  };</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ts] props 에러..]]></title>
            <link>https://velog.io/@young0_0/ts-props-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@young0_0/ts-props-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Sat, 15 Apr 2023 06:10:26 GMT</pubDate>
            <description><![CDATA[<h2 id="원인">원인</h2>
<p><code>LectureItem</code> 컴포넌트에서 <code>data</code> prop을 전달 받는데, <code>LectureDataItem</code> 타입에 <code>data</code>필드가 없기 때문에 발생한 에러.</p>
<h2 id="해결-방법">해결 방법</h2>
<p><code>LectureItem</code> 컴포넌트에서 <code>data</code> prop을 <code>lecture</code>와 같이 <code>LectureDataItem</code>타입에 맞게 필드 이름을 수정하면 된다.</p>
<pre><code class="language-js">interface LectureDataItem {
  id: number;
  course_title: string;
  link: string;
}

// props 에 타입 전달
interface LectureItemProps {
  lecture: LectureDataItem;
}

const LectureItem = ({ lecture }: LectureItemProps) =&gt; {
  return (
    &lt;LectureItemWrapper&gt;
      &lt;LectureItemTitle&gt;{lecture.course_title}&lt;/LectureItemTitle&gt;
      &lt;LectureItemLink href={lecture.link} target=&quot;_blank&quot;&gt;
        보러가기
      &lt;/LectureItemLink&gt;
    &lt;/LectureItemWrapper&gt;
  );
};

const LectureList = () =&gt; (
  &lt;LectureListWrapper&gt;
    {initialData.map((data) =&gt; (
      &lt;LectureItem lecture={data} key={data.id} /&gt;
    ))}
  &lt;/LectureListWrapper&gt;
);</code></pre>
<p><code>LectureItemProps</code> 인터페이스에서 <code>lecture</code>prop의 이름을 <code>data</code> 에서 <code>lecture</code>로 수정하고, <code>LectureItem</code>컴포넌트에서 <code>lecture</code> prop을 사용하도록 변경 해주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[공통 스타일 속성 관리]]></title>
            <link>https://velog.io/@young0_0/%EA%B3%B5%ED%86%B5-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%86%8D%EC%84%B1-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@young0_0/%EA%B3%B5%ED%86%B5-%EC%8A%A4%ED%83%80%EC%9D%BC-%EC%86%8D%EC%84%B1-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Fri, 14 Apr 2023 13:43:21 GMT</pubDate>
            <description><![CDATA[<h3 id="공통-스타일-관리-하는-이유">공통 스타일 관리 하는 이유</h3>
<ul>
<li>매 컴포넌트가 증가함에 따라 스타일 코드의 일관성이 떨어 진다. -&gt; 유지보수 비용의 증가</li>
<li>스타일 속성값들이 중구난방이라 어떤 속성을 갖고 있는지 코드로 확인이 어렵다. -&gt; 협업에서의 문제</li>
<li>스타일마다 다른 속성을 갖고 있어서 재사용이 불가능하다 -&gt; 비효율성 증가</li>
</ul>
<blockquote>
<p>이런 문제점을 styled-components를 사용한다면 contextAPI를 통해 한 번에 해결할 수 있다.</p>
</blockquote>
<h2 id="themeprovider">ThemeProvider</h2>
<p>styled-components는 ThemeProvider 를 통해서 강력한 theming 전략을 제공한다.
<code>context</code>를 사용해서 모든 리액트 컴포넌트에게 theme 속성을 전달하는 역할을 수행한다.</p>
<ol>
<li>App.jsx<pre><code class="language-js">import {ThemeProvider} from &#39;styled-components&#39;
</code></pre>
</li>
</ol>
<p>const theme = {
    color:red
}</p>
<p>const App = () =&gt; {
    return (
        <ThemeProvider them={them}>
            <Test/>
          </ThemeProvider>
    )
}</p>
<pre><code>App 컴포넌트에서 최상단의 태그가 &lt;ThemeProvider&gt; 이므로 하위 자식의 모든 컴포넌트는 &lt;ThemeProvider&gt;의 props로 넘어가는 thme 값을 사용할 수 있게 된다.

2. Test
```js
import styled, {ThemeProvider} from &#39;styled-components&#39;;

  const Button = styled.button`
      background-color : ${(props)=&gt;props.theme.color}
  `

  const Test = () =&gt;{
       return (
          &lt;Button&gt;버튼 테스트&lt;/Button&gt;
      )
  }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[HTML 의 inline 요소와 block 요소의 차이점과 예시]]></title>
            <link>https://velog.io/@young0_0/HTML-%EC%9D%98-inline-%EC%9A%94%EC%86%8C%EC%99%80-block-%EC%9A%94%EC%86%8C%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%EC%98%88%EC%8B%9C</link>
            <guid>https://velog.io/@young0_0/HTML-%EC%9D%98-inline-%EC%9A%94%EC%86%8C%EC%99%80-block-%EC%9A%94%EC%86%8C%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%EC%98%88%EC%8B%9C</guid>
            <pubDate>Fri, 07 Apr 2023 05:55:38 GMT</pubDate>
            <description><![CDATA[<h2 id="inline-요소와-block-요소의-차이점과-예시는">inline 요소와 block 요소의 차이점과 예시는?</h2>
<blockquote>
<p>block 요소는 화면의 한 줄을 전부 차지하는 요소 이고, inline 요소는 요소안에 내용 길이 만크만 너비를 차지 하는 요소 입니다. 
<strong>block 예</strong>
<code>&lt;div&gt;</code>,<code>&lt;p&gt;</code>,<code>&lt;tabale&gt;</code>,<code>&lt;form&gt;</code>,<code>&lt;ul&gt;</code>,<code>&lt;h1&gt;</code> 등
<strong>inline 예</strong>
<code>&lt;span&gt;</code>,<code>&lt;a&gt;</code>,<code>&lt;strong&gt;</code>,<code>&lt;input&gt;</code>,<code>&lt;img&gt;</code> 등</p>
</blockquote>
<h2 id="block과-inline-특징">block과 inline 특징</h2>
<h3 id="inline">inline</h3>
<ul>
<li>width, height 값을 줘도 안먹힌다.</li>
<li>내부에 블럭요소를 포함할수 없다.</li>
<li>인라인 요소를 css로 블럭화 할수 있다. (display:block) 또한 인라인요소와 블럭요소의 속성을 모두 갖는 속성으로 변경이 가능하다. (display:inline-block)</li>
<li>line-height로 줄의 높낮이를 조절할 수있고 text-align 으로 텍스트 중앙, 좌우측 정렬을 할수 있다.<h3 id="block">block</h3>
</li>
<li>width, height 값을 주면 먹는다.</li>
<li>내부에 인라인요소를 포함 할수 있다.</li>
<li>블록요소 다음에는 줄바꿈이 이뤄진다.</li>
<li>블록요소를 인라인 요소의 속성으로 변경 할수 있다. (display:inline),인라인요소와 블럭요소의 속성을 모두 갖는 속성으로 변경이 가능하다. (display:inline-block) </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[<li>요소는 왜 <ul>요소의 자식 요소여야만 하나요?]]></title>
            <link>https://velog.io/@young0_0/li%EC%9A%94%EC%86%8C%EB%8A%94-%EC%99%9C-ul%EC%9A%94%EC%86%8C%EC%9D%98-%EC%9E%90%EC%8B%9D-%EC%9A%94%EC%86%8C%EC%97%AC%EC%95%BC%EB%A7%8C-%ED%95%98%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@young0_0/li%EC%9A%94%EC%86%8C%EB%8A%94-%EC%99%9C-ul%EC%9A%94%EC%86%8C%EC%9D%98-%EC%9E%90%EC%8B%9D-%EC%9A%94%EC%86%8C%EC%97%AC%EC%95%BC%EB%A7%8C-%ED%95%98%EB%82%98%EC%9A%94</guid>
            <pubDate>Fri, 07 Apr 2023 05:03:09 GMT</pubDate>
            <description><![CDATA[<h2 id="li-요소는-왜-ul요소의-자식-요소여야만-하나요">li 요소는 왜 ul요소의 자식 요소여야만 하나요?</h2>
<p>li 요소는 목록 아이템을 보여주기 위한 요소이다.
목록을 담아주는 ul 요소가 필요하며 li 는 자식 요소가 되어야 한다.</p>
<blockquote>
<p>ul요소 없이 사용 하게 되면 화면상 문자는 없지만 시맨틱 구조를 지킴으로써 홈페이지 표준기준을 지키고 그에 따라 다른개발자들과 협업을 하여 코드를 쉽게 이해하고 분석할 수 있게 해준다.</p>
</blockquote>
<h3 id="ul-unorder-list">ul (Unorder List)?</h3>
<blockquote>
<p>순서가 중요하지 않은 목록을 나타낼 때 사용 한다.
점,사각형 등의 도형으로 표시 하며 자식 요소로 li 를 한개 이상 작성해야 한다.</p>
</blockquote>
<p>순서가 바뀌었을때 그 목록의 의미도 바뀌게 된다면 <code>&lt;ol&gt;</code> 태그를 쓰는 것이 바람직 하다.</p>
<h3 id="olorder-list">ol(Order List)?</h3>
<blockquote>
<p>순서가 중요한 목록을 나타낼 때 사용한다.
1,2,3 처럼 차례로 증가하는 번호가 붙는 목록 이며 자식 요소로 li를 한개 이상 작성해야 한다.</p>
</blockquote>
<p><code>&lt;ul&gt;</code> 과 <code>&lt;ol&gt;</code> 의 차이점은 순서의 중요성 이다.</p>
<h3 id="lilist-item">li(List item)?</h3>
<blockquote>
<p>목록 안에 아이템항목 을 나타낸다.</p>
</blockquote>
<h3 id="사용된-예시">사용된 예시</h3>
<p>ul은 보통 네비게이션을 만들 때 <code>&lt;nav&gt;</code> 안에 넣어 사용합니다.
ol은 실시간 검색어, 등 순서가 있는 항목을 제작할때 사용합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux 상태관리의 주요 개념들과 연결 관계]]></title>
            <link>https://velog.io/@young0_0/Redux-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EC%9D%98-%EC%A3%BC%EC%9A%94-%EA%B0%9C%EB%85%90%EB%93%A4%EA%B3%BC-%EC%97%B0%EA%B2%B0-%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@young0_0/Redux-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EC%9D%98-%EC%A3%BC%EC%9A%94-%EA%B0%9C%EB%85%90%EB%93%A4%EA%B3%BC-%EC%97%B0%EA%B2%B0-%EA%B4%80%EA%B3%84</guid>
            <pubDate>Thu, 06 Apr 2023 08:20:41 GMT</pubDate>
            <description><![CDATA[<h2 id="redux-란">redux 란?</h2>
<p>애플리케이션의 상태를 관리하기 위한 견고하고 안정적인 솔루션을 제공한다.</p>
<h2 id="redux가-필요한-이유">redux가 필요한 이유</h2>
<blockquote>
<ul>
<li>자식 컴포넌트 간 직접적인 데이터 전달이 불가능하다</li>
</ul>
</blockquote>
<ul>
<li>자식 컴포넌트가 많아지고 이들 간 데이터 전달이 필요하다면 부모로부터 props 전달이 필요하다</li>
<li>프로젝트가 커지면서 props Driling 이슈가 발생한다.</li>
<li>프로젝트가 커지면서 코드가 복잡하고, 유지 보수의 어려움이 증가한다.</li>
</ul>
<h2 id="redux-세가지-원칙">redux 세가지 원칙</h2>
<h3 id="1-진실은-하나의-근원으로부터">1. 진실은 하나의 근원으로부터</h3>
<ul>
<li>동일한 데이터는 항상 같은 곳에서 가지고 온다.</li>
<li>애플리케이션의 모든 상태는 하나의 저장소 안에 하나의 객체 트리 구조로 저장된다.<h3 id="2-state는-읽기-전용이다">2. state는 읽기 전용이다.</h3>
</li>
<li>리액트에서 setState메소드를 활용해야만 상태 변경이 가능하다</li>
<li>리덕스에서도 액션이라는 객체를 통해서만 상태를 변경할 수 있다.</li>
</ul>
<h3 id="3-변경은-순수함수로-작성되어야한다">3. 변경은 순수함수로 작성되어야한다.</h3>
<ul>
<li>변경은 순수함수로만 가능하다.</li>
<li>리듀서와 연관 되는 개념이다.</li>
<li>store - action - reducer</li>
</ul>
<h2 id="redux-주요-용어">redux 주요 용어</h2>
<p><img src="https://velog.velcdn.com/images/young0_0/post/900c161e-3ffc-4bb8-91c2-6444a06f3cdd/image.png" alt=""></p>
<h3 id="1-스토어-store">1. 스토어 (store)</h3>
<p>애플리케이션의 상태를 관리하고, getState(), dispatch(), subscript 같은 메서드를제공한다.</p>
<h3 id="2-액션-action">2. 액션 (action)</h3>
<p>액션은 애플리케이션에서 상태 변경을 설명하는 정보를 store 로 보내어 변화를 이끌어낸다.</p>
<pre><code class="language-js">const inCreaseCountAction = { type: &quot;INCREASE_COUNT&quot;}</code></pre>
<h3 id="3-리듀서">3. 리듀서</h3>
<p>애플리케이션 상태를 교체하는 함수 이전상태를 새로운 상태로 교체 한다.</p>
<blockquote>
<p>리듀서는 상태와 액션을 전달 받아 새로운 상태 로 교체 반환한다.
주어진 상태를 수정하는 것이 아니라, 새로운 상태로 교체 하는 것이 중요 하다. 
리듀서는 &#39;순수 함수 &#39; 여야한다.</p>
</blockquote>
<pre><code class="language-js">const reducer = (prev = init, action ){
    switch(aciton.type){
      case INCREASE_COUNT:
        return prev + 1
      case DECREASE_COUNT :
        return prev - 1
      default:
        return prev
    }
}</code></pre>
<h2 id="redux-장점">Redux 장점</h2>
<ul>
<li>순수함수를 사용하기 때문에 상태를 예측 가능하게 만든다.</li>
<li>유지보수에 좋다</li>
<li>디버깅에 유리 하다 (redux dev tool)</li>
<li>순수함수를 사용하기 때문에 테스트를 붙이기 용이하다.</li>
</ul>
<p>참고 
<a href="https://hanamon.kr/redux%EB%9E%80-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/">https://hanamon.kr/redux%EB%9E%80-%EB%A6%AC%EB%8D%95%EC%8A%A4-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/</a>
<a href="https://yamoo9.github.io/react-master/lecture/rd-redux.html">https://yamoo9.github.io/react-master/lecture/rd-redux.html</a></p>
]]></description>
        </item>
    </channel>
</rss>