<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩 일지</title>
    <link>https://liinye.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 1 Jul 2026 08:06:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>liinyeye</managingEditor>
    <image>
      <title>코딩 일지</title>
      <url>https://tistory1.daumcdn.net/tistory/6888844/attach/6e2312cd141a459a8539a615dae248b1</url>
      <link>https://liinye.tistory.com</link>
    </image>
    <item>
      <title>리액트 성능 최적화 : useCallback, useMemo, Memo</title>
      <link>https://liinye.tistory.com/5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 하다보면 성능 최적화를 의식해 useCallback, useMemo와 Memo를 습관적으로 사용하지만 정작 어떤 차이가 있는지 정확히 알지 못한 채 사용하고 있다는 것을 깨달았다. 그래서 useCallback, useMemo와 Memo 각각의 사용법에 대해 개념부터 다시 제대로 알아보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;useCallback&lt;/h2&gt;
&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;함수의 재생성을 방지하는 React Hook&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트가 리렌더링되더라도 동일한 의존성 배열을 갖는 한, 이전에 생성한 함수를 재사용&lt;/li&gt;
&lt;li&gt;함수가 자식 컴포넌트에 props로 전달될 때 유용. 왜냐면, 새로 생성된 함수는 참조가 바뀌어 자식 컴포넌트가 불필요하게 리렌더링될 수 있기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;어떻게 사용하는지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;컴포넌트의 리랜더링 방지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 function (){} 나 () =&amp;gt; {} 은 항상 다른 함수를 생성한다. 따라서, 여기서 handleSubmit함수를 useCallbakc으로 감싸주지 않는다면 ProductPage 컴포넌트가 리렌더링 될때마다 새로운 함수가 생기게 되어 ShippingForm의 props는 절대 같아질 수 없고 자식컴포넌트의 memo최적화는 동작하지 않게 될 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1735561636638&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useCallback } from 'react';

function ProductPage({ productId, referrer, theme }) {

  // useCallback으로 감싸지 않는다면 theme이 바뀔때마다 다른 함수가 될 것입니다...
  // 따라서, useCallback으로 감싸 React에게 리렌더링 간에 함수를 캐싱하도록 요청합니다...
  const handleSubmit = useCallback((orderDetails) =&amp;gt; {
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails,
    });
  }, [productId, referrer]);  // ...이 의존성이 변경되지 않는 한...
  
  return (
    &amp;lt;div className={theme}&amp;gt;
    {/* ... 그래서 useCallback으로 감싸지 않을 경우, ShippingForm의 props는 같은 값이 아니므로 매번 리렌더링 할 것입니다. */}
      &amp;lt;ShippingForm onSubmit={handleSubmit} /&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;size18&quot;&gt;&lt;b&gt;커스텀훅 최적화하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 훅을 작성하는 경우, 반환하는 모든 함수를 useCallback으로 감싸는 것이 좋다. 이렇게 하면 Hook을 사용하는 컴포넌트가 필요할 때 가지고 있는 코드를 최적화할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1735565841914&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function useRouter() {
  const { dispatch } = useContext(RouterStateContext);

  const navigate = useCallback((url) =&amp;gt; {
    dispatch({ type: 'navigate', url });
  }, [dispatch]);

  const goBack = useCallback(() =&amp;gt; {
    dispatch({ type: 'back' });
  }, [dispatch]);

  return {
    navigate,
    goBack,
  };
}&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;useMemo&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;리랜더링 사이에 계산 결과를 캐싱할 수 있게 해주는 React Hook&lt;/blockquote&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;/li&gt;
&lt;li&gt;초기 렌더링 시, useMemo에서 얻을 수 있는 값은 계산 함수를 호출한 결과값이며, 종속성이 변경되기 전까지 리렌더링 사이의 계산 결과를 캐싱함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;useCallback과 useMemo는 어떤 연관이 있나요?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 훅은 모두 자식 컴포넌트를 최적화할 때 유용하다. 무언가를 전달할 때 memoization(캐싱)을 할 수 있도록 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1735562737186&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useMemo, useCallback } from 'react';

