<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dolphin-pc.log</title>
        <link>https://velog.io/</link>
        <description>더 나은 개발경험을 생각하는, 프론트엔드 개발자입니다.</description>
        <lastBuildDate>Sun, 11 Aug 2024 13:10:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dolphin-pc.log</title>
            <url>https://velog.velcdn.com/images/dolphin-pc/profile/c5e41835-d789-4fe6-9e84-07955c3baa79/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dolphin-pc.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dolphin-pc" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[블로그를 이전했습니다!]]></title>
            <link>https://velog.io/@dolphin-pc/%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A5%BC-%EC%9D%B4%EC%A0%84%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@dolphin-pc/%EB%B8%94%EB%A1%9C%EA%B7%B8%EB%A5%BC-%EC%9D%B4%EC%A0%84%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Sun, 11 Aug 2024 13:10:04 GMT</pubDate>
            <description><![CDATA[<h1 id="블로그를-이전했습니다">블로그를 이전했습니다!</h1>
<p><a href="https://dolphin-pc.notion.site/9b914d1523fe4fa9bda697a6254cad49?pvs=4">https://dolphin-pc.notion.site/9b914d1523fe4fa9bda697a6254cad49?pvs=4</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring, 웹소켓 연동]]></title>
            <link>https://velog.io/@dolphin-pc/Spring-%EC%9B%B9%EC%86%8C%EC%BC%93-%EC%97%B0%EB%8F%99</link>
            <guid>https://velog.io/@dolphin-pc/Spring-%EC%9B%B9%EC%86%8C%EC%BC%93-%EC%97%B0%EB%8F%99</guid>
            <pubDate>Wed, 07 Aug 2024 03:51:31 GMT</pubDate>
            <description><![CDATA[<p>Git Issue - <a href="https://github.com/bocho-drive/back/issues/100#issuecomment-2272555503">https://github.com/bocho-drive/back/issues/100#issuecomment-2272555503</a></p>
<hr>
<h1 id="💥-트러블슈팅-웹소켓에서-사용자-정보-불러오기">[💥 트러블슈팅] 웹소켓에서 사용자 정보 불러오기</h1>
<ul>
<li>관련 커밋 : <a href="https://github.com/bocho-drive/back/commit/3861f10194107d6f7a0ef1758d515a7b9ccc59f0">https://github.com/bocho-drive/back/commit/3861f10194107d6f7a0ef1758d515a7b9ccc59f0</a></li>
<li>웹소켓 URL : <code>ws://localhost:8080/api/chat/msg/{chatId}</code></li>
<li>Header : Authorization <code>Bearer ~~</code><h2 id="📌-배경">📌 배경</h2>
</li>
<li>웹소켓 연결 후, 사용자 정보를 불러오기 위해 <code>SecurityContextHolder.getContext().getAuthentication()</code>를 사용하였음</li>
<li>하지만, authentification은 <code>null</code>로 처리가 되고 있어, 이에 대해서 원인을 알아보고자 했다.<ul>
<li><a href="https://velog.io/@kgb/SecurityContextHolder.getContext.getAuthentication%EC%97%90%EC%84%9C-null%EC%9D%B4-%EB%9C%A8%EB%8A%94-%EB%AC%B8%EC%A0%9C">SecurityContextHolder.getContext().getAuthentication()에서 null이 발생하는 문제</a></li>
<li><a href="https://velog.io/@kevin_/Spring-Security-%EC%9D%B8%EC%A6%9D-%EA%B0%9D%EC%B2%B4%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EA%B0%80%EC%A0%B8%EC%98%AC%EB%9E%98">Spring Security 인증 객체를 어떻게 가져올래?</a></li>
<li><a href="https://velog.io/@byeolhaha/%EC%9B%B9%EC%86%8C%EC%BC%93-SeucrityContextHolder%EB%A5%BC-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B3%A0-%EC%8B%B6%EC%9D%80%EB%8D%B0-%EC%99%9C-null%EB%A1%9C-%EA%B2%80%EC%83%89%EB%90%A0%EA%B9%8C">websocket 환경에서의 securitycontextHolder</a></li>
</ul>
</li>
<li>위 글로 도달한 결론은, <strong>Spring의 멀티 Thread환경</strong>으로 인해 <code>SecurityContextHolder의 context</code>가 공유되고 있지 않는다는 것이었다.</li>
</ul>
<h2 id="🎉-해결">🎉 해결</h2>
<ul>
<li><p><strong>Debug모드</strong>로 실행해보니, <code>WebSocketSession</code>객체 안에 유저정보가 담겨있던 것이다..!!!!
<img src="https://velog.velcdn.com/images/dolphin-pc/post/fb29de20-eff6-45ee-94a2-51cf15d55ddd/image.png" alt=""></p>
</li>
<li><p>이를 토대로, session객체에서 유저정보를 가져오는 메소드를 만들었다.</p>
<pre><code class="language-java">  /** 웹소켓 세션에서 사용자 정보를 가져오는 메서드 */
  public CustomUserDetails getUserDetails(WebSocketSession session) {
      Principal principal = session.getPrincipal();
      if (principal instanceof UsernamePasswordAuthenticationToken) {
          UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) principal;
          return (CustomUserDetails) token.getPrincipal();
      }
      return null;
  }</code></pre>
</li>
<li><p>이렇게 구현한 뒤, 채팅 테스트를 위해 postman으로 실행해보았다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/b6aa01fd-4c41-41d9-ae5a-0451d362eba5/image.gif" alt=""></p>
</li>
</ul>
<h2 id="🤔-궁금증">🤔 궁금증</h2>
<h3 id="1-securitycontextholder에-context가-공유되지-않는-구체적인-이유">1. SecurityContextHolder에 context가 공유되지 않는 <strong>구체적인</strong> 이유</h3>
<ul>
<li><code>ws://localhost:8080/api/chat/msg/6</code>로 웹소켓 Connect를 하면, <code>JwtFilter</code>에 도달하여, <code>SecurityContextHolder.setContext(context);</code>가 되는 것을 확인했다.</li>
<li>하지만, <code>ChatWebSocketHandler.java</code>의 <code>afterConnectionEstablished</code>메소드 함수에서 SecurityContextHolder.getContext()가 Null이 되는 이유를 Thread환경이 다르다는 것을 이해했지만, 정확한 원인을 알지 못하였다.<h3 id="2-websocketsession-객체에-사용자-정보가-담길-수-있었던-이유">2. WebSocketSession 객체에 사용자 정보가 담길 수 있었던 이유</h3>
</li>
<li>해결방법 당시, session객체에 사용자 정보가 담겨져 있어 이를 get하여 해결하긴 했다.</li>
<li>하지만, session객체에 사용자 정보가 담길 수 있었던 원인을 제대로 파악하지 못했다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 7주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-7%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-7%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 04 Aug 2024 06:36:00 GMT</pubDate>
            <description><![CDATA[<h1 id="7주차---팀-프로젝트-api연동">7주차 - 팀 프로젝트, API연동</h1>
<h2 id="fact">Fact</h2>
<ul>
<li>UI작업 완성 후, 게시글/댓글 API 연동 작업 진행</li>
<li><a href="https://github.com/orgs/bocho-drive/projects/2/views/1?sliceBy%5Bvalue%5D=2024-07-29">https://github.com/orgs/bocho-drive/projects/2/views/1?sliceBy%5Bvalue%5D=2024-07-29</a></li>
</ul>
<h2 id="feeling--future">Feeling &amp; Future</h2>
<h3 id="컴포넌트의-기준">컴포넌트의 기준</h3>
<ul>
<li>공통 컴포넌트를 개발하던 중, 조건부 Props에 따라 다른 동작을 하려는 컴포넌트를 만들었다.</li>
<li>이에 기술매니저님께 피드백을 받아본 결과, 컴포넌트화 하려는 기준이 약하다는 의견을 듣게 되었다.
<a href="https://github.com/orgs/bocho-drive/projects/2/views/4?pane=issue&amp;itemId=72845899">https://github.com/orgs/bocho-drive/projects/2/views/4?pane=issue&amp;itemId=72845899</a></li>
<li>앞으로는 컴포넌트를 설계하기 위해, ** 하나의 기능만을 수행하는 단일책임적인 원칙을 준수하고 간결한 코드 작성을 지켜가야겠다고 느꼈다. **</li>
</ul>
<h3 id="tanstack-query-mutation">Tanstack Query, mutation</h3>
<ul>
<li>react-query의 mutation 후, setQueryData, invalidateQueries를 수행하여, 새로운 데이터를 불러오기전 낙관적 업데이트 데이터를 보여주려 했다.</li>
<li>이러한 방법에 대해 매니저님께 피드백받은 결과, <strong>데이터 무결성을 생각해야 하는 상황을 지양</strong>해야 한다는 의견을 듣게 되었고, 특수한 상황이 아니라면 <code>refetch</code>를 통해 새로운 데이터를 불러오는 것이 데이터정확성 측면에서 옳은 방법이라고 하셨다.</li>
<li>최적화, 성능적인 측면도 중요하지만, 정확한 데이터를 보여주는 것이 FE개발자로서 더욱 중요한 원칙이라는 것으로 받아들였다.
<a href="https://github.com/orgs/bocho-drive/projects/2/views/4?pane=issue&amp;itemId=72846258">https://github.com/orgs/bocho-drive/projects/2/views/4?pane=issue&amp;itemId=72846258</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 6주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-6%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-6%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 29 Jul 2024 00:41:42 GMT</pubDate>
            <description><![CDATA[<h1 id="6주차---팀-프로젝트-개발시작">6주차 - 팀 프로젝트, 개발시작</h1>
<h2 id="fact">Fact</h2>
<ul>
<li>Github Projects로 개발진행상황 관리<ul>
<li><a href="https://github.com/orgs/bocho-drive/projects/2">https://github.com/orgs/bocho-drive/projects/2</a></li>
</ul>
</li>
</ul>
<h2 id="feeling--future">Feeling &amp; Future</h2>
<ul>
<li>앞으로 진행해야 될 내용들을 <code>issue</code>로 관리하고, Commit시 <code>#이슈번호</code>로 남기는 방식으로 개발을 진행했다.</li>
<li>이렇게 issue와 commit내역을 연동해놓으니, 차후 개발내용과 코드내용을 연결지어 확인할 수 있어 개발추적에 용이했다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 5주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-5%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-5%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 22 Jul 2024 00:02:17 GMT</pubDate>
            <description><![CDATA[<h1 id="5주차---level5완성--팀-프로젝트-시작">5주차 - Level5완성 &amp; 팀 프로젝트 시작</h1>
<h2 id="fact">Fact</h2>
<h3 id="level-5-완성">Level 5 완성</h3>
<p><a href="https://level5-cs-app.vercel.app/">https://level5-cs-app.vercel.app/</a></p>
<h3 id="팀-프로젝트-기획">팀 프로젝트 기획</h3>
<ul>
<li><a href="https://dolphin-pc.notion.site/5b512b8266a24f79ac7eab68b174e282?pvs=4">아이디어 선정 &amp; 유저플로우 분석</a></li>
<li><a href="https://dolphin-pc.notion.site/API-c0124a40d5dc42e2be03dce72bc7ef7a?pvs=4">API/기능 명세서</a></li>
<li><a href="https://dolphin-pc.notion.site/MVP-dc116e43d3c64a579d80145c9f4d9e1f?pvs=4">MVP 구현범위 설정</a></li>
</ul>
<h3 id="feeling">Feeling</h3>
<h3 id="1-제네릭--타입-제한">1. 제네릭 &amp; 타입 제한</h3>
<ul>
<li><p>상황</p>
<ul>
<li><p><strong>addNewCsCard</strong>는 <strong>제네릭 함수</strong>로 <code>T타입</code>을 매개변수로 받을 수 있음</p>
</li>
<li><p>매개변수를 그저 <code>T</code> 라고 선언할 경우, 함수 사용시 <code>어떠한 타입</code>도 들어갈 수 있는 문제 발생</p>
</li>
<li><p>이는 <strong>정적 타이핑</strong>의 장점을 보지 못함</p>
<pre><code class="language-tsx">export const addNewCsCard = async &lt;T&gt;(data:T) {}

// 사용
addNewCsCard&lt;들어가면_안되는_타입&gt;</code></pre>
</li>
<li><p>이를 방지하기 위해, <code>T extends</code> 사용</p>
</li>
</ul>
</li>
</ul>
<ol>
<li>제네릭에서의 <code>extends</code> 는 <strong>제한</strong>의 의미</li>
<li>제네릭 T는 무엇이든지 받을 수 있지만, 그 범위를 제한하려면 extends를 사용하면 됨</li>
</ol>
<p>참고 : <a href="https://inpa.tistory.com/entry/TS-%F0%9F%93%98-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Generic-%ED%83%80%EC%9E%85-%EC%A0%95%EB%B3%B5%ED%95%98%EA%B8%B0">https://inpa.tistory.com/entry/TS-📘-타입스크립트-Generic-타입-정복하기</a></p>
<pre><code class="language-tsx">// 함수 선언
export type NewAuthCardReq = Omit&lt;ICsCard, &quot;id&quot;&gt; &amp; {
  userId: string;
};

export type NewCardReq = Omit&lt;ICsCard, &quot;id&quot;&gt; &amp; {
  password: string;
};

export const addNewCsCard = async &lt;T extends NewAuthCardReq | NewCardReq&gt;(
  data: T
): Promise&lt;ICsCard&gt; =&gt; {
  if (data.password) data.password = encrypt(data.password);

  const res = await api.post&lt;ICsCard&gt;(BASE_URL, data);
  return res.data;
};

// 함수 사용

// 인증사용자의 Card추가
const onAddNewCardAuth = async (data: AuthCardFormSchema): Promise&lt;void&gt; =&gt; {
  if (!userId) return;

  const res = await addNewCsCard&lt;NewAuthCardReq&gt;({ ...data, userId });
  onSuccess(res.id);
};

// 익명사용자의 Card추가
const onAddNewCard = async (data: CardFormSchema): Promise&lt;void&gt; =&gt; {
  const res = await addNewCsCard&lt;NewCardReq&gt;(data);
  onSuccess(res.id);
};</code></pre>
<h3 id="2-zustand---store공통기능-관리">2. zustand - store&amp;공통기능 관리</h3>
<ul>
<li><strong>zustand</strong>로 <strong>global state와 공통기능</strong>을 정의하여, 여러 컴포넌트에서 <strong>재사용&amp;일관된 상태관리</strong>를 할 수 있었음</li>
</ul>
<h3 id="3-react-hook-form--yup">3. react-hook-form &amp; yup</h3>
<ul>
<li>react-hook-form을 사용할 때, 검증기능을 사용하기 위해서는 input에 직접 <code>validation</code>을 붙여줘야 했음</li>
</ul>
<pre><code class="language-tsx">&lt;S.input.Input type=&quot;text&quot; {...register(&quot;title&quot;, {required:true)} /&gt;
{errors.title &amp;&amp; &lt;S.span.ErrorSpan&gt;제목을 입력해주세요.&lt;/S.span.ErrorSpan&gt;</code></pre>
<ul>
<li>이럴 경우, validation의 재사용이 필요할 경우, 모든 input에 찾아가 수정해주어야 하는 문제 생김</li>
</ul>
<h3 id="yup-resolver활용">yup resolver활용</h3>
<pre><code class="language-tsx">// 사용할 schema 정의
import * as yup from &quot;yup&quot;;

const title = yup.string().required(&quot;제목을 입력해주세요.&quot;);
const content = yup.string().required(&quot;내용을 입력해주세요.&quot;);

export const authCardFormSchema = yup.object().shape({
  title,
  content,
});
export type AuthCardFormSchema = yup.InferType&lt;typeof authCardFormSchema&gt;;

// form
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm&lt;AuthCardFormSchema&gt;({
    defaultValues: csCard,
    resolver: yupResolver(authCardFormSchema),
  });

  return (
    &lt;form onSubmit={handleSubmit(onSubmit)}&gt;
      &lt;label htmlFor=&quot;title&quot;&gt;제목&lt;/label&gt;
      &lt;S.input.Input type=&quot;text&quot; {...register(&quot;title&quot;)} /&gt;
      {errors.title &amp;&amp; &lt;S.span.ErrorSpan&gt;{errors.title.message}&lt;/S.span.ErrorSpan&gt;}
      &lt;S.div.Gap $height={20} $width={0} /&gt;

      &lt;label htmlFor=&quot;content&quot;&gt;내용&lt;/label&gt;
      &lt;S.input.TextArea {...register(&quot;content&quot;)} /&gt;
      {errors.content &amp;&amp; &lt;S.span.ErrorSpan&gt;{errors.content.message}&lt;/S.span.ErrorSpan&gt;}
      &lt;S.div.Gap $height={20} $width={0} /&gt;

      &lt;S.button.Button $fullWidth type=&quot;submit&quot;&gt;
        {isEditMode.current ? &quot;작성&quot; : &quot;수정&quot;}
      &lt;/S.button.Button&gt;
    &lt;/form&gt;</code></pre>
<h3 id="4-suspense--usesuspensequery">4. Suspense &amp; useSuspenseQuery</h3>
<ul>
<li>보통 비동기 통신에 의한 렌더링은 <strong>IF 문</strong>을 통한 <code>명령형</code>으로 작성하곤 한다.</li>
<li>이를 <code>선언형</code>으로 변경하기 위해, React.Suspense와 useSuspenseQuery활용<ul>
<li>예전에는, useQuery의 옵션으로 <strong>{suspense:true}</strong>를 줘야 했지만, v5에서는 <strong>useSuspenseQuery</strong>로 따로 함수가 생겨남<pre><code class="language-tsx"></code></pre>
</li>
</ul>
</li>
</ul>
<p>// CardDetailPage.tsx
&lt;Suspense fallback={<LoadingFallbackUI />}&gt;
  <h2>CS카드</h2>
  <CsCardPaper id={Number(id)} />
</Suspense></p>
<p>//CsCardPaper.tsx
const CsCardPaper = ({ id }: { id: number }) =&gt; {
  const { data: card } = useSuspenseQuery({
    queryKey: [&quot;csCards&quot;, id],
    queryFn: ({ queryKey }) =&gt; getCsCardById(queryKey[1] as number),
  });
  return (
    &lt;S.div.Paper&gt;
      &lt;CsCard.Header /&gt;
      {isEditMode ? (
        &lt;CsCard.EditForm /&gt;
      ) : (
        <Fragment>
          <h1>{card.title}</h1>
          <hr />
          <h3>{card.content}</h3>
        </Fragment>
      )}
    &lt;/S.div.Paper&gt;
  );
};</p>
<p>```</p>
<h2 id="feeling--future">Feeling &amp; Future</h2>
<ul>
<li>제네릭을 활용해서 <code>구조적 타이핑</code>의 장점을 얻어갔던 것이 TS를 제대로 사용하는 느낌이 들었다.</li>
<li><code>Yup Resolver</code>를 활용해서 form 검증로직을 하나의 파일에서 관리했던 경험이 좋았다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 4주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-4%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-4%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 14 Jul 2024 12:58:51 GMT</pubDate>
            <description><![CDATA[<h1 id="4주차---주특기-level-45">4주차 - 주특기, level 4/5</h1>
<h2 id="fact">Fact</h2>
<h3 id="level-4---인증인가-활용-🔗">Level 4 - 인증/인가 활용 <a href="https://dolphin-pc.notion.site/React-Lv4-5dd231e762d549b1af21987969c4f387?pvs=4">🔗</a></h3>
<ul>
<li><strong>PrivateRoute</strong>로 인증화면 분기</li>
<li><strong>Mixed Content</strong>, vercel proxy로 해결</li>
</ul>
<h3 id="level-5---나만의-react앱-구현구현중-🔗">Level 5 - 나만의 React앱 구현(구현중... <a href="https://dolphin-pc.notion.site/React-Lv5-e0e2e6aa2bfa4bc4884102d048ee5cfa?pvs=4">🔗</a>)</h3>
<ul>
<li>react-query활용</li>
</ul>
<h2 id="finding">Finding</h2>
<h3 id="💥-mixed-content-해결">💥 Mixed Content 해결</h3>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/d6b2450f-cfbd-415b-96b0-f8986c8a1c3a/image.png" alt=""></p>
<ul>
<li>서비스 배포 후(https적용), http API접근 시 오류 발생</li>
<li>해결을 위해 <code>proxy</code>로 우회하려 했으나, <code>vite.config</code>의 설정은 개발단계에서만 적용됨</li>
<li>운영 서버에서의 우회를 위해, vercel의 서버를 이용한 proxy활용<ul>
<li><code>vercel.json</code>을 작성하면, 경로를 rewrite해준다.<pre><code>// ./vercel.json
{
&quot;rewrites&quot;: [
{
  &quot;source&quot;: &quot;/api/:path*&quot;,
  &quot;destination&quot;: &quot;http://3.38.191.164/:path*&quot;
},
{
  &quot;source&quot;: &quot;/api/:path*/&quot;,
  &quot;destination&quot;: &quot;http://3.38.191.164/:path*/&quot;
},
{ &quot;source&quot;: &quot;/(.*)&quot;, &quot;destination&quot;: &quot;/&quot; }
]
}</code></pre></li>
</ul>
</li>
</ul>
<h3 id="zustand">Zustand</h3>
<ul>
<li>global state와 관련하여 새로운 라이브러리를 검색하다보니, <code>zustand</code>가 괜찮아 보였다.</li>
<li>그 이유로는,<ul>
<li>작은 번들 사이즈</li>
<li>provider 불필요</li>
<li><code>RTK</code>와 같은 state와 action이 모여있는 형태</li>
<li><code>recoil</code>과 같은 <code>use</code>함수의 사용방법</li>
<li><code>redux devtools</code> 사용가능!</li>
</ul>
</li>
</ul>
<h3 id="atomic---props-drilling-보완">Atomic - Props drilling 보완</h3>
<ul>
<li>Atomic 패턴을 활용해 컴포넌트를 쪼개다 보면, 불필요하게 props를 전달해주어야 하는 상황이 발생하게 된다.</li>
<li><code>Props drilling</code>을 보완해줄 수 있는 방법이 있는데, <code>Compound</code>방법이 있다.<h4 id="compound">Compound</h4>
</li>
<li>여러 개의 하위 컴포넌트가 하나의 부모 컴포넌트 안에서 작동하도록 하는 설계 방식이다.<pre><code class="language-tsx">function App() {
return (
  &lt;Tabs&gt;
    &lt;Tab&gt;Tab 1&lt;/Tab&gt;
    &lt;Tab&gt;Tab 2&lt;/Tab&gt;
    &lt;Tab&gt;Tab 3&lt;/Tab&gt;
  &lt;/Tabs&gt;
);
}</code></pre>
</li>
</ul>
<h1 id="feeling--future">Feeling &amp; Future</h1>
<ul>
<li>Recoil, RTK가 state관리에서 주로 사용된다고 생각했지만, <code>큰 번들사이즈</code> <code>늦은 업데이트 주기</code> 등으로 인해 <code>Zustand</code>가 급격하게 인기를 얻고 있는 것 같다.<ul>
<li>앞으로 라이브러리를 선택할 때, 익숙한 것이 아닌 <code>업데이트 주기</code> 등을 고려하여 선택하는 것도 좋은 방법이 될 것 같다.</li>
</ul>
</li>
<li>Atomic패턴 개선<ul>
<li>Atomic패턴을 도입할 때 만해도, 정리가 잘 되어가는 느낌에 <code>이건 최고야..!</code> 라고 느꼈지만, <code>Props drilling</code>, <code>molecules&lt;-&gt;organisms 경계모호</code> 등의 문제를 보며, 좋은 패턴을 도입하더라도, 주관적인 기준을 확립하고 사용할 때 빛을 발하는 것 같다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 3주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-3%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-3%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 07 Jul 2024 12:52:12 GMT</pubDate>
            <description><![CDATA[<h1 id="3주차---주특기-level-123">3주차 - 주특기, level 1/2/3</h1>
<h2 id="fact">Fact</h2>
<ul>
<li>React - <code>redux</code> <code>styled-components</code> <code>react-portal</code></li>
</ul>
<h3 id="level1-🔗">Level1 <a href="https://github.com/Dolphin-PC/level1-my-todo-list">🔗</a></h3>
<ul>
<li>Level1은 useState와 Props만을 이용했기에, 간단하게 구현함<ul>
<li>props전달에 의한 re-render를 최소화하기 위해, useCallback과 React.memo를 활용하여 부모 컴포넌트의 변경에 따른 자식 컴포넌트의 re-render를 방지했다.</li>
<li><code>TodoCard</code>에 전달되는 <strong>onToggleTodo</strong>, <strong>onDeleteTodo</strong>함수를 <code>useCallback</code>으로 메모이제이션하고, <code>React.memo(TodoCard)</code>로 감싸주었다.</li>
</ul>
</li>
</ul>
<h3 id="level2-🔗">Level2 <a href="https://github.com/Dolphin-PC/level2-my-todo-list">🔗</a></h3>
<ul>
<li><p>Level2 - <strong>redux</strong>을 이용한 todo list</p>
<ul>
<li><code>Ducks패턴</code>을 이용한 redux 함수 작성</li>
<li><code>atomic패턴</code>을 이용한 폴더구조 활용</li>
</ul>
<p>📦src
┣ 📂components
┃ ┣ 📂atom
┃ ┃ ┣ 📜Button.tsx
┃ ┃ ┗ 📜Layout.tsx
┃ ┣ 📂molecules
┃ ┃ ┗ 📜TodoCard.tsx
┃ ┣ 📂pages
┃ ┃ ┣ 📜DetailPage.tsx
┃ ┃ ┗ 📜MainPage.tsx
┃ ┗ 📂template
┃ ┃ ┗ 📂TodoForm
┃ ┃ ┃ ┣ 📜TodoForm.tsx
┃ ┃ ┃ ┗ 📜index.ts</p>
</li>
</ul>
<h3 id="level3-🔗">Level3 <a href="https://github.com/Dolphin-PC/level3-components">🔗</a></h3>
<ul>
<li><p><strong>styled-components</strong>를 이용한 Input, Button, Modal, Select컴포넌트 구현</p>
<ul>
<li><p><code>atomic</code>패턴의 컴포넌트 설계</p>
</li>
<li><p><code>S-Dot</code>, <code>$prefix</code>를 통한 styled-component 설계</p>
<p>  📦src
   ┣ 📂assets
   ┣ 📂components
   ┃ ┣ 📂atom
   ┃ ┣ 📂molecules
   ┃ ┗ 📂template
   ┣ 📂styles
   ┃ ┣ 📜button.style.ts
   ┃ ┣ 📜index.style.ts
   ┃ ┣ 📜input.style.ts
   ┃ ┣ 📜row.style.ts
   ┃ ┗ 📜select.style.ts
   ┣ 📂util</p>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/fa85c18f-80a3-4d7c-be42-713572a0b2e2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/85b11c47-0b49-4816-bdea-e82be88e1515/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/b98b52ee-562d-47d7-a899-27519a89f7bd/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h2 id="finding">Finding</h2>
<ul>
<li><code>Ducks</code>패턴을 통한, 코드의 관심사 집중방법</li>
<li><code>Atomic</code>패턴을 통한, 컴포넌트 재사용 방법</li>
<li><code>styled-component</code>의 Props를 통한 컴포넌트 재사용 방법</li>
</ul>
<h2 id="feeling--future">Feeling &amp; Future</h2>
<ul>
<li><code>Ducks</code>, <code>Atomic</code> 패턴의 적용으로 코드의 규칙성을 부여하여, 코드가 급격하게 복잡해지는 문제를 방지할 수 있어, 디자인 패턴의 중요성을 깨닫게 되었다.</li>
<li><code>styled-component</code>로 Designed컴포넌트를 재사용하기 좋았다.<ul>
<li>tailwind로 Designed컴포넌트를 공통화할 경우, props 전달로 인해 조합 사용이 좋지 못했다. <a href="https://github.com/Dolphin-PC/level1-my-todo-list/issues/1">🔗</a></li>
</ul>
</li>
<li>다양한 <code>디자인 패턴</code>을 알고 많은 <code>라이브러리</code>를 사용해보고 장단점을 알고 있는 것이, 앞으로 프로젝트 상황에 적합한 기술/패턴을 도입하는 데 유용할 것 같다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 2주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-2%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-2%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 30 Jun 2024 11:34:15 GMT</pubDate>
            <description><![CDATA[<h1 id="2주차---알고리즘-및-주특기-시작">2주차 - 알고리즘 및 주특기 시작</h1>
<h2 id="fact">Fact</h2>
<ul>
<li>팀원간의 페어프로그래밍을 통한 알고리즘 문제 코드 리뷰</li>
<li>React 강의 시작 및 First 개인과제 시작</li>
</ul>
<h2 id="feeling">Feeling</h2>
<ul>
<li>코딩테스트 문제들은 프로그래머스 Lv 0-1수준이라 쉽게 넘겼다.</li>
<li>페어프로그래밍을 통해 다른 팀원의 코드를 보며, 다른 방식으로 풀 수 있다는 것을 보기도 했고, 내가 작성한 코드를 하나씩 설명하면서 정리가 될 수 있었다.</li>
</ul>
<h2 id="finding">Finding</h2>
<ul>
<li>페어 프로그래밍에서 얻을 수 있는 장점은 2가지 인 것 같다.<ol>
<li>다른 사람의 색다른 생각</li>
<li>내가 짠 코드를 설명하면서 정리해 볼 수 있는 기회</li>
</ol>
</li>
<li>하지만, 팀원간의 기량 차이가 크다면, <code>2번</code>밖에 얻을 수 없었다.</li>
</ul>
<h2 id="future">Future</h2>
<ul>
<li>새로 깨닫거나 배운 것은 없었던 것 같다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 1주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-1%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-1%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Sun, 23 Jun 2024 12:35:36 GMT</pubDate>
            <description><![CDATA[<h1 id="1주차---js기초-주간">1주차 - JS기초 주간</h1>
<h2 id="fact">Fact</h2>
<h4 id="이번주에-한-일">이번주에 한 일</h4>
<ol>
<li>JS강의 복습</li>
<li>야구게임 구현</li>
<li>(IT공채 지원서작성...)</li>
</ol>
<h2 id="feeling">Feeling</h2>
<h4 id="느낌">느낌</h4>
<ol>
<li>JS강의 - 사전학습과정에서 개념을 정리하고 간 터라 복습 진행할 필요를 느끼지 못함</li>
<li>야구게임 구현<ul>
<li>분업하여 구현하기에는 기능의 개수가 너무 적어, 각자 야구게임을 직접 구현하기로 함</li>
<li>나 포함 3명의 팀원이 각 브랜치에 완성된 코드를 PR하는 방식으로 진행</li>
</ul>
</li>
</ol>
<h2 id="finding">Finding</h2>
<h4 id="배운-것-얻은-것">배운 것, 얻은 것</h4>
<ul>
<li>Git Fork-PR을 통한 소스 contribute방법</li>
</ul>
<h2 id="future">Future</h2>
<h4 id="배운-것을-향후-어떻게-적용할-것인가">배운 것을 향후 어떻게 적용할 것인가</h4>
<ul>
<li>Git Fork-PR을 통해 Git프로젝트의 팀원이 아니더라도 코드를 반영할 수 있는 방법을 배우며, <code>오픈소스 개발기여</code>에 적용해볼 수 있을 것 같다.</li>
</ul>
<h2 id="마무리하며">마무리하며..</h2>
<h4 id="js의-es란">JS의 ES란</h4>
<ul>
<li>ES, ECMAScript는 JS의 <code>표준사양</code>이다.</li>
<li>매년 업데이트되어 JS의 새로운 기능과 개선사항을 도입하며, ES5 ➡️ ES6때 가장 큰 변화가 있었다.<ul>
<li>대표적으로 <code>let</code> <code>const</code> <code>화살표함수</code> <code>async/await</code> 등이 있으며, 개발편의성과 관련한 내용이 가장 많았다.</li>
</ul>
</li>
</ul>
<h4 id="es5-vs-es6">ES5 vs ES6</h4>
<ol>
<li>변수선언 let/const<pre><code class="language-js">// es5
var a = &quot;&quot;;
</code></pre>
</li>
</ol>
<p>// es6
let a = &quot;&quot;;
const b = &quot;&quot;;</p>
<pre><code>
2. 화살표 함수
```js
// es5
function func() { }

// es6
const func = () =&gt; {}</code></pre><ol start="3">
<li>async/await<pre><code class="language-js">// es5
doSomething()
.then(result1 =&gt; doSomethingElse(result1))
.then(result2 =&gt; doAnotherThing(result2))
.then(result3 =&gt; doSomethingMore(result3))
</code></pre>
</li>
</ol>
<p>// es6
const result1 = await doSomething();
const result2 = await doSomethingElse(result1);
const result3 = await doAnotherThing(result2);</p>
<p>```</p>
<ul>
<li>번외 <code>콜백지옥</code><ul>
<li>콜백지옥은 비동기 처리 뒤에 실행할 콜백함수를 지나치게 남발하여, 코드의 가독성을 해치는 경우이다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/989b2692-3715-4d3b-adce-1213c9b4c7a1/image.png" alt=""></li>
<li>이러한 지옥은 가독성을 해치고 서비스의 유지보수성을 떨군다.</li>
<li>그러므로, 비동기 처리를 할때는 되도록 <code>Promise를 이용한 then()</code>을 사용하거나 <code>async/await</code>를 사용하도록 하자</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WIL] Week 0주차]]></title>
            <link>https://velog.io/@dolphin-pc/WIL-Week-0%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@dolphin-pc/WIL-Week-0%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 17 Jun 2024 12:16:48 GMT</pubDate>
            <description><![CDATA[<h1 id="0주차---웹-미니-프로젝트-주간-610--14">0주차 - 웹 미니 프로젝트 주간 (6/10 ~ 14)</h1>
<h2 id="fact">Fact</h2>
<h4 id="이번주에-한-일">이번주에 한 일</h4>
<ol>
<li>입학시험</li>
<li>웹 미니 프로젝트 발제 및 개발 진행</li>
</ol>
<h2 id="feeling">Feeling</h2>
<h4 id="느낌">느낌</h4>
<ol>
<li>입학시험 - 매우 쉬웠음</li>
<li>웹 미니 프로젝트 - 오랜만의 협업개발이 재미 있었음</li>
</ol>
<h2 id="finding">Finding</h2>
<h4 id="배운-것-얻은-것">배운 것, 얻은 것</h4>
<p>웹 미니 프로젝트 - flask도 JSP와 같이 <code>include</code>가 가능하다.</p>
<h2 id="future">Future</h2>
<h4 id="배운-것을-향후-어떻게-적용할-것인가">배운 것을 향후 어떻게 적용할 것인가</h4>
<p>flask는 사용할 일 없을 것으로 보임. (전통적인 Spring SSR방식)</p>
<h2 id="마무리하며">마무리하며..</h2>
<ul>
<li>이번 주차에는 크게 배운 것을 써먹었다기보다, 기존에 알고 있는 지식으로 프로젝트를 잘 마무리했던 것 같다.</li>
<li>Git협업, shell스크립트로 배포 자동화 등 기존에 알고 있던 것들을 잘 써먹었다.</li>
</ul>
<ul>
<li><a href="https://teamsparta.notion.site/15-DevMinds-79a149a02dd34453a306c025cb2bf29f">개발 결과물 브로셔</a></li>
<li><a href="https://github.com/DevMinds-inno/DevMinds">Github</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FE 디자인 패턴(아키텍처)]]></title>
            <link>https://velog.io/@dolphin-pc/FE-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</link>
            <guid>https://velog.io/@dolphin-pc/FE-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</guid>
            <pubDate>Sat, 08 Jun 2024 08:39:06 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며..</h1>
<ul>
<li>MVC, MVVM, Flux 등 코드의 아키텍처 종류에 대해 대략적인 특징만 알고 있었다.</li>
<li>이번 기회에 여러 아키텍처의 특징을 정리해보면서, 아키텍처의 변천사를 알아보고자 한다.</li>
</ul>
<h1 id="fe에서의-디자인-패턴">FE에서의 디자인 패턴</h1>
<ul>
<li>흔히들 알고 있는 디자인 패턴은 <code>생성</code> <code>구조</code> <code>행동</code> 패턴으로 분류된 개념을 떠올리곤 한다.
그래서 나 또한 위 디자인패턴을 가장 먼저 읽고 정리하게 되었고, 문득 <code>아니 이건 객체에 대한 설명같은데, 프론트 보다는 백엔드 쪽에 가깝지 않나?!</code>라는 생각이 들어 FE에서의 디자인 패턴을 조금 더 살펴보기로 했다.</li>
<li>FE의 디자인 패턴은 결국 <code>웹 디자인 패턴</code>과 동일하게 풀이된다.</li>
<li>옛날의 웹은 백엔드를 중심으로 한 <code>읽기전용</code>웹이 전부였고, 단순한 패턴이 웹 디자인패턴의 시작이었다.</li>
</ul>
<h2 id="1-mvc-패턴">1. MVC 패턴</h2>
<ul>
<li>제일 유명한 패턴일 것이다. Model-View-Controller
FE라는 개념이 없던 시절에는 웹사이트 자체가 View였기에, Model을 통한 View를 그려주는 매우 단순한 방식을 택했다.<ul>
<li>그렇기에 <code>View &gt; Controller -&gt; Model -&gt; View</code> 방식으로 흘러간다.</li>
<li>이에 대한 단점은 아주 명확한데, <code>Model과 View이 끈끈</code>하다는 것이다.<ul>
<li>대부분 운영환경의 경우, Model보다는 View쪽에서의 변경사항이 많이 발생한다.</li>
<li><code>MVC의 같은 경우, View의 수정이 필요할 때마다, Model의 변경또한 불가피해진다.</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>★ 초기에는 FE의 역할이 없어, Model을 통한 View를 그리는 매우 단순한 방식을 택했다.</p>
</blockquote>
<blockquote>
<p>⚠️ 매우 단순하지만, MVC간의 결합도가 높아</p>
</blockquote>
<ol>
<li>코드 복잡성이 높고</li>
<li>유지보수/테스트가 어려우며</li>
<li>비즈니스 로직의 (관심사)분리가 애매한 상황이 존재할 수 있다.</li>
</ol>
<hr>
<h2 id="2-mvp-패턴">2. MVP 패턴</h2>
<ul>
<li>MVC패턴의 의존성을 낮추고자 나온 패턴으로, <code>Model-View-Presenter</code> 이다.</li>
<li>Presenter가 Controller의 역할을 대신하지만, 흐름의 순서에 차이가 생긴다.</li>
<li><code>View &gt; Presenter &gt; Model &gt; Presenter &gt; View</code> 와 같이 Presenter가 완벽한 중개자가 된다.</li>
</ul>
<blockquote>
<p>★ MVC패턴에서의 뷰-모델간의 결합도를 낮춘다.</p>
</blockquote>
<blockquote>
<p>⚠️ Presenter의 역할이 중요해지면서, 결합도 또한 증가되었다.</p>
</blockquote>
<hr>
<h2 id="3-mvvm-패턴">3. MVVM 패턴</h2>
<ul>
<li>이제서야 초기 현대적인 디자인 패턴이 시작되었다.</li>
<li><code>Model-View-ViewModel</code>로, 이전의 MVP패턴과 달리 <code>데이터바인딩</code>이라는 개념으로 결합도를 조금 더 낮추게 한다.</li>
</ul>
<blockquote>
<p>✅ 데이터바인딩이란
View의 속성과 ViewModel의 속성을 연결하여, 유기적인 관계로 만드는 것이다.
ex. 뷰모델의 <code>userName</code>속성과 뷰의 <code>Input의 value</code> 속성을 바인딩하면, userName이 변경될 때마다 TextInput의 값도 자동으로 변경되는 것이다.</p>
</blockquote>
<ul>
<li>이러한 데이터바인딩을 통해, View와 ViewModel의 연결을 확립하기에 MVP패턴보다는 결합도가 낮다고 말할 수 있다.
(MVP에서 View와 Presenter가 태어날 때부터 짝꿍이었다)</li>
</ul>
<blockquote>
<p>★ MVVM은 <code>데이터바인딩</code>을 통해 UI와 비즈니스로직을 분리하여, 재사용성과 유지보수성을 높인다.
또한, 이러한 패턴은 현재의 FE 3대장인 React, Vue, Angular에서 초기개념으로 사용되었다.</p>
</blockquote>
<blockquote>
<p>⚠️ ViewModel의 설계가 어렵고, 학습곡선이 높다.</p>
</blockquote>
<hr>
<h2 id="4-component-패턴">4. Component 패턴</h2>
<ul>
<li>인간의 욕심은 끝이 없듯이, 완벽에 가까운 MVVM패턴에서 더욱 재사용성이 높은 패턴을 찾게 되었다.</li>
<li>웹서비스가 발전하면서, 하나의 Page안에서 여러 모듈을 조립하는 방식인 <code>Component패턴</code>이 등장하게 되었다.</li>
<li></li>
</ul>
<blockquote>
<p>★ 재사용성, 모듈화, 독립성 등 컴포넌트를 기반으로 한 개발방식 (지금의 FE에 가깝다)
비즈니스 로직이 컴포넌트에 포함되면, 재사용성이 떨어지기에 UI와 비즈니스 로직을 분리하는 <code>Container-Presenter</code> 방식을 초기에는 활용하곤 했다.</p>
</blockquote>
<blockquote>
<p>⚠️ 컴포넌트 단위로 쪼개다 보니, 컴포넌트간의 유기적인 데이터관리가 어렵게 되었다.
<code>Props Drilling</code></p>
</blockquote>
<hr>
<h2 id="5-flux-패턴">5. Flux 패턴</h2>
<ul>
<li><strong>Component패턴</strong>은 props를 통해서만 데이터를 관리하다보니, 데이터의 파편화가 있었
다.</li>
<li>이를 해결하기 위해 store라는 전역저장소를 두어, 단방향적인 데이터흐름인 <code>Flux패턴</code>이 탄생하게 되었다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/b2a12a12-4b87-4522-a6c1-d91b3707d65d/image.png" alt=""></li>
<li><code>Action</code>객체를 Dispatcher함수를 통해 Store에 반영하면, Store를 구독하는 View에 반영되는 흐름이다.</li>
</ul>
<blockquote>
<p>★ Props Drilling해소
전역상태관리 시대의 시작</p>
</blockquote>
<blockquote>
<p>⚠️ 높은 러닝커브
상태관리만을 위한 코드 (보일러 플레이트, Redux)</p>
</blockquote>
<hr>
<h2 id="6-observer-observable-패턴">6. Observer-Observable 패턴</h2>
<ul>
<li>1:다 관계의 종속성을 정의하는 패턴이다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/21296e0b-192e-4ff3-b22a-32567f8188da/image.png" alt=""></li>
<li>Flux와 비슷하나, Action과 Dispatch를 배제하여, 변경된 값을 모두에게 전달하는 방식이다.</li>
<li>초창기의 Mobx, RxJS</li>
</ul>
<hr>
<h2 id="7-atomic-패턴">7. Atomic 패턴</h2>
<ul>
<li>지금의 Recoil이 따르고 있는 패턴</li>
<li>Redux의 Flux패턴이 너무 장황하다고 여기게 되자, Model에 쉽게 접근하는 방법을 목표로 한다.</li>
<li>Atom이라는 단위로 DataModel을 설계한다.</li>
</ul>
<h1 id="정리하며">정리하며...</h1>
<ul>
<li>MVC패턴부터 지금의 Component패턴까지 알아보면서 느낀점은 
디자인 패턴은 <code>불편한 것을 해결하거나, 더욱 나은 개선을 위해</code> 진화해왔다는 점이다.</li>
<li>MVC패턴의 불편함을 MVP로, MVP의 불편함을 MVVM으로 ...</li>
<li>하지만, Component패턴부터는 불편함보다는 더욱 나은 개선을 위해서인 것 같다.
(물론, 보일러 플레이트나 높은 러닝커브 또한 불편함이라고 볼 수 있겠다..)</li>
</ul>
<ul>
<li>현재 많이 사용되고 있는 Redux, Recoil, React등이 이러한 디자인 패턴에 기인한 라이브러리인 것을 볼 수 있기에 디자인패턴에서 탄생될 라이브러리를 잘 활용하기 위해서는 디자인패턴에 대해 계속해서 알아보는 노력을 하는 것이 중요하다고 생각이 되었다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[디자인 패턴 - 3. 행동패턴]]></title>
            <link>https://velog.io/@dolphin-pc/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-3.-%ED%96%89%EB%8F%99%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dolphin-pc/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-3.-%ED%96%89%EB%8F%99%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sat, 08 Jun 2024 05:14:03 GMT</pubDate>
            <description><![CDATA[<h2 id="행동hebavior-패턴">행동(Hebavior) 패턴</h2>
<blockquote>
<p>객체간의 책임할당과 관련
어떻게 동작을 실행할 것인가?</p>
</blockquote>
<h3 id="1-🔗-책임-연쇄chain-of-responsibility">1. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%B1%85%EC%9E%84-%EC%97%B0%EC%87%84chain-of-responsibility">🔗 책임 연쇄(Chain of Responsibility)</a></h3>
<ul>
<li>요청이 들어왔을 때, 객체-&gt;객체 간의 이동을 반복하며 적절한 핸들러를 찾을 때까지 계속 이동</li>
<li>예시) <ul>
<li>결제수단이 1. 카드 2. 현금 3. 네이버페이 가 있을 경우,</li>
<li>100,000원을 결제하려 한다.</li>
<li>카드에서 100,000원을 결제한다 -&gt; 하지만, 50,000원밖에 결제가 되지 않았다. </li>
<li>2,3순위로 이동하여 결제를 계속한다.</li>
</ul>
</li>
</ul>
<h3 id="2-명령command">2. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EB%AA%85%EB%A0%B9command">명령(Command)</a></h3>
<ul>
<li>명령할 인터페이스를 분리하여, 클라이언트에서 사용할 때, 명령을 전달한다.</li>
</ul>
<pre><code class="language-ts">// 전구를 리모컨으로 조작할 때의 경우

interface Command {
  exe(): void;
  undo(): void;
  redo(): void;
}

class Bulb {
  turnOn(): void {
    console.log(&quot;전구 켜짐&quot;);
  }

  turnOff(): void {
    console.log(&quot;전구 꺼짐&quot;);
  }
}

class TurnOn implements Command {
  bulb: Bulb;

  constructor(bulb: Bulb) {
    this.bulb = bulb;
  }

  exe(): void {
    this.bulb.turnOn();
  }

  undo(): void {
    this.bulb.turnOff();
  }

  redo(): void {
    this.exe();
  }
}

class RemoteControl {
  submit(command: Command) {
    command.exe();
  }
}

const bulb = new Bulb();

const turnOn = new TurnOn(bulb);

const remote = new RemoteControl();

remote.submit(turnOn);
</code></pre>
<h3 id="3-반복자iterator">3. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EB%B0%98%EB%B3%B5%EC%9E%90iterator">반복자(Iterator)</a></h3>
<ul>
<li>객체의 요소에 접근하는 방법을 제시하고, 내부 구조를 드러내지 않는다.</li>
</ul>
<pre><code class="language-ts">/**
 * @desc 라디오 채널을 예시로 한 코드
 */
class RadioStation {
  frequency: number;

  constructor(frequency: number) {
    this.frequency = frequency;
  }

  getFrequency(): number {
    return this.frequency;
  }
}

class StationList implements Iterable&lt;RadioStation&gt; {
  stations: RadioStation[] = [];
  counter = 0;

  addStation(station: RadioStation) {
    this.stations.push(station);
  }

  removeStation(station: RadioStation) {
    this.stations = this.stations.filter(
      (s) =&gt; s.frequency != station.frequency
    );
  }

  [Symbol.iterator](): Iterator&lt;RadioStation&gt; {
    return {
      next: () =&gt; {
        if (this.counter &lt; this.stations.length) {
          return { done: false, value: this.stations[this.counter++] };
        } else {
          this.counter = 0;
          return { done: true, value: null };
        }
      },
    };
  }
}

const stationList = new StationList();
stationList.addStation(new RadioStation(100));
stationList.addStation(new RadioStation(200));
stationList.addStation(new RadioStation(300));

for (const station of stationList) {
  console.log(station.getFrequency());
}

stationList.removeStation(new RadioStation(200));

for (const station of stationList) {
  console.log(station.getFrequency());
}
</code></pre>
<h3 id="4-중재자mediator">4. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%A4%91%EC%9E%AC%EC%9E%90mediator">중재자(mediator)</a></h3>
<ul>
<li>두 객체 간의 상호작용을 제어하기 위해 <strong>중재자</strong>를 추가한다.</li>
<li>중재자패턴은 상호작용에 필요한 구현체를 알 필요가 없어, 객체간의 결합도를 줄일 수 있다.</li>
</ul>
<pre><code class="language-ts">/**
 * @desc 채팅방을 예시로 한 중재자 패턴
 */

interface ChatRoomMediator {
  showMessage(user: User, message: string): void;
}

class User {
  name: string;
  chatMediator: ChatRoomMediator;

  constructor(name: string, chatMediator: ChatRoomMediator) {
    this.name = name;
    this.chatMediator = chatMediator;
  }

  getName() {
    return this.name;
  }

  send(message: string): void {
    this.chatMediator.showMessage(this, message);
  }
}

class ChatRoom implements ChatRoomMediator {
  showMessage(user: User, message: string): void {
    const time = new Date().toLocaleDateString();
    const sender = user.getName();

    console.log(`${time} [${sender}]: ${message}`);
  }
}

const chatRoom = new ChatRoom();
const johnUser = new User(&quot;John&quot;, chatRoom);
const janeUser = new User(&quot;Jane&quot;, chatRoom);

johnUser.send(&quot;hi&quot;);
janeUser.send(&quot;hey there&quot;);
</code></pre>
<h3 id="5-메멘토memento">5. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EB%A9%94%EB%A9%98%ED%86%A0memento">메멘토(Memento)</a></h3>
<ul>
<li>객체의 상태를 어딘가에 저장해두고, 나중에 복원할 수 있도록 저장해두는 패턴이다.</li>
</ul>
<pre><code class="language-ts">/**
 * @desc 텍스트편집기의 예시로 메멘토 패턴
 */
class EditorMemento {
  protected content: string;

  constructor(content: string) {
    this.content = content;
  }

  getContent(): string {
    return this.content;
  }
}

class Editor {
  protected content = &quot;&quot;;

  type(words: string) {
    this.content = this.content + &quot; &quot; + words;
  }

  save(): EditorMemento {
    return new EditorMemento(this.content);
  }

  restore(editorMemento: EditorMemento) {
    this.content = editorMemento.getContent();
  }

  print(): void {
    console.log(this.content);
  }
}

const editor = new Editor();

editor.type(&quot;hi&quot;);
editor.type(&quot;hello&quot;);

const editorMemento = editor.save();

editor.type(&quot;whatup&quot;);
editor.print();

editor.restore(editorMemento);
editor.print();
</code></pre>
<h3 id="6-옵저버observer">6. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%98%B5%EC%A0%80%EB%B2%84observer">옵저버(Observer)</a></h3>
<ul>
<li>객체 간의 의존성을 연결하여, 객체의 상태가 변경될 때마다 구독객체에 알림을 보낸다.</li>
<li>(react에서는 흔히 알고 있는 전역상태관리, state가 변경되면 UI렌더링)</li>
</ul>
<pre><code class="language-ts">/**
 * @desc 구인구직을 예시로 한 옵저버 패턴
 */
class JobPost {
  protected title: string;

  constructor(title: string) {
    this.title = title;
  }

  getTitle(): string {
    return this.title;
  }
}

interface Observer {
  onJobPosted(jobPost: JobPost): void;
}

class JobSeeker implements Observer {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  onJobPosted(jobPost: JobPost): void {
    console.log(`Hi ${this.name}! New Job Posted: ${jobPost.getTitle()}`);
  }
}

interface Observable {
  notify(jobPost: JobPost): void;
  attach(observer: Observer): void;
  addJob(jobPost: JobPost): void;
}

class EmployeeAgency implements Observable {
  protected observers: Observer[] = [];

  // 옵저버 등록
  attach(observer: Observer): void {
    this.observers.push(observer);
  }

  // 새로운 직업이 등록된다면, 알림 발송
  addJob(jobPost: JobPost): void {
    this.notify(jobPost);
  }

  // 등록된 옵저버들에게 새로운 직업이 등록되었다고 알리기
  notify(jobPost: JobPost): void {
    for (const observer of this.observers) {
      observer.onJobPosted(jobPost);
    }
  }
}

const john = new JobSeeker(&quot;john&quot;);
const jane = new JobSeeker(&quot;jane&quot;);

const jobPoster = new EmployeeAgency();
jobPoster.attach(john);
jobPoster.attach(jane);

jobPoster.addJob(new JobPost(&quot;FE Engineer&quot;));
</code></pre>
<h3 id="7-방문자visitor">7. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EB%B0%A9%EB%AC%B8%EC%9E%90visitor">방문자(Visitor)</a></h3>
<ul>
<li>기존 객체를 수정하지 않고 새로운 작업을 추가하기 위한 패턴<pre><code class="language-ts">/**
* @desc 동물원을 예시로 한 방문자 패턴
* 방문자들에게 여러동물들의 묘기를 보여줘야 함
*/
interface Animal {
accept(operation: AnimalOperation): void;
}
</code></pre>
</li>
</ul>
<p>interface AnimalOperation {
  visitMonkey(monkey: Monkey): void;
  visitLion(lion: Lion): void;
  visitDolphin(dolphin: Dolphin): void;
}</p>
<p>class Monkey implements Animal {
  accept(operation: AnimalOperation): void {
    operation.visitMonkey(this);
  }</p>
<p>  shout(): void {
    console.log(&quot;우끼끼&quot;);
  }
}</p>
<p>class Lion implements Animal {
  accept(operation: AnimalOperation): void {
    operation.visitLion(this);
  }</p>
<p>  roar(): void {
    console.log(&quot;ROAR&quot;);
  }
}</p>
<p>class Dolphin implements Animal {
  accept(operation: AnimalOperation): void {
    operation.visitDolphin(this);
  }</p>
<p>  speak(): void {
    console.log(&quot;돌고래 울음소리&quot;);
  }
}</p>
<p>class Speak implements AnimalOperation {
  visitMonkey(monkey: Monkey): void {
    monkey.shout();
  }</p>
<p>  visitDolphin(dolphin: Dolphin): void {
    dolphin.speak();
  }</p>
<p>  visitLion(lion: Lion): void {
    lion.roar();
  }
}</p>
<p>const monkey = new Monkey();
const lion = new Lion();
const dolphin = new Dolphin();</p>
<p>const speak = new Speak();</p>
<p>monkey.accept(speak);
lion.accept(speak);
dolphin.accept(speak);</p>
<p>// 여기서, Jump라는 묘기를 추가한다면 어떡할까?
// 아마 각 동물들을 수정해야 할 것이다.
// 그러지말고, Jump라는 새 방문자를 만들어 보자
class Jump implements AnimalOperation {
  visitMonkey(monkey: Monkey): void {
    console.log(&quot;monkey jump&quot;);
  }</p>
<p>  visitDolphin(dolphin: Dolphin): void {
    console.log(&quot;dolphin jump&quot;);
  }</p>
<p>  visitLion(lion: Lion): void {
    console.log(&quot;lion jump&quot;);
  }
}</p>
<p>const jump = new Jump();</p>
<p>monkey.accept(jump);
lion.accept(jump);
dolphin.accept(jump);</p>
<pre><code>

### 8. [전략(Strategy)](https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%A0%84%EB%9E%B5strategy)
- 상황에 따라 객체가 수행할 행동을 달리하는 것이다.
- 예를 들어, 엄청난 알고리즘을 적용했다고 하자.
  - 하지만, 이는 데이터의 양이 방대할 때만 유효하고, 데이터 양이 적을 때는 오히려 역효과가 발생한다고 가정하자.

&gt; 전략 패턴은 상황에 따라 전략을 전환하는 패턴이다.

```ts
interface ISort {
  sort(dataset: number[]): void;
}

class BubbleSort implements ISort {
  sort(dataset: number[]): void {
    console.log(&quot;데이터의 수가 적을 때는 Bubble이 유용해요!&quot;);
  }
}

class QuickSort implements ISort {
  sort(dataset: number[]): void {
    console.log(&quot;데이터의 수가 많은 때는 QuickSort가 유용해요!&quot;);
  }
}

class Sorter {
  protected sorterSmall: ISort;
  protected sorterBig: ISort;

  constructor(sorterSmall: ISort, sorterBig: ISort) {
    this.sorterSmall = sorterSmall;
    this.sorterBig = sorterBig;
  }

  sort(dataset: number[]): void {
    if (dataset.length &gt; 5) {
      return this.sorterBig.sort(dataset);
    }
    return this.sorterSmall.sort(dataset);
  }
}

const dataSet = [1, 2, 3, 4, 5];

const sorter = new Sorter(new BubbleSort(), new QuickSort());

sorter.sort(dataSet);

dataSet.push(6);
sorter.sort(dataSet);
</code></pre><h3 id="9-상태state">9. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%83%81%ED%83%9Cstate">상태(State)</a></h3>
<blockquote>
<p>상태가 변경될 때, 클래스의 동작을 변경
객체가 특정상태에 따라 행위를 달리하는 상황에서, 조건문으로 행위를 달리하는 것이 아닌 상태를 <code>객체화</code> 하여 상태가 행동할 수 있도록 위임하는 패턴</p>
</blockquote>
<ul>
<li>상태는 state라는 변수로 관리하면서,</li>
<li>메소드(행동)에 따라, state에 update될 내용을 클래스로 만들어 낸다.</li>
</ul>
<h3 id="10-템플릿-메소드template-method">10. <a href="https://soobing.github.io/cs/design-patterns-for-humans/#-%EC%83%81%ED%83%9Cstate">템플릿 메소드(Template Method)</a></h3>
<blockquote>
<p>객체의 생성단계가 절대 변경되지 못할 때, 이 단계를 템플릿화하여 생성하는 패턴이다.</p>
</blockquote>
<pre><code class="language-ts">/**
 * @desc 프로그램 개발을 예시로 템플릿메소드 패턴
 */
abstract class ProgramBuilder {
  public build(): void {
    this.test();
    this.lint();
    this.assemble();
    this.deploy();
  }

  abstract test(): void;
  abstract lint(): void;
  abstract assemble(): void;
  abstract deploy(): void;
}

class AProgramBuilder extends ProgramBuilder {
  test(): void {
    console.log(&quot;AProgramBuilder test&quot;);
  }

  lint(): void {
    console.log(&quot;AProgramBuilder lint&quot;);
  }

  assemble(): void {
    console.log(&quot;AProgramBuilder assemble&quot;);
  }

  deploy(): void {
    console.log(&quot;AProgramBuilder deploy&quot;);
  }
}

const AProgram = new AProgramBuilder();

AProgram.build();
</code></pre>
<h1 id="마무리하며">마무리하며...</h1>
<ul>
<li>생성, 구조, 행동 패턴에서의 다양한 디자인 패턴을 보며, 친근하게 느꼈던 패턴들이 많았다.</li>
<li>그럴만한게, 코드를 작성하면서 내가 고민했던 방식들이 이 디자인패턴들의 특징과 맞닿아있었기 때문이다.<ul>
<li><code>퍼사드 패턴</code> <code>builder패턴</code> <code>템플릿 패턴</code>과 같이 코드의 복잡성을 낮추려 할 때 많이 사용했던 것 같다.</li>
</ul>
</li>
<li>디자인 패턴을 알아보며, 코드를 작성하는 개발자에게는 디자인 패턴이라는 것은 <code>고민의 흔적</code>이라는 것이라고 느끼며, 디자인 패턴을 활용하는 일은 많지 않지만, 특별한 상황에서의 디자인패턴 활용은 해답이 되어주는 것 같다.</li>
<li>이처럼 디자인 패턴은 많이 활용되지는 않지만, 특별한 문제에 맞닥뜨렸을 때 <code>아 ~~디자인 패턴 사용하면 될 것 같은데?!</code>라고 떠올릴 정도로 개념만 익히고 가는 것이 좋다고 생각한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이노캠] 디자인 패턴 - 2. 구조패턴]]></title>
            <link>https://velog.io/@dolphin-pc/%EC%9D%B4%EB%85%B8%EC%BA%A0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-2.-%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dolphin-pc/%EC%9D%B4%EB%85%B8%EC%BA%A0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-2.-%EA%B5%AC%EC%A1%B0%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sat, 08 Jun 2024 01:49:42 GMT</pubDate>
            <description><![CDATA[<h2 id="2-구조structural-패턴">2. 구조(Structural) 패턴</h2>
<blockquote>
<p>구조 패턴은 객체의 <code>구성</code>과 관련되며, Entity가 어떻게 사용될 수 있는지에 관한 것입니다.</p>
</blockquote>
<h3 id="1-🔌-어댑터adapter">1. 🔌 어댑터(Adapter)</h3>
<blockquote>
<p>어댑터 패턴을 사용하면 호환되지 않은 객체를 다른 클래스와 호환되도록 할 수 있다.</p>
</blockquote>
<pre><code class="language-ts">class Hunter {
  hunt(lion: Lion): void {
    lion.roar();
  }
}

// 이제 Hunter클래스는 Lion객체만 사냥할 수 있다.

interface Lion {
  roar(): void;
}

class ALion implements Lion {
  roar(): void {
    console.log(&quot;사자 죽어요&quot;);
  }
}

// 여기서, Hunter가 다른 동물도 사냥하고 싶다면 어떻게 해야 할까?

class Wolf {
  bark() {
    console.log(&quot;늑대 죽네&quot;);
  }
}

class WolfAdapter implements Lion {
  protected wolf: Wolf;

  constructor(wolf: Wolf) {
    this.wolf = wolf;
  }

  roar() {
    this.wolf.bark();
  }
}

// Usage
const hunter = new Hunter();

const lion = new ALion();

const wolf = new Wolf();
const wolfAdapter = new WolfAdapter(wolf);

hunter.hunt(lion);
hunter.hunt(wolfAdapter);
</code></pre>
<ul>
<li>hunter는 <code>Lion</code>객체만 사냥할 수 있다.</li>
<li>하지만, 다른 객체도 사냥할 수 있게끔, <code>Wolf</code>를 사냥할 수 있도록 <code>Lion</code>객체를 모방한 <code>WolfAdapter</code>를 통해, 사냥꾼을 변경하지 않고도 wolf를 사냥할 수 있게 만들 수 있다.</li>
</ul>
<h3 id="3-브릿지bridge">3. 브릿지(Bridge)</h3>
<pre><code class="language-ts">/**
 * @desc 브릿지 패턴
 *
 * 구현체에서 속성을 분리한다.
 *
 * 여기서는 [테마]에 따른 웹사이트 색상을 예시로 들어볼 것이다.
 *
 * 예를 들어, 페이지 A,B,C가 있고, 테마 1,2,3이 있다면 어떻게 할 것인가
 *   무식하게 한다면, A(1,2,3), B(1,2,3), C(1,2,3)을 모두 구현할 것이다.
 *
 * 여기서 브릿지 패턴을 적용한다면, 테마 1,2,3을 별도 분리하여, 활용할 때 가져다 쓰게 할 수 있다.
 */

// WebPage속성에서 Theme은 별도의 Type으로 빼놓는다.
type WebPage = {
  theme: Theme;
  getContent(): string;
};

class About implements WebPage {
  theme: Theme;

  constructor(theme: Theme) {
    this.theme = theme;
  }

  getContent(): string {
    return &quot;About Page in &quot; + this.theme.getColor();
  }
}

type Theme = {
  getColor(): string;
};

class DarkTheme implements Theme {
  getColor(): string {
    return &quot;Dark&quot;;
  }
}

class WhiteTheme implements Theme {
  getColor(): string {
    return &quot;White&quot;;
  }
}

// Usage
const dark = new DarkTheme();
const white = new WhiteTheme();

const aboutPage_Black = new About(dark);
const aboutPage_White = new About(white);

console.log(aboutPage_Black.getContent());
console.log(aboutPage_White.getContent());
</code></pre>
<blockquote>
<p>Property를 별도분리하여, 활용할 때 조립하는 방식
추상화&lt;-&gt;구현체를 분리</p>
</blockquote>
<h3 id="3-컴포지트composite">3. 컴포지트(Composite)</h3>
<blockquote>
<p>복합체 패턴, 복합객체와 단일객체를 동일한 컴포넌트로 취급하여, 클라이언트에게 이 둘을 구분하지 않고 동일한 인터페이스를 사용하도록 하는 구조 패턴 (...?, 명확히 이해가 되지 않는다)</p>
</blockquote>
<ul>
<li>아마도, 공통된 속성을 기반으로 활용할 수 있게 하는 패턴인 것 같은데,</li>
<li>예시를 들어보자면, 모든 사람들은 조금씩 다르지만 <code>Age</code>를 가진다 -&gt; 20대가 몇명이지? 라고 구해볼 수 있는 것같다.</li>
</ul>
<h3 id="4-데코레이터decorator">4. 데코레이터(Decorator)</h3>
<blockquote>
<p>객체를 Wrapping함으로써, 동적으로 객체를 변경할 수 있게 한다.</p>
</blockquote>
<pre><code class="language-ts">type Coffee = {
  cost: number;
};

class BasicCoffee implements Coffee {
  cost = 0;
}

class Americano implements Coffee {
  cost: number;
  constructor(coffee: Coffee) {
    this.cost = 20;
  }
}

class Latte implements Coffee {
  cost: number;
  constructor(coffee: Coffee) {
    this.cost = 40;
  }
}

let coffee = new BasicCoffee();

coffee = new Americano(coffee);
console.log(coffee.cost);

coffee = new Latte(coffee);
console.log(coffee.cost);
</code></pre>
<blockquote>
<p>속성이 동일한 인스턴스에 한해서, 객체의 변경을 객체를 Wrap하여 바꾼다.</p>
</blockquote>
<h3 id="5-퍼사드facade">5. 퍼사드(Facade)</h3>
<blockquote>
<p>마치 <code>물위의 백조</code>와 같다</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/59361c6f-cd2b-4c41-95c9-a6407e3da8b7/image.png" alt=""></p>
<ul>
<li>여러 동작들을 하나의 함수로 묶어서, 클라이언트가 사용하기 쉽게 단순화하는 패턴이다.</li>
<li>예를 들어, 컴퓨터를 켜본다고 생각해보자.<ul>
<li>우리는 컴퓨터 전원을 켜기 위해 전원버튼만 누르면 된다 (간단~)</li>
<li>하지만, 컴퓨터 내부동작은 그렇지 않다.<ul>
<li>전원공급</li>
<li>bios세팅</li>
<li>os ...</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-ts">class Computer {
  전원공급() {
    console.log(&quot;전원!&quot;);
  }
  소리내기() {
    console.log(&quot;소리!&quot;);
  }
  화면켜기() {
    console.log(&quot;화면!&quot;);
  }
  준비완료() {
    console.log(&quot;준비!&quot;);
  }
  BIOS세팅() {
    console.log(&quot;BIOS!&quot;);
  }
  OS() {
    console.log(&quot;OS!&quot;);
  }
}

class ComputerFacade {
  computer: Computer;

  constructor(computer: Computer) {
    this.computer = computer;
  }

  turnOn() {
    this.computer.BIOS세팅();
    this.computer.OS();
    this.computer.소리내기();
    this.computer.전원공급();
    this.computer.화면켜기();
    this.computer.준비완료();
  }
}

const computer = new Computer();
const user = new ComputerFacade(computer);

user.turnOn();
</code></pre>
<h3 id="6-플라이웨이트flyweight">6. 플라이웨이트(Flyweight)</h3>
<blockquote>
<p><code>공유!</code> 유사한 객체를 공유하여 메모리, 비용을 최소화</p>
</blockquote>
<pre><code class="language-ts">class Coffee {
  진함 = 0;
}

class CoffeeMaker {
  makedCoffee: Map&lt;string, Coffee&gt; = new Map();

  make(key: string): Coffee {
    // 만들어진 커피가 없다면, 커피를 만들어둔다.
    if (!this.makedCoffee.has(key)) {
      this.makedCoffee.set(key, new Coffee());
    }

    return this.makedCoffee.get(key)!;
  }
}

const coffeeMaker = new CoffeeMaker();

const coffeeList = [
  coffeeMaker.make(&quot;아메리카노&quot;),
  coffeeMaker.make(&quot;라떼&quot;),
  coffeeMaker.make(&quot;아메리카노&quot;),
  coffeeMaker.make(&quot;아메리카노&quot;),
];

// 하지만 객체공유 이기에, 다른 객체까지 영향이 간다.
coffeeList[0].진함 = 2;
console.log(coffeeList);
</code></pre>
<blockquote>
<p>⚠️ 비용 최소화 관점에서 공유하는 것은 좋으나, 객체 변경에 따라 다른 객체까지 변경되므로 주의해서 사용해야 할 것 같다.</p>
</blockquote>
<h3 id="7-프록시proxy">7. 프록시(Proxy)</h3>
<blockquote>
<p>하나의 클래스가 다른 클래스의 기능을 나타내는 것
👍 이런 경우에 활용할 수 있다. </p>
</blockquote>
<ul>
<li>특정 객체의 조건 확인</li>
<li>추가기능 제공</li>
</ul>
<pre><code class="language-ts">type Door = {
  open(): void;
  close(): void;
};

class HomeDoor implements Door {
  open() {
    console.log(&quot;Home Door Open&quot;);
  }

  close() {
    console.log(&quot;Home Door Closed&quot;);
  }
}

class SecureDoor implements Door {
  isLock = true;
  door: Door;

  constructor(door: Door) {
    this.door = door;
  }

  unLock(password: string) {
    if (password == &quot;secret&quot;) this.isLock = false;
  }

  open() {
    // 프록시 패턴 : 조건 확인
    if (this.isLock) {
      console.log(&quot;Door is Locked&quot;);
    } else {
      this.door.open();
    }
  }

  close() {
    this.door.close();
  }
}

// 집에 문을 달았다.
const door = new HomeDoor();

door.open();
door.close();

// 하지만, 우리집은 누구나 열수 있기에, 도어락을 설치했다.
const secureDoor = new SecureDoor(door);
secureDoor.open();
// 이제 우리집은 암호를 풀어야만 열 수 있다.

secureDoor.unLock(&quot;secret&quot;);
secureDoor.open();

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[이노캠] 디자인 패턴 - 1. 생성패턴]]></title>
            <link>https://velog.io/@dolphin-pc/%EC%9D%B4%EB%85%B8%EC%BA%A0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dolphin-pc/%EC%9D%B4%EB%85%B8%EC%BA%A0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sat, 08 Jun 2024 01:48:32 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며...</h1>
<ul>
<li>이노캠 필수과정 1일차, 기술매니저님이 Next, TS에 관해 여쭤보신 뒤 디자인 패턴에 대해 공부를 제시해주셨다.</li>
<li>안그래도, 사이드프로젝트를 진행하면서 왠지모르게 마음에 들지 않는 코드의 구조와 더 좋은 방법이 없나.. 라는 생각이 들던 참이었다.</li>
</ul>
<h3 id="디자인패턴">디자인패턴</h3>
<ul>
<li><a href="https://soobing.github.io/cs/design-patterns-for-humans/#%EC%83%9D%EC%84%B1creational-%ED%8C%A8%ED%84%B4">우리들을 위한 디자인 패턴</a></li>
<li>위 링크의 내용을 읽고, 이해한 내용을 써내려가보려 한다.</li>
</ul>
<hr>
<h1 id="디자인-패턴이란">디자인 패턴이란</h1>
<blockquote>
<p>디자인 패턴은 반복되는 문제에 대한 해결책이며, 특정 문제를 해결하는 방법에 대한 지침이다.</p>
</blockquote>
<p>디자인 패턴은 <code>문제의 해결책</code>이며, 문제를 찾는 해결책은 아니다. (...?)</p>
<h2 id="디자인-패턴-종류">디자인 패턴 종류</h2>
<ol>
<li>생성 (Creational)</li>
<li>구조 (Structural)</li>
<li>행동 (Behavioral)</li>
</ol>
<hr>
<h2 id="생성-creational-패턴">생성 (Creational) 패턴</h2>
<blockquote>
<p>객체 또는 관련된 객체 그룹을 <code>인스턴스화</code>하는 방법에 초점을 맞춘다.</p>
</blockquote>
<h3 id="1-심플-팩토리">1. 심플 팩토리</h3>
<blockquote>
<p>심플 팩토리는 클라이언트에게 인스턴스화 로직을 노출하지 않고 클라이언트용 인스턴스를 생성한다.</p>
</blockquote>
<pre><code class="language-ts">interface Door {
  getWidth(): number;
  getHeight(): number;
}

class WoodenDoor implements Door {
  protected width: number;
  protected height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  getWidth(): number {
    return this.width;
  }

  getHeight(): number {
    return this.height;
  }
}

class DoorFactory {
  public static makeDoor(width: number, height: number): Door {
    return new WoodenDoor(width, height);
  }
}

// 위와 같은 팩토리가 있을 때, 클라이언트에서 인스턴스를 생성하는 법은 아래와 같이 하면 된다.

const door = DoorFatory.makeDoor(100,100);
</code></pre>
<blockquote>
<p>👍  객체를 생성할 때, 일부 로직을 포함해야 할 경우 위와 같은 팩토리 패턴을 사용하면 좋다.
예를 들어, <code>makeDoor</code>에서 width와 height로 계산 로직이 들어갈 수도 있다.</p>
</blockquote>
<h3 id="2-팩토리-메소드">2. 팩토리 메소드</h3>
<blockquote>
<p>자식 클래스에게 인스턴스화 로직을 위임하는 방식이다.</p>
</blockquote>
<ul>
<li><p>이게 무슨 소리인고하니, 예를 들어</p>
<ul>
<li>인사담당자라고 한다면, </li>
<li><code>개발관련 면접관</code>이 있을 것이고,</li>
<li><code>소통관련 면접관</code>이 있을 것이다.</li>
</ul>
</li>
<li><p>이처럼, <code>여러종류의</code> 면접관이 많을 것인데, 이것은 면접자에 따라 달라진다.
(클라이언트에서 사용될 때(런타임)에 따라 특정 클래스에서 필요한 인스턴스를 받아야 한다.</p>
</li>
<li><p>(<a href="https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9CFactory-Method-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90">팩토리 메소드</a>, 해당 글을 보고 이해했다)</p>
</li>
<li><p>면접관 Class</p>
<ul>
<li>개발 면접관 </li>
<li>인사 면접관</li>
<li>소통 면접관</li>
<li>인성 면접관
등등 면접자에 따라 면접관 종류가 달라질 것이다.</li>
</ul>
</li>
<li><p>이를 위해서, 면접관 Class에서 종류에 따라 필요한 <code>면접관을 할당(인스턴스화)</code>하려면 모든 조건에 따라 분기처리를 해주어야 한다. (이는 <code>개방/폐쇄 원칙</code>에 좋지 않다)<img src="https://velog.velcdn.com/images/dolphin-pc/post/da8bdbf7-82e6-42f3-8152-f6d0e17faee1/image.png" alt=""></p>
</li>
</ul>
<blockquote>
<p>👍 필요한 인스턴스가 런타임에 동적으로 결정될 때 유용하다.</p>
</blockquote>
<h3 id="3-추상-팩토리">3. 추상 팩토리</h3>
<blockquote>
<p>구체적인 내용을 지정하지 않고, 관련된 것들을 그룹화한다.</p>
</blockquote>
<pre><code class="language-ts">interface Door {
    getDesc() : void; 
}

class ADoor implements Door {
     getDesc() {
          console.log(&quot;ADoor&quot;);    
    }
}

class BDoor implements Door {
     getDesc() {
          console.log(&quot;BDoor&quot;);    
    }
}

----

interface DoorMan {
     fix() : void;
}

class ADoorMan implements DoorMan {
     fix() {
        console.log(&#39;난 15달러&#39;);
    }    
}

class BDoorMan implements DoorMan {
     fix() {
        console.log(&#39;난 4달라&#39;);
    }    
}

---

interface DoorFactory {
     getDesc(): Door;
      fix(): DoorMan;
}


class ADoorFactory implements DoorFactory {
     getDesc(): Door {
          return new ADoor();
    }

      fix(): DoorMan {
         return new ADoorMan(); 
    }
}

class BDoorFactory implements DoorFactory {
     getDesc(): Door {
          return new BDoor();
    }

      fix(): DoorMan {
         return new BDoorMan(); 
    }
}</code></pre>
<p>이처럼, Factory안에서는 구현내용없이, 관련된 내용을 그룹화하고 return하는 내용밖에 없다.</p>
<blockquote>
<p>👍  상호 의존성이 있고, 복잡한 생성로직이 있는 경우 유용하다.</p>
</blockquote>
<h3 id="4-생성자-builder">4. 생성자 (Builder)</h3>
<ul>
<li>contructor의 오염을 방지하면서, 다양한 타입의 객체를 생성하기에 유용하다.</li>
<li>서브웨이에서 주문하는 방법과 비슷하다.<ol>
<li>빵은 미디움으로 주시고요.</li>
<li>야채는 빼주시고,</li>
<li>치킨, 계란 넣어주시고,</li>
<li>15cm로 하고,</li>
<li>결제하고, 빵을 받는다.</li>
</ol>
</li>
</ul>
<pre><code class="language-ts">// 생성자를 이용한 방식
class Burger {
  protected size: number;
  protected cheese: boolean = false;
  protected pepperoni: boolean = false;
  protected lettuce: boolean = false;
  protected tomato: boolean = false;

  constructor(builder: BurgerBuilder) {
    this.size = builder.size;
    this.cheese = builder.cheese;
    this.pepperoni = builder.pepperoni;
    this.lettuce = builder.lettuce;
    this.tomato = builder.tomato;
  }
}

class BurgerBuilder {
  public size: number;
  public cheese: boolean = false;
  public pepperoni: boolean = false;
  public lettuce: boolean = false;
  public tomato: boolean = false;

  constructor(size: number) {
    this.size = size;
  }

  addPepperoni(): BurgerBuilder {
    this.pepperoni = true;
    return this;
  }

  addLettuce(): BurgerBuilder {
    this.lettuce = true;
    return this;
  }

  addCheese(): BurgerBuilder {
    this.cheese = true;
    return this;
  }

  addTomato(): BurgerBuilder {
    this.tomato = true;
    return this;
  }

  build(): Burger {
    return new Burger(this);
  }
}

// 활용
const burger = new BurgerBuilder(14)
  .addPepperoni()
  .addLettuce()
  .addTomato()
  .build();
</code></pre>
<blockquote>
<p>👍 객체의 생성이 여러단계에 걸쳐야 할 때 유용하다.</p>
</blockquote>
<h3 id="5-프로토타입">5. 프로토타입</h3>
<blockquote>
<p>객체를 복사하여, 새로운 객체를 생성한다.</p>
</blockquote>
<ul>
<li><code>Object.create</code>로 간단하게 수행가능하다.<pre><code class="language-ts">const original: Sheep = new Sheep(&quot;A&quot;);
// original
//   name : &quot;A&quot;
//   category : &quot;sheep&quot;
</code></pre>
</li>
</ul>
<p>const clone: Sheep = Object.create(original);
clone.setName(&quot;B&quot;)
// clone
//   name : &quot;B&quot;
//   category : &quot;sheep&quot;</p>
<pre><code>
&gt; 👍 기존 객체와 유사한 객체가 필요하거나, 생성 비용이 많이 드는 경우 유용하다.


### 6. 싱글톤
&gt; 특정 클래스의 객체가 한번만 생성되도록 한다.
⚠️ 싱글톤은 안티패턴으로 분류된다. 일부사례에서 유용하긴 하나, 주의해서 사용해야 한다.

- `생성자`, `복제`, `확장`을 `비활성화`하고, 특정 메소드로만 인스턴스 get이 가능하다.

```ts
// 대통령을 예시로 들어보겠습니다. (대통령은 1명 뿐이니)

class President {
     private static instance: President;

    private constructor() {}

    private clone(){}
    private wakeup(){}

    public static getInstance: President {
         if(!President.instance) {
             President.instance = new Presiden(); 
        }

      return President.instance;
    }
}

const president1: President = President.getInstance();
const president2: President = President.getInstance();

console.log(president1 === president2); // true</code></pre><hr>
<p>구조패턴은 다음편에...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2024 이노캠] 사전과정 4/5일차 (5/31)]]></title>
            <link>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-45%EC%9D%BC%EC%B0%A8-531</link>
            <guid>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-45%EC%9D%BC%EC%B0%A8-531</guid>
            <pubDate>Fri, 31 May 2024 13:33:02 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며..</h1>
<ul>
<li>4일차는 복습날, 오늘은 3주차 강의를 진행하는 날이다.</li>
</ul>
<h2 id="오늘-공부할것">오늘 공부할것</h2>
<ul>
<li>JS 3주차 : 데이터 타입(심화), 실행 컨텍스트, this</li>
</ul>
<h3 id="3-1-데이터타입의-종류-및-메모리">3-1. 데이터타입의 종류 및 메모리</h3>
<ul>
<li><p>기본형 (Primitive type)</p>
<ul>
<li>Number</li>
<li>String</li>
<li>Boolean</li>
<li>null</li>
<li>undefined</li>
<li>Symbol</li>
</ul>
</li>
<li><p>참조형 (Reference type)</p>
<ul>
<li>Object<ul>
<li>Array</li>
<li>Function</li>
<li>Date</li>
<li>RegExp</li>
<li>Map, WeakMap</li>
<li>Set, WeakSet</li>
</ul>
</li>
</ul>
</li>
<li><p>구분 기준</p>
</li>
</ul>
<ol>
<li><p>복제여부</p>
<ul>
<li>기본형 : 값이 담긴 주소값을 바로 복제</li>
<li>참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제</li>
</ul>
</li>
<li><p>불변성의 여부 (메모리 관점)</p>
<ul>
<li>기본형 : 불변성<ul>
<li>이게 무슨말이냐, let a=10이라고 했을 때, a=20 으로 했을 때 a변수가 가리키는 주소값 자체는 변경되지만, 10값이 할당된 <code>메모리</code>는 그대로 남아있다. (이후 가비지 콜렉터가 수거해감)</li>
</ul>
</li>
<li>참조형 : 불변성을 띄지 않음<ul>
<li>데이터 묶음을 가리키는 주소값 자체가 바뀌므로, 변동성이 있다고 볼 수 있음</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr>
<ul>
<li>메모리 : 비트, 바이트</li>
</ul>
<h3 id="3-2-변수-선언과-데이터-할당기본형데이터">3-2. 변수 선언과 데이터 할당(기본형데이터)</h3>
<ul>
<li>값 자체를 해당 주소에 저장하기 때문에, 값이 변경될 경우 주소값이 변경되지 <code>값은 변경되지 않기 떄문에 (메모리 관점에서 불변하다)</code> 라고 볼 수 있음</li>
<li>값이 새로이 추가가 될 경우에는, 해당 값을 데이터 영역에 <code>새로 추가하고</code> 그의 주소값을 a변수로 지정한다.</li>
<li>이를 <code>데이터 관점</code>에서 보았을 때, <code>값이 추가가 될뿐 변경이 되지 않아 불변하다</code>라고 볼 수 있다. </li>
</ul>
<h3 id="3-3-변수-선언과-데이터-할당참조형데이터">3-3. 변수 선언과 데이터 할당(참조형데이터)</h3>
<ul>
<li>값의 묶음 주소값을 해당 주소에 저장하기 떄문에, 값이 변경될 경우 해당 주소값을 바꾼다.</li>
<li>obj -&gt; (obj의 값들을 가리키는 주소값) -&gt; (obj의 실제 데이터가 있는 곳)</li>
<li>obj의 값이 변경되었을 때, <code>(obj의 값들을 가리키는 주소값)</code> 이 부분이 변경되기에, <code>가변</code> 하다라고 본다.</li>
</ul>
<h3 id="3-4-불변-객체얕은-복사-깊은-복사">3-4. 불변 객체(얕은 복사 깊은 복사)</h3>
<ul>
<li>객체를 할당받는다면, 그것은 복사가 아닌 주소값을 공유한다 라고 볼 수 있다.<pre><code class="language-js">const obj = {}
const obj2 = obj;
</code></pre>
</li>
</ul>
<p>console.log(obj == obj2) // true</p>
<pre><code>
- 그러므로, 객체를 공유받는 것이 아닌 값자체를 복사하려면 새로운 객체를 생성하고, 값을 하나하나 복사하는 수밖에 없다.
```js
const arr = [1,2,3];
function copy(arr) {
     let res_arr=[];
      arr.forEach(ele =&gt; res_arr.push(ele))
    return res_arr;
}

const arr2 = copy(arr);

console.log(arr == arr2) // false</code></pre><ul>
<li>중첩객체에 대해 모든 것을 복사하려거든, 재귀를 통한 깊은복사밖에 답이 없다. (아니면 <code>JSON.stringify</code>로 변환한 다음, 다시 <code>JSON.parse</code> 하던가</li>
</ul>
<h3 id="3-5-null과-undefined">3-5. null과 undefined</h3>
<ul>
<li>undefined : 정의되지 않음, 진짜 값이 없음 (개발자가 한거 아님)</li>
<li>null : 정의되지 않음, 의도된 값이 없음을 의미 (개발자가 한 짓임)</li>
</ul>
<h3 id="3-6-실행-컨텍스트-및-콜-스택">3-6. 실행 컨텍스트 및 콜 스택</h3>
<ul>
<li>실행 컨텍스트? 코드가 실행될 환경정보가 있는 곳</li>
<li>JS는 위-&gt;아래 순서로 코드를 읽어가면서, 값들을 스택으로 쌓아둔다. (=&gt; 콜스택)</li>
</ul>
<h3 id="3-78-record와-호이스팅">3-7/8. record와 호이스팅</h3>
<ul>
<li>Context는 위-&gt;아래 순서로 Call Stack으로 쌓인다고 했는데, 쌓으면서 아래와 같은 짓을 한다.</li>
</ul>
<ol>
<li>VariableEnvironment 저장<ul>
<li>현재 컨텍스트의 식별자정보 저장, <code>변수a</code>라는 놈을 기억하고 있겠다. <code>(현재의 기억)</code></li>
</ul>
</li>
<li>LexicalEnvironment <ul>
<li>선언적 어휘환경 저장, 선언된 시점에서의 데이터를 기억하고 있음 <code>(태어날 때의 기억)</code></li>
</ul>
</li>
<li>thisbinding<ul>
<li><del>그놈의 THIS!!!</del> this가 바라봐야할 객체를 기억하고 있는다. <code>(부모님을 기억하고 있는다고 보면 됨)</code></li>
</ul>
</li>
</ol>
<ul>
<li>호잇!스팅 : 선언된 모든 것들은 머리채잡혀서 위로 올라가진다.<ul>
<li>하지만, const/class 같은 놈들은 <code>TDZ</code>라는 것에 의해 잡혀 올라가지더라도, 선언된 위치 이전에 사용하면 오류를 던져준다.</li>
</ul>
</li>
</ul>
<h3 id="3-9-outerenvironmentreference">3-9. outerEnvironmentReference</h3>
<ul>
<li>3.6에서 <code>콜스택</code> 형태로, 모든 정보를 기억하고 있는 댔다.</li>
<li>콜스택으로 들어가기전, 자신의 조상을 기억하고 들어간다 (=&gt;outerEnvironmentReference)</li>
<li>그 즉슨, 현재 Context에 없는 놈을 개발자가 찾으라고 명령한다면, 이놈들은 문밖으로 뛰쳐나가 어떻게든 찾아오려고 노력한다. <code>(밖에 있는 경우에만 찾을 수 있음)</code></li>
<li>이것을 <code>스코프 체인</code> 이라고 한다.</li>
<li><code>Inner -&gt; Outer -&gt; Global</code></li>
</ul>
<h3 id="3-10-상황에-따라-달라지는-this">3-10. 상황에 따라 달라지는 this</h3>
<ul>
<li>this는 Function이 함수실행이냐, 메소드실행이냐에 따라 달라진다. (엥 이게 뭔 소리여)</li>
<li>this가 정해지는 시점은 <code>콜스택에 들어가는 시점</code>이라고 했다.</li>
<li>그 즉슨, 함수가 실행되는 시점에 따라 this가 달라진다는 것인데
함수실행(독립적)으로 된다면 this는 Global을 가리키고,
메소드(객체에 붙어있는)으로 된다면 this는 객체를 가리킨다.</li>
<li><code>독립적</code> 여부에 따라 this가 달라진다.<ul>
<li>내부함수 이더라도, 독립적으로 실행된다면 this는 global을 가리킨다.</li>
</ul>
</li>
</ul>
<h3 id="3-11-this우회방법-콜백함수-this-생성자함수-this">3-11. this우회방법 콜백함수 this 생성자함수 this</h3>
<h4 id="this-우회방법">this 우회방법</h4>
<ul>
<li>this를 명시적으로 가리키기 위해, <code>that/self</code> 와 같은 변수에 this를 공유해두는 방법도 있다.<pre><code class="language-js">let that = this;</code></pre>
</li>
<li>또한, <code>Arrow Function</code>의 경우에는, <code>ThisBinding</code>이 포함되지 않아 독립적이든 아니든 선언시점에서의 this를 기억하고 있는다. (렉시컬 스코프)</li>
</ul>
<h4 id="콜백함수에서의-this">콜백함수에서의 this</h4>
<ul>
<li>this를 별도로 지정해주지 않았다면, this -&gt; global 을 가리킨다.</li>
<li>addEventListener 메소드의 경우, this는 메소드를 실행시킨 장본인을 가리킨다. (button.addEvent 였다면, this -&gt; button을 가리킨다.)</li>
</ul>
<h4 id="new-생성자함수에서의-this">new 생성자함수에서의 this</h4>
<ul>
<li>new로 만들어진 놈은 <code>인스턴스</code>임</li>
<li>new로 생성될 경우, 인스턴스 자신을 가리킴</li>
</ul>
<h3 id="3-12-명시적-this바인딩-및-유사배열-객체">3-12. 명시적 this바인딩 및 유사배열 객체</h3>
<h4 id="명시적-this바인딩">명시적 this바인딩</h4>
<ul>
<li>call, apply, bind<ul>
<li>call 메소드 실행시, 첫번째 인자에 this가 바인딩될 객체가 들어가고, 이후 값들은 개별적으로 들어감<pre><code class="language-js">func.call(obj, 1,2,3,4);</code></pre>
</li>
<li>apply 메소드는 call과 동일하나, 이후 값들을 배열로 묶어서 들어감<pre><code class="language-js">func.call(obj, [1,2,3,4]);</code></pre>
</li>
<li>bind 메소드는 call과 들어가는 것은 동일하나, 즉시실행되지 않고 바인딩된 값을 return 해준다. (나중에 이 함수를 실행하도록 저장해둘 수 있다.)</li>
</ul>
</li>
</ul>
<h4 id="유사배열-객체">유사배열 객체</h4>
<ul>
<li>배열이랑 비슷하게 생긴 객체놈이 배열이랑 하는 짓을 똑같이 할 수 있음<pre><code class="language-js">const 배열비슷하게_생긴_놈 = {
   0: &#39;1&#39;,
    1: &#39;2&#39;,
    2: &#39;3&#39;,
    length : 3
}
</code></pre>
</li>
</ul>
<p>Array.prototype.push.call(배열비슷하게_생긴_놈, &#39;d&#39;)
console.log(배열비슷하게_생긴_놈) // {0: &#39;1&#39;, 1: &#39;2&#39;,2: &#39;3&#39;,3: &#39;d&#39;, length : 4 }
}</p>
<p>```</p>
<h3 id="313-call-apply-bind-응용">3.13. call apply bind 응용</h3>
<ul>
<li>call, apply는 this가 될 놈을 첫번째 인자로 넣어주면 되고</li>
<li>bind는 call이랑 똑같으나, 지금 당장말고 나중에 실행되야 할때 쓰임</li>
</ul>
<h3 id="숙제-실행-컨텍스트-더-알아보기">숙제. 실행 컨텍스트 더 알아보기</h3>
<ul>
<li>this를 활용한 실행컨텍스트 문제</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2024 이노캠] 사전과정 3일차 (5/29)]]></title>
            <link>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-3%EC%9D%BC%EC%B0%A8-529</link>
            <guid>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-3%EC%9D%BC%EC%B0%A8-529</guid>
            <pubDate>Wed, 29 May 2024 11:42:37 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며..</h1>
<h2 id="오늘-공부할것">오늘 공부할것</h2>
<ul>
<li>JS 2주차 1강 ~ 6강</li>
</ul>
<h3 id="12강-es6-문법-소개-및-실습-12">1/2강 ES6 문법 소개 및 실습 (1/2)</h3>
<ul>
<li>let, const</li>
<li>화살표 함수<ul>
<li>this가 없어, 렉시컬 스코프에 의해 this가 바인딩된다. (선언 시점)</li>
</ul>
</li>
<li>삼항 연산자 (? :)</li>
<li>구조분해할당</li>
<li>단축 속성명<ul>
<li>객체에 value를 지정할 때, key의 값과 value의 변수값이 일치하다면 skip이 가능함</li>
</ul>
</li>
<li>전개구문 (spread, ...arr)</li>
<li>나머지 매개변수 (...args)</li>
<li>템플릿 리터럴 (``, ${})</li>
<li>named export, default export</li>
</ul>
<h3 id="34강-일급개체로의-함수-12">3/4강 일급개체로의 함수 (1/2)</h3>
<ul>
<li>일급객체란, 아래와 같은 조건을 만족할 때 일컫는 말이다.</li>
</ul>
<ol>
<li>변수에 함수를 할당</li>
<li>함수의 파라미터로 함수를 전달</li>
<li>함수를 반환</li>
<li>객체의 프로퍼티로 함수를 할당</li>
<li>배열의 요소로 함수를 할당</li>
</ol>
<ul>
<li>이처럼, 함수가 일급객체로 취급되기 때문에, JS에서 함수를 매우 유연하게 사용할 수 있다.</li>
</ul>
<h3 id="5강-map-소개-및-예시코드-연습">5강 Map 소개 및 예시코드 연습</h3>
<ul>
<li>key-value 형태의 객체<ul>
<li>set() : 저장</li>
<li>get() : value 조회</li>
<li>delete : 키-값 쌍 삭제</li>
<li>clear : Map 내용 전체 삭제</li>
<li>size : Map 크기</li>
</ul>
</li>
</ul>
<h3 id="6강-set-소개-및-예시코드-연습">6강 Set 소개 및 예시코드 연습</h3>
<ul>
<li>고유한 값만을 저장하는 배열(과 유사한형태)</li>
</ul>
<h3 id="숙제-배열-연습하기">숙제. 배열 연습하기</h3>
<ul>
<li>문자열의 특정 index번째에 따라, 배열 정렬문제</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2024 이노캠] 사전과정 2일차 (5/28)]]></title>
            <link>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-2%EC%9D%BC%EC%B0%A8-528</link>
            <guid>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-2%EC%9D%BC%EC%B0%A8-528</guid>
            <pubDate>Tue, 28 May 2024 09:53:09 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며..</h1>
<h2 id="오늘-공부할것">오늘 공부할것</h2>
<ul>
<li>JS 1주차 9강 ~ 15강</li>
</ul>
<h3 id="9강-조건문">9강. 조건문</h3>
<ul>
<li>if, else if, else, switch, 삼항 연산자</li>
</ul>
<h3 id="10강-조건문-중첩">10강. 조건문 중첩</h3>
<ul>
<li>조건문 중첩, <code>||</code> <code>&amp;&amp;</code> 단축 평가</li>
<li>falsy, truthy<h3 id="11강-객체">11강. 객체</h3>
</li>
<li>객체, new 생성자를 통한 객체 생성</li>
<li>Object, keys() values() entrise() assign()</li>
<li>객체 비교, 객체 병합<h3 id="1213강-배열-12">12/13강. 배열 1/2</h3>
</li>
<li>[], Array</li>
<li>push(), pop(), shift(), unshift(), slice(), splice(), forEach(), map(), filter(), reduce(), find(), some(), every(), sort(), reverse()<h3 id="14강-for문">14강. for문</h3>
</li>
<li>for, for-of, for-in, while, do-while<h3 id="15강-break-continue">15강. break continue</h3>
</li>
<li>break : 반복문 종료</li>
<li>continue : 스킵<h3 id="숙제">숙제</h3>
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/12916">문자열 연습하기</a>
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/76501">반복문, 조건문 연습하기</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2024 이노캠] 사전과정 1일차 (5/27)]]></title>
            <link>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-1%EC%9D%BC%EC%B0%A8-527</link>
            <guid>https://velog.io/@dolphin-pc/2024-%EC%9D%B4%EB%85%B8%EC%BA%A0-%EC%82%AC%EC%A0%84%EA%B3%BC%EC%A0%95-1%EC%9D%BC%EC%B0%A8-527</guid>
            <pubDate>Mon, 27 May 2024 07:26:50 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며..</h1>
<p>오늘은 이노캠 개강전, 1.5주간의 사전준비과정에 돌입했다.
30분가량 강사님의 과정에 대한 설명을 간략히 듣고, <code>게더</code>를 통해 4명의 팀원과 인사를 마치고, 각자 공부를 하고 7시에 다시 모이기로 했다.</p>
<h2 id="오늘-공부할것">오늘 공부할것</h2>
<ul>
<li>5/27(월) : 환경설정 및 1주차 1-8<ul>
<li>JS, VS code 등 개발에 필요한 환경설정</li>
<li>스파르타코딩클럽 1주차, 1강 ~ 8강</li>
</ul>
</li>
</ul>
<hr>
<h2 id="1-환경설정">1. 환경설정</h2>
<blockquote>
<p><a href="https://hh99.gitbook.io/onboarding-js/part-01.-hello-world/0.-../javascript">https://hh99.gitbook.io/onboarding-js/part-01.-hello-world/0.-../javascript</a></p>
</blockquote>
<ul>
<li>Node.js, VScode</li>
</ul>
<hr>
<h2 id="2-스파르타코딩클럽-1주차-1강--8강">2. 스파르타코딩클럽 1주차, 1강 ~ 8강</h2>
<blockquote>
<p>1주차 주요 내용 : 자바스크립트 기본 문법</p>
</blockquote>
<h3 id="1주차---1강-자바스크립트-소개">1주차 - 1강. 자바스크립트 소개</h3>
<ol>
<li>JS언어의 역사</li>
<li>JS언어의 특징<ol>
<li>객체지향 프로그래밍 지원<ul>
<li>Object {}</li>
</ul>
</li>
<li>동적 타이핑<ul>
<li>런타임시, 변수의 타입 <code>변동적으로</code>지정</li>
</ul>
</li>
<li>함수형 프로그래밍 지원<ul>
<li><code>일급객체</code> : 함수를 일반 값과 마찬가지로 변수에 할당하거나, 함수의 인자로 전달/반환값으로 사용할 수 있는 객체</li>
</ul>
</li>
<li>비동기 처리<ul>
<li>동기적이지 못한(ex. API통신) 구간에 대한 응답을 기다리지 않고, 병렬로 처리할 수 있도록 하는 방식</li>
</ul>
</li>
<li>클라이언트/서버 측 모두 사용가능<ul>
<li>JS의 모태는 웹 브라우저에서 사용하기 위했지만, Node.js의 발전으로 인해 서버측에서도 사용이 가능함</li>
</ul>
</li>
</ol>
</li>
</ol>
<h3 id="1주차---2강-변수와-상수">1주차 - 2강. 변수와 상수</h3>
<ul>
<li>변수 : <code>var</code> <code>let</code> <code>const</code></li>
<li>상수 : <code>const</code></li>
</ul>
<h3 id="1주차---34강-데이터-타입">1주차 - 3/4강. 데이터 타입</h3>
<ul>
<li>데이터 타입 : 숫자, 문자열, 불리언, undefined, null, Object, Array</li>
</ul>
<h3 id="1주차---5강-형변환">1주차 - 5강. 형변환</h3>
<ul>
<li><strong>암시적 형 변환</strong> : JS에서 자동으로 수행되는 형 변환, 일반적으로 연산자를 사용할 때 발생<ul>
<li>문자열 변환</li>
<li>숫자 변환</li>
<li>불리언 변환</li>
</ul>
</li>
<li><strong>명시적 형 변환</strong> : 직접 자료형을 변환하는 것<ul>
<li>문자열 변환</li>
<li>숫자 변환</li>
</ul>
</li>
</ul>
<h3 id="1주차---6강-연산자">1주차 - 6강. 연산자</h3>
<ul>
<li>산술연산자 : + - * / %</li>
<li>할당연산자 : = += -= *= /= %=</li>
<li>비교연산자 : == === != &lt; &gt;</li>
<li>논리연산자 : &amp;&amp; ||</li>
<li>삼항연산자 : ? :</li>
<li>타입연산자 : typeof</li>
</ul>
<h3 id="1주차---7강-함수">1주차 - 7강. 함수</h3>
<ul>
<li><p>함수 선언문</p>
<pre><code class="language-ts">function add(x,y) {}</code></pre>
</li>
<li><p>함수 표현식</p>
<pre><code class="language-ts">let add = function (x,y) {}</code></pre>
</li>
</ul>
<h3 id="1주차---8강-스코프와-화살표-함수">1주차 - 8강. 스코프와 화살표 함수</h3>
<ul>
<li><p>스코프(scope)란, 현재 실행되고 있는 Context로 값이 표현되거나 참조될 수 있는 환경을 말함.</p>
<ul>
<li>전역 스코프 (Global scope) : 어디서든 참조할 수 있는 환경</li>
<li>지역 스코프 (Local scope) : 특정 함수안에서만 참조할 수 있는 환경</li>
<li>블록 스코프 (Block scope) : if, for문과 같이 {}에 둘러쌓여 있는 환경</li>
</ul>
</li>
<li><p>화살표 함수 </p>
<ul>
<li>화살표 함수는 ES6문법에서 나온 것으로, 함수선언을 <code>=&gt;</code>지정어로 간결하게 표현할 수 있으며 내부적 this바인딩이 존재하지 않아, 중첩함수안에서 사용될 경우, 렉시컬 스코프에 의해서 this는 선언된 객체를 가리킨다.
(화살표 함수가 선언된 곳의 객체가 <code>this</code>가 된다)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[VS code, Code Snippet]]></title>
            <link>https://velog.io/@dolphin-pc/VS-code-Code-Snippet</link>
            <guid>https://velog.io/@dolphin-pc/VS-code-Code-Snippet</guid>
            <pubDate>Fri, 24 May 2024 03:03:20 GMT</pubDate>
            <description><![CDATA[<h1 id="code-snippet">Code Snippet</h1>
<ul>
<li>Code Snippet이란, 자주 사용되는 <code>코드 조각</code>을 말한다.</li>
<li>단축키로 하여금, 코드를 불러올 수가 있다.</li>
</ul>
<pre><code class="language-ts">// rafce

import React from &#39;react&#39;

const page = () =&gt; {
  return (
    &lt;div&gt;page&lt;/div&gt;
  )
}

export default page</code></pre>
<h1 id="vs-code-설정">VS code 설정</h1>
<h3 id="1-commandsshiftp-로-커맨드-패널을-연다">1. <code>Commands+Shift+P</code> 로 커맨드 패널을 연다.</h3>
<h3 id="2-configure-user-snippets-선택">2. <code>Configure User Snippets</code> 선택</h3>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/0802f862-0126-42d3-ac39-3cba8fb7756d/image.png" alt=""></p>
<h3 id="3-코드-스니펫이-적용될-위치를-적용한다">3. 코드 스니펫이 적용될 위치를 적용한다.</h3>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/76c2edcd-4035-4b30-8287-c490ff9757b6/image.png" alt=""></p>
<h3 id="4-코드-스니펫의-제목을-작성한다">4. 코드 스니펫의 제목을 작성한다.</h3>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/4129bbd2-9795-4f05-9a6a-ddfcf67c1e7e/image.png" alt=""></p>
<h3 id="5-코드-스니펫-작성">5. 코드 스니펫 작성</h3>
<ul>
<li>객체의 제목 : 구별할 수 있을 정도로만 적당히 작명한다.</li>
<li>prefix : 스니펫을 불러올 단축어</li>
<li>body : 스니펫 코드
<img src="https://velog.velcdn.com/images/dolphin-pc/post/84f94e56-6e90-4362-aae4-930781a9c96d/image.png" alt=""><blockquote>
<p>$1 $2 와 같은 특수지정어가 존재하는데, 이는 코드 스니펫을 읽어온 직후 사용자의 cursor를 해당 위치하게 해준다.</p>
</blockquote>
</li>
</ul>
<blockquote>
<p>TIP : 코드 스니펫 본문을 작성할 때, ``(백틱이 불가능하다)
<a href="https://snippet-generator.app/">https://snippet-generator.app/</a> 이 사이트를 이용하면 본문코드를 snippet으로 변환해준다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모투] Recoil, selectorFamily를 활용한 렌더링 최적화]]></title>
            <link>https://velog.io/@dolphin-pc/%EB%AA%A8%ED%88%AC-Recoil-selectorFamily%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@dolphin-pc/%EB%AA%A8%ED%88%AC-Recoil-selectorFamily%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Tue, 21 May 2024 08:40:49 GMT</pubDate>
            <description><![CDATA[<h1 id="들어가며">들어가며</h1>
<h2 id="배경">배경</h2>
<ul>
<li>특정Tab을 클릭하면, Accordion 컴포넌트의 <code>open</code> state값을 변경시켜 Accordion을 열고자 했다.</li>
<li>아래 이미지를 보면, Tab제목이나 Accordion버튼을 클릭할 때마다, 모든 컴포넌트가 재렌더링되는 문제가 있었다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/938426c1-445e-48b3-98b8-8bbb789c2a23/image.gif" alt=""></li>
</ul>
<h2 id="소스구조">소스구조</h2>
<ol>
<li>바탕이 되는 컴포넌트 <code>TabScroll</code>는 <code>useTabScroll(hooks)</code>에서 Recoil데이터를 선언하고, <code>Tab제목</code>컴포넌트와 <code>Accordion</code>컴포넌트를 하위 자식으로 가진다.</li>
</ol>
<pre><code class="language-ts">// TabScroll.tsx
const TabScroll = ({
  groupLikeStockList,
}: {
  groupLikeStockList: TGroupLikeStockInfo[];
}) =&gt; {
  // [registryRef]의 tabIndex로 스크롤될 컴포넌트의 ref배열에 등록한다.
  // [handleScroll]로 지정된 컴포넌트 클릭시, ref배열의 위치로 스크롤 및 ref컴포넌트의 Accordion을 열어준다.
  const { registryRef, handleScroll, headerRef } = useTabScroll({
    length: groupLikeStockList.length,
  });
  ...
  return (
    ...
    // Tab제목 컴포넌트
    {groupLikeStockList.map((group, idx) =&gt; {
        return (
            &lt;Button key={idx} tabIndex={idx} onClick={handleScroll}&gt;
                {group.groupName}
            &lt;/Button&gt;
        );
    })}
    ...
    // Accordion컴포넌트
    {groupLikeStockList.map((group, idx) =&gt; {
        return (
          &lt;div key={idx} tabIndex={idx} ref={registryRef}&gt;
            &lt;Section.Accordion
              index={idx}
              title={group.groupName}
              noContent={&lt;Button primary&gt;주식 추가하기&lt;/Button&gt;}
            &gt;
              {group.likeStockInfoList.length &amp;&amp;
                group.likeStockInfoList.map((likeStock, idx) =&gt; {
                  return (
                    &lt;div
                      key={idx}
                      className=&quot;flex items-center justify-between&quot;
                    &gt;
                      &lt;p&gt;
                        {likeStock.name} ({likeStock.stockId})
                      &lt;/p&gt;
                      &lt;Button primary&gt;BUY&lt;/Button&gt;
                    &lt;/div&gt;
                  );
                })}
            &lt;/Section.Accordion&gt;
          &lt;/div&gt;
        );
      })}
  )
}</code></pre>
<pre><code class="language-ts">// useTabScroll.ts | hooks함수
export const useTabScroll = ({ length }: { length: number }) =&gt; {
    const [isOpenTabList, setIsOpenTabList] = useRecoilState(tabOpenStateList);

    // 버튼 클릭시, ref에 등록된 element로 스크롤 이동
    const handleScroll = (e: MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
        const tabIndex = e.currentTarget.tabIndex;
            ...
            setIsOpenTabList(() =&gt; {
                const newState = [...isOpenTabList];
                newState[tabIndex] = true;
                return newState;
            });
        }
  };
})

// 
</code></pre>
<ol start="2">
<li>recoil의 atom에는 <code>tabOpenStateList</code>가 등록되어있다.<pre><code class="language-ts">export const tabOpenStateList = atom&lt;boolean[]&gt;({
key: &quot;tabOpenStateList&quot;,
default: [],
});</code></pre>
</li>
</ol>
<h2 id="문제원인">문제원인</h2>
<ul>
<li>Tab을 클릭할 때마다 실행되는 <code>setIsOpenTabList</code>부분에서 <code>recoil의 전체 상태값이 변경</code>되어, 모든 컴포넌트가 재렌더링된다고 생각되었다.<pre><code class="language-ts">setIsOpenTabList(() =&gt; {
  const newState = [...isOpenTabList];
  newState[tabIndex] = true;
  return newState;
});</code></pre>
</li>
<li>그래서 이러한 <code>isOpenTabList</code> state배열을 잘게 잘라서 사용할 수 있도록 <code>selectorFamily</code>를 활용하였다.</li>
</ul>
<h2 id="적용">적용</h2>
<pre><code class="language-ts">// atoms/tab.ts
import { DefaultValue, atom, selectorFamily } from &quot;recoil&quot;;

export const tabOpenStateList = atom&lt;boolean[]&gt;({
  key: &quot;tabOpenStateList&quot;,
  default: [],
});

export const tabOpenState = selectorFamily({
  key: &quot;tabOpenState&quot;,
  get:
    (tabIndex: number) =&gt;
    ({ get }) =&gt; {
      return get(tabOpenStateList)[tabIndex];
    },
  set:
    (tabIndex: number) =&gt;
    ({ set }, newValue: boolean | DefaultValue) =&gt; {
      set(tabOpenStateList, (prev) =&gt; {
        const newState = [...prev];
        if (!(newValue instanceof DefaultValue)) {
          newState[tabIndex] = newValue;
        }
        return newState;
      });
    },
});
</code></pre>
<ul>
<li>이처럼 <code>TabIndex</code>값에 따라 <code>tabOpenStateList</code>에서 특정요소만 get/set할 수 있도록 설정했다.</li>
</ul>
<h3 id="활용">활용</h3>
<pre><code class="language-ts">// useTabScroll.ts
  const setOpenList = Array(length)
    .fill(false)
    .map((_, idx) =&gt; useSetRecoilState(tabOpenState(idx)));
...

// 버튼 클릭시, ref에 등록된 element로 스크롤 이동
  const handleScroll = (e: MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
    const tabIndex = e.currentTarget.tabIndex;
    if (tabBodyRef.current) {
      (tabBodyRef.current[tabIndex] as HTMLDivElement).scrollIntoView({
        behavior: &quot;smooth&quot;,
        block: &quot;start&quot;,
        inline: &quot;nearest&quot;,
      });
      setOpenList[tabIndex](true);
    }
  };</code></pre>
<ul>
<li>위와 같이, <code>tabOpenState</code> selectorFamily를 배열의 수만큼 <code>setOpenList</code>변수에 미리 할당해둔다.<blockquote>
<p>이처럼 적용한 이유!
handleScroll함수가 실행될 때, 비로소 openState값이 바뀌어야 하기에 <code>useSetRecoilState</code>를 함수내부에서 사용할 수 있도록 <code>미리 선언</code>해주어야 했다.</p>
<p>React hooks의 선언 규칙은 항상 최상단에서 이루어져야 하기에, 위와 같이 <code>setOpenList</code>에 미리 담아주었다.</p>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/869bb344-77e8-405c-ad58-849114f626b1/image.png" alt=""></p>
<ul>
<li>자주 접하는 에러...</li>
<li>이처럼 적용하고, Accordion 컴포넌트에서도 index에 맞는 selector를 가져오도록 작성해주었다.
<img src="https://velog.velcdn.com/images/dolphin-pc/post/2dc6986a-f496-4c2b-accd-ffd67935762a/image.png" alt=""></li>
</ul>
<h1 id="그-결과">그 결과!</h1>
<p><img src="https://velog.velcdn.com/images/dolphin-pc/post/39b1694b-7fd1-4ac9-80ec-4a9b75053f9b/image.gif" alt=""></p>
<ul>
<li>다음과 같이, tab클릭 &amp; accordion버튼 클릭 시에도, 해당 컴포넌트만 re-render되도록 최적화할 수 있었다!!</li>
</ul>
<h3 id="수정된-소스코드">수정된 소스코드</h3>
<p><a href="https://github.com/Dolphin-PC/motoo/commit/500f93424fbf21b188545aa5dd7745d6f57f21ed">https://github.com/Dolphin-PC/motoo/commit/500f93424fbf21b188545aa5dd7745d6f57f21ed</a></p>
<h2 id="20240523-수정">2024.05.23 수정</h2>
<ul>
<li><strong><em>selectorFamily -&gt; atomFamily로 수정</em></strong></li>
<li>처음에는 atom으로 선언된 배열에 대해서, get/set을 할 수 있는 selectorFamily를 사용했다.</li>
<li>하지만, selectorFamily와 atomFamily의 기능이 거의 유사한 것을 알 수 있었고, 이는 <code>사용목적</code>에 따라 구분되어 있다는 것을 알 수 있었다.<ul>
<li>atomFamily : 동적인 키를 가진 atom의 집합 (동일한 상태를 공유해야 하는 여러 컴포넌트에 용이)</li>
<li>selectorFamily : 동적인 키를 가진 selector의 집합 (atom값에 계산을 하거나, 비동기작업을 수행하는 데 사용)</li>
</ul>
</li>
<li>이를 보았을 때, 내 상황에서는 <code>atomFamily</code>가 적합하다고 생각하여 코드를 리팩토링했다 (더 간결해졌다!)<pre><code class="language-ts">// atoms/tab.ts
</code></pre>
</li>
</ul>
<p>export const tabOpenStateList = atomFamily&lt;boolean, number&gt;({
  key: &quot;openList&quot;,
  default: () =&gt; false,
});
// atom관련한 코드가 이렇게 짧아졌다.</p>
<p>```</p>
<h1 id="3줄-요약">3줄 요약</h1>
<ul>
<li>특정 Tab을 클릭하면 Accordion이 열리게 하고 싶어, recoil을 사용했다.</li>
<li>하지만 atom(배열)로 OpenState를 관리하고 있어, 특정요소가 update되면 전체 페이지가 re-render되는 문제 발생</li>
<li>이를 atomFamily로 수정하여, OpenState<code>(atom 집합)</code>로 특정 컴포넌트만 re-render되도록 수정</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>