function ProductPage({ productId, referrer }) {
  const product = useData('/product/' + productId);

  const requirements = useMemo(() =&amp;gt; { // 함수를 호출하고 그 결과를 캐싱합니다.
    return computeRequirements(product);
  }, [product]);

  const handleSubmit = useCallback((orderDetails) =&amp;gt; { // 함수 자체를 캐싱합니다.
    post('/product/' + productId + '/buy', {
      referrer,
      orderDetails,
    });
  }, [productId, referrer]);

  return (
    &amp;lt;div className={theme}&amp;gt;
      &amp;lt;ShippingForm requirements={requirements} onSubmit={handleSubmit} /&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;차이점은 &lt;b&gt;무엇을 캐싱&lt;/b&gt;하는지!&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;useMemo는 호출한 함수의 결과값을 캐싱&lt;/b&gt;. 위 예시에서는 computeRequirements(product) 함수 호출 결과를 캐싱해서 product가 변경되지 않는 한 이 결과값이 변경되지 않도록 함. 이것은 불필요하게 ShippingForm을 리렌더링하지 않고 requirements객체를 넘겨줄 수 있도록 해주며, 필요할 때 React는 렌더링 중에 넘겨주었던 함수를 호출하여 결과를 계산함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;useCallback은 함수 자체를 캐싱&lt;/b&gt;. 전달할 함수를 캐싱해서 productId나 referrer이 변하지 않으면 handleSubmit자체가 변하지 않도록 함. 이것은 불필요하게 ShippingForm을 리렌더링하지 않고 handleSubmit함수를 전달할 수 있도록 해줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React.memo&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;React.memo는 props가 변경되지 않았을 때 렌더링을 막아주는 최적화 도구&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 컴포넌트가 렌더링될 때 자식 컴포넌트도 리렌더링되는 상황에서, props가 변하지 않는다면 불필요한 렌더링을 방지. 하지만 props 변경 빈도 확인했을 때 isSelected와 같은 props의 변경 빈도가 높다면, React.memo의 비용이 렌더링 비용보다 클 수 있음.&lt;/p&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;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고 자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리액트 공식 문서&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>React</category>
      <category>리액트</category>
      <category>성능최적화</category>
      <author>liinyeye</author>
      <guid isPermaLink="true">https://liinye.tistory.com/5</guid>
      <comments>https://liinye.tistory.com/5#entry5comment</comments>
      <pubDate>Mon, 30 Dec 2024 22:38:26 +0900</pubDate>
    </item>
    <item>
      <title>기술블로그 이사, velog에서 티스토리로</title>
      <link>https://liinye.tistory.com/4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기술블로그를 처음 작성할 때부터 어떤 플랫폼에 글을 써야할지 고민을 많이 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;길게 고민할 여유는 없어 일단 벨로그로 시작해 몇 달동안 글을 써왔다. 마크다운 문법에는 어느 정도 익숙해졌지만 그와 별개로 여러 가지 불편한 점들이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 벨로그는 플랫폼 자체 유저가 많지 않고, SEO 노출이 잘 되지 않다보니 다른 사람들과 소통한다는 느낌이 잘 들지 않았다. 블로그는 다른 사람들과 소통하는 맛으로 방문자수도 확인하고 소소하게 댓글도 남기고 하는 재미가 있는데, 그런게 부족하다보니 아무래도 동기부여가 덜 됐던 것도 있는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 이미지를 넣을 때마다 아래 설명을 넣을 수 없다는 점이 불편했고 동영상도 매번 gif로 변환해서 삽입해야한다는 점도 좀 불편했다. 이 부분은 왜 개선이 안되는지 모르겠지만...이유가 있겠지..!&lt;/p&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;아무튼 2025년 새로운 마음가짐으로, 티스토리로 돌아와 다시 열심히 글을 써보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 기술 블로그를 보시고 싶은 분들은 아래 링크로 들어가주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@liin/posts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@liin/posts&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <category>Velog</category>
      <category>개발블로그</category>
      <category>기술블로그</category>
      <category>벨로그</category>
      <author>liinyeye</author>
      <guid isPermaLink="true">https://liinye.tistory.com/4</guid>
      <comments>https://liinye.tistory.com/4#entry4comment</comments>
      <pubDate>Mon, 30 Dec 2024 19:03:30 +0900</pubDate>
    </item>
    <item>
      <title>[팀프로젝트] Firebase 활용한 CRUD 문서 작성하기</title>
      <link>https://liinye.tistory.com/3</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 팀프로젝트에서는 CRUD를 구현하고 활용해야했다. 하지만 CRUD에 대해서 처음 들어본 나는 먼저 어떤 개념인지 파악을 하기위해 CRUD가 뭔지 찾아봤다.&lt;/p&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;CRUD 문서란?&lt;/b&gt;&lt;/h3&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CRUD&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;(생성(Create), 읽기(Read), 갱신(Update), 삭제(Delete))&lt;/b&gt;는 저장된 데이터에 대해 작업할 수 있는 방법의 약어입니다. 영속적인 저장소의 4가지 기본 기능에 대한 연상기호입니다. CRUD는 일반적으로 데이터베이스나 데이터 저장소에서 수행되는 작업을 의미하지만, 데이터가 실제로 삭제되지 않지만 상태에 삭제된 것으로 표시되는 일시 삭제와 같은 애플리케이션의 고수준 기능에도 적용될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;출처 : &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/CRUD&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/ko/docs/Glossary/CRUD&lt;/a&gt;&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;CRUD는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;대부분의 컴퓨터 소프트웨어가 가지는 &lt;b&gt;기본적인 데이터 처리 기능&lt;/b&gt;인 &lt;b&gt;Create(생성), Read(읽기), Update(갱신), Delete(삭제)&lt;/b&gt;를 묶어서 일컫는 말이다&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;. 사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1f1f1f; text-align: left;&quot;&gt;&amp;lt;출처 : &lt;a href=&quot;https://ko.wikipedia.org/wiki/CRUD&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.wikipedia.org/wiki/CRUD&lt;/a&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 90px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; background-color: #eaecf0;&quot;&gt;&lt;b&gt;이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; background-color: #eaecf0;&quot;&gt;&lt;b&gt;조작&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; background-color: #eaecf0;&quot;&gt;&lt;b&gt;SQL&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Create&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;INSERT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Read&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;(또는 Retrieve)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;읽기&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;(또는 인출)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;SELECT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Update&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;갱신&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;UPDATE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;Delete&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;(또는 Destroy)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;삭제&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;(또는 파괴)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;&gt;&lt;a href=&quot;https://www.google.com/url?sa=i&amp;amp;url=https%3A%2F%2Fwww.atatus.com%2Fglossary%2Fcrud%2F&amp;amp;psig=AOvVaw2lnCwH_ZQS8xuWJcW4xx93&amp;amp;ust=1713597693411000&amp;amp;source=images&amp;amp;cd=vfe&amp;amp;opi=89978449&amp;amp;ved=0CBIQjRxqFwoTCOCSyYPfzYUDFQAAAAAdAAAAABAK&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQedPi/btsGLJcfpsk/Q8MzRVPcUrD7mOr0E90PoK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQedPi%2FbtsGLJcfpsk%2FQ8MzRVPcUrD7mOr0E90PoK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;640&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;출처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 데이터를 만들고, 읽고, 쓰고 ,삭제하는 기능으로 프로그램을 만드는 데 있어서 꼭 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 팀 소개 페이지에서 어떻게 CRUD를 구현하는가?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 페이지에 댓글을 남길 수 있는 방명록을 활용했다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.93%; height: 130px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5872%; background-color: #eaecf0;&quot;&gt;Creat(생성)&lt;/td&gt;
&lt;td style=&quot;width: 129.888%;&quot;&gt;방명록 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5872%; background-color: #eaecf0;&quot;&gt;Read(읽기)&lt;/td&gt;
&lt;td style=&quot;width: 129.888%;&quot;&gt;firestore에 저장된 방명록 항목 조회&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5872%; background-color: #eaecf0;&quot;&gt;Update(수정)&lt;/td&gt;
&lt;td style=&quot;width: 129.888%;&quot;&gt;등록된 방명록 내용 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.5872%; background-color: #eaecf0;&quot;&gt;Delete(삭제)&lt;/td&gt;
&lt;td style=&quot;width: 129.888%;&quot;&gt;등록된 방명록 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Firebase CRUD 공식 문서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#add_a_document&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Create&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713511571093&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;Cloud Firestore에 데이터 추가 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에 데이터 추가 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다음&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#add_a_document&quot; data-og-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#add_a_document&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#add_a_document&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Cloud Firestore에 데이터 추가 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에 데이터 추가 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다음&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.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;&lt;b&gt;Read&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_a_document&quot;&gt;한 개&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713511622720&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;Cloud Firestore로 데이터 가져오기 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore로 데이터 가져오기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. &quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_a_document&quot; data-og-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_a_document&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_a_document&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Cloud Firestore로 데이터 가져오기 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore로 데이터 가져오기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1;&quot; href=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_multiple_documents_from_a_collection&quot;&gt;여러 개&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713511685398&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;Cloud Firestore로 데이터 가져오기 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore로 데이터 가져오기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. &quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_multiple_documents_from_a_collection&quot; data-og-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_multiple_documents_from_a_collection&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/firestore/query-data/get-data?hl=ko#get_multiple_documents_from_a_collection&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Cloud Firestore로 데이터 가져오기 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore로 데이터 가져오기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.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;&lt;b&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#update-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Update&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713511576467&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;Cloud Firestore에 데이터 추가 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에 데이터 추가 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다음&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#update-data&quot; data-og-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#update-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ko#update-data&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Cloud Firestore에 데이터 추가 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에 데이터 추가 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다음&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.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;&lt;b&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko#delete_documents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Delete&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1713511579894&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;Cloud Firestore에서 데이터 삭제 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에서 데이터 삭제 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다&quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko#delete_documents&quot; data-og-url=&quot;https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko#delete_documents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ko#delete_documents&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Cloud Firestore에서 데이터 삭제 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;5월 14일, Google I/O에서 Firebase를 다시 만나보세요. 지금 등록하기 의견 보내기 Cloud Firestore에서 데이터 삭제 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;firebase.google.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>liinyeye</author>
      <guid isPermaLink="true">https://liinye.tistory.com/3</guid>
      <comments>https://liinye.tistory.com/3#entry3comment</comments>
      <pubDate>Fri, 19 Apr 2024 20:39:40 +0900</pubDate>
    </item>
    <item>
      <title>[팀 프로젝트] html, css, js로 전체 화면 캐러셀 구현하기</title>
      <link>https://liinye.tistory.com/2</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;b&gt;현재 상황&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀과 팀원을 소개하는 미니 프로젝트를 진행 중이다. 레이아웃이 백프로 마음에 들지는 않았지만, 메인 화면 텍스트 레이아웃에 대해서 충분히 고민할 시간은 없어 일단 그대로 진행하기로 결정했다. 일단 내가 맡은 부분은 상세페이지 구현이었는데, 레이아웃까지는 익숙한 코드라 무리없이 잘 만들었지만 아직 자바스크립트가 익숙치 않아 어떻게 시작해야할지 막막했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;메인 페이지 1.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beVgJm/btsGIg8MQZD/IQVK2LwQKlruXYHqHUYFyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beVgJm/btsGIg8MQZD/IQVK2LwQKlruXYHqHUYFyK/img.png&quot; data-alt=&quot;메인 화면 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beVgJm/btsGIg8MQZD/IQVK2LwQKlruXYHqHUYFyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeVgJm%2FbtsGIg8MQZD%2FIQVK2LwQKlruXYHqHUYFyK%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;1440&quot; height=&quot;1024&quot; data-filename=&quot;메인 페이지 1.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메인 화면 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;메인 페이지 2.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1Z5fi/btsGJRmEfjy/rBSoIlEV80arF936qI6q30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1Z5fi/btsGJRmEfjy/rBSoIlEV80arF936qI6q30/img.png&quot; data-alt=&quot;메인 화면 2&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1Z5fi/btsGJRmEfjy/rBSoIlEV80arF936qI6q30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1Z5fi%2FbtsGJRmEfjy%2FrBSoIlEV80arF936qI6q30%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;1440&quot; height=&quot;1024&quot; data-filename=&quot;메인 페이지 2.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메인 화면 2&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;상세 페이지 (팀원 개별 프로필 캐러셀).png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW6x2n/btsGJOQ4k6r/Bxheqq2kHDTvyBXS4EeA1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW6x2n/btsGJOQ4k6r/Bxheqq2kHDTvyBXS4EeA1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW6x2n/btsGJOQ4k6r/Bxheqq2kHDTvyBXS4EeA1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW6x2n%2FbtsGJOQ4k6r%2FBxheqq2kHDTvyBXS4EeA1k%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;1440&quot; height=&quot;1024&quot; data-filename=&quot;상세 페이지 (팀원 개별 프로필 캐러셀).png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1024&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 캐러셀을 처음 구현해보는거라 보통 캐러셀을 구현할 때 이미지 단위로 슬라이드를 넘기는데, 디자인과 기획 상 전체 화면이 넘어가는 방식으로 캐러셀을 구현해야 했다. 처음에는 html 파일을 여러 개를 만들어 버튼을 누르면 다른 html 파일로 넘어가도록 해야하나했는데, 팀원들과 논의 해보니 이미지처럼 div 여러 종류를 만들어 그게 화면에서 슬라이드 되도록 구현하기로 정했다.&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;일단 구글링해서 찾은 기존 캐러셀 구현하는 방식대로 버튼을 누르면 x축으로 화면 너비만큼 이동하게끔 코드를 짜봤는데, 화면 넘어가는게 매끄럽지 않았다. 또한 캐러셀을 넘기면서 캐러셀 순서에 맞게 아이콘이랑 프로필 배경 이미지도 바뀌어야 하는데, 이 부분 코드를 어떻게 동작시켜야할지 난감했다.&lt;/p&gt;
&lt;pre id=&quot;code_1713353133380&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const prevBtn = document.querySelector(&quot;.prev&quot;);
const nextBtn = document.querySelector(&quot;.next&quot;);
const carouselSlide = document.querySelector(&quot;.carousel-slide&quot;);
const carousel = document.querySelectorAll(&quot;.carousel&quot;);

let index = 0;
const itemNumbers = carousel.length;
// 캐러셀 아이템 갯수 지정

function clickPrevBtn(e){
    if (index === 0) {
        return;
    } else if (index -= 1) {
        carouselSlide.style.transform = `translateX(-100vw)`;
    }
}

function clickNextBtn() {
    if (index === itemNumbers - 1) {
        return;
    } else if (index += 1) {
        carouselSlide.style.transform = `translateX(100vw)`;
    }
}

prevBtn.addEventListener(&quot;click&quot;, clickPrevBtn);
nextBtn.addEventListener(&quot;click&quot;, clickNextBtn);&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h3&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;size18&quot;&gt;&lt;b&gt;HTML 코드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(.carousel-box div안의 내용은 너무 길어 생략)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[전체 구조]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼과 캐러셀을 감아주는 .wrapper div&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 앞, 뒤 button &amp;amp; carousel wrapper로서의 div&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;nbsp; carousel을 여러 개 담을 .carousel-container div&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 개별 .carousel-box div&lt;/p&gt;
&lt;pre id=&quot;code_1713351440377&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &amp;lt;body&amp;gt;
    &amp;lt;div class=&quot;wrapper&quot;&amp;gt;
      &amp;lt;button class=&quot;prev&quot; type=&quot;button&quot;&amp;gt;
        &amp;lt;i class=&quot;fa-solid fa-caret-left fa-2x&quot;&amp;gt;&amp;lt;/i&amp;gt;
      &amp;lt;/button&amp;gt;
        &amp;lt;!--Carousel--&amp;gt;
        &amp;lt;div style=&quot;overflow: hidden&quot;&amp;gt;
          &amp;lt;div class=&quot;carousel-container&quot;&amp;gt;
            &amp;lt;!--무한히 움직일 수 있도록 마지막꺼 맨앞으로(편법임)--&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
            &amp;lt;!--무한히 움직일 수 있도록 마지막꺼 맨앞으로(편법임)--&amp;gt;
            &amp;lt;div class=&quot;carousel-box&quot;&amp;gt;&amp;lt;div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;button class=&quot;next&quot; type=&quot;button&quot;&amp;gt;
        &amp;lt;i class=&quot;fa-solid fa-caret-right fa-2x&quot;&amp;gt;&amp;lt;/i&amp;gt;
      &amp;lt;/button&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;size18&quot;&gt;&lt;b&gt;JS 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1713350999344&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;!--Carousel--&amp;gt;
    &amp;lt;script&amp;gt;
      const carousel = document.querySelector(&quot;.carousel-container&quot;);
      const carouselBox = document.querySelectorAll(&quot;.carousel-box&quot;);
      const icons = document.querySelectorAll(&quot;.icons&quot;);
      const icon = document.querySelectorAll(&quot;.icon&quot;);
      const nextBtn = document.querySelector(&quot;.next&quot;);
      const prevBtn = document.querySelector(&quot;.prev&quot;);

      // 원하는 배경색 헥스코드로 넣기
      const myBackGroundColor = [
        &quot;#618a58&quot;, // 홍유나
        &quot;#8fbcdb&quot;, // 이준혁
        &quot;#bba2fe&quot;, // 복예린
        &quot;#e2c881&quot;, // 김승회
        &quot;#288292&quot;, // 채종민
      ];

      let idx = 1;
      //함수에서 인자로 boolean을 사용하기 위해 변수를 지정해준다.
      let isInteraction = false;

      const setTransition = (value) =&amp;gt; {
        carousel.style.transition = value;
      };

      const setTranslate = () =&amp;gt; {
        carousel.style.transform =
          &quot;translateX(&quot; + (-100 / carouselBox.length) * idx + &quot;%)&quot;;
      };

      const setBackGroundColor = () =&amp;gt; {
        const myIcon = icons[idx].getElementsByClassName(&quot;icon&quot;)[idx - 1];
        // const myBgColor = bgColors[idx].getElementsByClassName(&quot;left-left&quot;)[idx - 1];
        // myBgColor.style.backgroundColor = myBackGroundColor[idx - 1];
        myIcon.style.backgroundColor = myBackGroundColor[idx - 1];
        myIcon.style.boxShadow = &quot;0px 0px 10px 5px rgba(0, 0, 0, 0.15)&quot;;
      };

      const interaction = () =&amp;gt; {
        isInteraction = true;
        setTimeout(() =&amp;gt; {
          isInteraction = false;
        }, 600);
      };

      /** 버튼 클릭 시 슬라이드 되는 스타일 변경을 담당 */
      const slide = (idx) =&amp;gt; {
        interaction();
        setTransition(&quot;300ms all ease-in&quot;);

        setTimeout(() =&amp;gt; {
          setTransition(&quot;&quot;);
        }, 300);

        setTranslate();
      };



      const init = () =&amp;gt; {
        setBackGroundColor();
        setTranslate();
      };

      init();

      icon.forEach(icon =&amp;gt; {
        icon.addEventListener(&quot;click&quot;, function(e) {
            let parent = e.currentTarget.parentElement;
            let children = parent.children;
            let index = Array.prototype.indexOf.call(children, e.currentTarget) + 1;
            if(idx !== index){
                idx = index;
                slide(idx);
                setBackGroundColor();
            }
        });
      });

      nextBtn.addEventListener(&quot;click&quot;, () =&amp;gt; {
        if (isInteraction) return;
        if (idx &amp;gt;= carouselBox.length - 1) idx = -1;
        idx++;
        slide(idx);

        if (idx === 6) {
          idx = 1;

          setTransition(&quot;300ms all ease-in&quot;);
          setTimeout(() =&amp;gt; {
            setTransition(&quot;&quot;);
            setTranslate();
          }, 300);
        }
        setBackGroundColor();
      });

      prevBtn.addEventListener(&quot;click&quot;, () =&amp;gt; {
        if (isInteraction) return;
        if (idx &amp;lt;= 0) idx = carouselBox.length;
        idx--;
        slide(idx);

        if (idx === 0) {
          idx = 5;

          setTransition(&quot;300ms all ease-in&quot;);
          setTimeout(() =&amp;gt; {
            setTransition(&quot;&quot;);
            setTranslate();
          }, 300);
        }
        setBackGroundColor();
      });
    &amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;느낀점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;js 동작 코드에서 캐러셀 버튼을 누르면 어떤 변화가 생겨야하는지 대략 이해는 가는데, 아직 화살표 함수와 다양하게 함수를 정의하고 사용하는 방법에 익숙하지 않아 코드를 봐도 어떤 방식으로 돌아가는지 잘 이해가 되지 않았다.&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;일단 자바스크립트 강의 복습이랑 추가로 ES6 강의를 듣고 개념을 이해하는 것부터 더 필요할 것 같다.&lt;/p&gt;</description>
      <category>TIL</category>
      <author>liinyeye</author>
      <guid isPermaLink="true">https://liinye.tistory.com/2</guid>
      <comments>https://liinye.tistory.com/2#entry2comment</comments>
      <pubDate>Wed, 17 Apr 2024 20:59:29 +0900</pubDate>
    </item>
  </channel>
</rss>