<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>seong-dodo.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 23 May 2025 06:12:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>seong-dodo.log</title>
            <url>https://images.velog.io/images/seong-dodo/profile/b573cf96-da62-4079-b3e7-b1e0ce64c168/IMG_5478.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. seong-dodo.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/seong-dodo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[단위 테스트 도입기: 레거시 프로젝트에도 테스트 문화를]]></title>
            <link>https://velog.io/@seong-dodo/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8F%84%EC%9E%85%EA%B8%B0-%EB%A0%88%EA%B1%B0%EC%8B%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EB%8F%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AC%B8%ED%99%94%EB%A5%BC-vihl9h19</link>
            <guid>https://velog.io/@seong-dodo/%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8F%84%EC%9E%85%EA%B8%B0-%EB%A0%88%EA%B1%B0%EC%8B%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EB%8F%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%AC%B8%ED%99%94%EB%A5%BC-vihl9h19</guid>
            <pubDate>Fri, 23 May 2025 06:12:04 GMT</pubDate>
            <description><![CDATA[<h1 id="🧪-단위-테스트-환경-설정-및-구축">🧪 단위 테스트 환경 설정 및 구축</h1>
<h2 id="✅-목적">✅ 목적</h2>
<ul>
<li>코드의 <strong>안정성과 신뢰성 확보</strong></li>
<li><strong>버그 조기 발견</strong> 및 빠른 수정 가능</li>
<li><strong>리팩토링 시 기존 기능 보장</strong></li>
<li><strong>협업 시 코드 이해도 상승</strong> 및 유지보수 용이성 향상</li>
</ul>
<hr>
<h2 id="🛠-추천-도구">🛠 추천 도구</h2>
<table>
<thead>
<tr>
<th>도구</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Jest</strong></td>
<td>자바스크립트 테스트 프레임워크</td>
</tr>
<tr>
<td><strong>React Testing Library</strong></td>
<td>React 컴포넌트 테스트에 최적화된 유틸리티</td>
</tr>
</tbody></table>
<blockquote>
<p>✔️ <strong>Jest + React Testing Library</strong> 조합으로 단위 테스트 구성</p>
</blockquote>
<hr>
<h2 id="📦-단위-테스트-예제-코드-작성">📦 단위 테스트 예제 코드 작성</h2>
<ul>
<li><code>useExpandable</code> 훅 리팩토링  </li>
<li>TypeScript 기반 테스트 코드 적용</li>
</ul>
<hr>
<h2 id="🔄-점진적-테스트-도입-및-레거시-코드-적용-전략">🔄 점진적 테스트 도입 및 레거시 코드 적용 전략</h2>
<ul>
<li>✅ 신규 개발 및 리팩토링 시 <strong>테스트 코드 우선 작성</strong></li>
<li>🔍 레거시 코드 중 <strong>핵심 기능부터 점진적으로 테스트 추가</strong></li>
<li>📌 <strong>중요도 및 변경 빈도</strong>에 따른 우선순위 지정</li>
<li>♻️ <strong>리팩토링과 병행하여 테스트 작성</strong>, 커버리지 확대</li>
<li>📈 단계적 도입을 통해 <strong>업무 영향 최소화</strong> 및 <strong>테스트 문화 정착</strong></li>
</ul>
<hr>
<h2 id="🎯-기대효과">🎯 기대효과</h2>
<ul>
<li>핵심 훅 로직에 대한 <strong>안정성 보장</strong></li>
<li>코드 변경 시 <strong>의도치 않은 동작 방지</strong></li>
<li><strong>테스트 커버리지 확보</strong>로 품질 향상</li>
<li><strong>개발 생산성</strong> 및 <strong>유지보수성 증가</strong></li>
</ul>
<hr>
<h2 id="🚀-테스트-실행-명령어">🚀 테스트 실행 명령어</h2>
<pre><code class="language-bash"># 테스트 실행
npm test src/hooks/ui/expandable/useExpandable.test.ts

# 테스트 + 커버리지 리포트
npm test src/hooks/ui/expandable/useExpandable.test.ts --coverage</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[App Router 전환과 타입스크립트 기반 개발 환경 구축기 (5월 3주차 회고)]]></title>
            <link>https://velog.io/@seong-dodo/App-Router-%EC%A0%84%ED%99%98%EA%B3%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%EA%B8%B0-5%EC%9B%94-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@seong-dodo/App-Router-%EC%A0%84%ED%99%98%EA%B3%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EA%B8%B0%EB%B0%98-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%EA%B8%B0-5%EC%9B%94-3%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 23 May 2025 01:26:57 GMT</pubDate>
            <description><![CDATA[<p>🗓️ Weekly Report
기간: 2025.05.19 ~ 2025.05.23</p>
<h3 id="✅-작업-내용">✅ 작업 내용</h3>
<h4 id="1-presigned-url-업로드-로직-개선">1. Presigned URL 업로드 로직 개선</h4>
<ul>
<li><p>기존 클라이언트 단 직접 업로드 방식 → 서버 중계 방식으로 변경</p>
</li>
<li><p>Next.js 서버에서 presigned URL을 호출하여 보안성 강화</p>
</li>
<li><p>네트워크 응답값을 클라이언트 대신 서버에서 관리 가능해짐</p>
</li>
</ul>
<h4 id="2-nextjs-app-router-도입-및-14버전-업그레이드">2. Next.js App Router 도입 및 14버전 업그레이드</h4>
<ul>
<li><p>기존 Pages Router에서는 서버 환경에서 File 객체가 없어 업로드 처리에 제약 발생</p>
</li>
<li><p>App Router 도입을 통해 서버 컴포넌트와의 유연한 연결 가능</p>
</li>
<li><p>안정성을 고려하여 Next.js 14로 업그레이드 완료</p>
</li>
</ul>
<h4 id="3-타입스크립트-도입">3. 타입스크립트 도입</h4>
<ul>
<li><p>App Router 구조상 타입스크립트 사용이 권장됨</p>
</li>
<li><p>프로젝트 전체적으로 타입스크립트 기반 리팩토링 진행</p>
</li>
<li><p>신규 개발은 TS 기반으로 진행, 레거시는 기능 단위로 점진적 적용 예정</p>
</li>
</ul>
<hr>
<h3 id="📈-느낀-점-및-향후-계획">📈 느낀 점 및 향후 계획</h3>
<ul>
<li>이미지 업로드 리팩토링 작업은 시간이 오래 걸렸지만 <strong>보안성, 유지보수성 측면에서 큰 개선</strong>이 있었음</li>
<li>이번 작업을 계기로 타입스크립트 도입하게 됨</li>
<li>앞으로의 신규 기능은 TS 기반으로 개발</li>
<li>레거시 코드는 기능 단위로 분리 → 타입 적용을 통해 점진적 개선 예정</li>
<li>다양한 예외 케이스를 고려한 로직 작성 필요, 운영 중 발생하는 케이스는 지속 보완 예정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[이미지 업로드 로직 개선 ]]></title>
            <link>https://velog.io/@seong-dodo/%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C-%EB%A1%9C%EC%A7%81-%EA%B0%9C%EC%84%A0</link>
            <guid>https://velog.io/@seong-dodo/%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C-%EB%A1%9C%EC%A7%81-%EA%B0%9C%EC%84%A0</guid>
            <pubDate>Wed, 21 May 2025 01:43:32 GMT</pubDate>
            <description><![CDATA[<h3 id="✅-배경-및-기존-문제">✅ <strong>배경 및 기존 문제</strong></h3>
<p>초기 프론트엔드에서는 이미지 업로드 시 <strong>클라이언트에서 직접 AWS S3에 업로드</strong>하는 방식을 사용했습니다. 이 방식은 업로드 Key가 <strong>프론트 코드 또는 네트워크 탭에서 노출</strong>될 수 있어 보안상 취약했습니다.</p>
<p>이를 개선하기 위해 <strong>presigned URL을 백엔드에서 받아서</strong> S3에 업로드하는 방식으로 1차 개선을 완료했습니다.</p>
<p>하지만 여전히 <strong>presigned URL이 네트워크 탭을 통해 노출될 수 있는 보안 이슈</strong>에 대해 presigned URL을 <strong>클라이언트가 아닌 서버 측에서 처리</strong>하도록 아키텍처를 변경하게 되었습니다.</p>
<h3 id="⚠️-기존-시도---page-router-방식">⚠️ <strong>기존 시도 - Page Router 방식</strong></h3>
<p>기존에는 Next.js의 <strong>Page Router</strong> 방식에서 서버 API 라우트를 통해 presigned URL을 받아 처리하려 했습니다. 하지만 이 방식에서는 브라우저에서 선택한 File <strong>객체를 서버로 직접 전달할 수 없는 한계</strong>가 있었습니다.</p>
<p>이를 해결하기 위해 FormData로 파일을 전달하는 접근을 시도했지만, Page Router에서 FormData를 파싱하고 처리하는 데 <strong>복잡하고 불편한 로직</strong>이 필요하다는 문제가 있었습니다.</p>
<h3 id="✅-개선-방향---app-router-도입-및-타입스크립트-전환">✅ <strong>개선 방향 - App Router 도입 및 타입스크립트 전환</strong></h3>
<p>이러한 문제를 해결하기 위해 Next.js의 <strong>App Router</strong>로 전환하였습니다.</p>
<p><strong>App Router</strong>는 Next.js 13 이상부터 권장되는 방식이며, 서버 컴포넌트와의 통합, server actions, formData 처리 등 보다 <strong>직관적인 서버-클라이언트 연동 방식</strong>을 제공합니다.</p>
<p>App Router 환경에서는 server actions 또는 route handlers를 통해 <strong>FormData를 쉽게 처리</strong>할 수 있고, presigned URL을 통한 파일 업로드도 서버 측에서 안전하게 수행할 수 있습니다.</p>
<p>이번 구조 전환과 함께 <strong>TypeScript도 도입</strong>하여 전체 코드의 안정성과 개발 효율성을 강화했습니다.</p>
<h3 id="✨-기대-효과">✨** 기대 효과**</h3>
<p>presigned URL을 <strong>클라이언트에 노출하지 않음</strong>으로써 보안성 강화</p>
<p>App Router 도입으로 서<strong>버 측 파일 처리 로직을 명확하게 구현 가능</strong></p>
<p>TypeScript 도입을 통해 <strong>정적 타입 검사를 통한 코드 안정성 확보</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[맛보기 프로젝트] react + typescript todolist ]]></title>
            <link>https://velog.io/@seong-dodo/%EB%A7%9B%EB%B3%B4%EA%B8%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-react-typescript-todolist</link>
            <guid>https://velog.io/@seong-dodo/%EB%A7%9B%EB%B3%B4%EA%B8%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-react-typescript-todolist</guid>
            <pubDate>Mon, 27 Jun 2022 15:31:22 GMT</pubDate>
            <description><![CDATA[<h2 id="목표">목표</h2>
<ul>
<li>typescript 사용보기</li>
<li>커스텀 hook 만들어서 사용해보기</li>
<li>render hooks 패턴 적용해보기</li>
</ul>
<br />



<h2 id="step-1-typescript-적용해보기">STEP 1. typescript 적용해보기</h2>
<h3 id="일반적으로-관심사-분리만-생각하여-props로-전달하는-방식으로-개발">일반적으로 관심사 분리만 생각하여 props로 전달하는 방식으로 개발</h3>
<pre><code class="language-javascript">
// TodoPage 컴포넌트
import { useState } from &#39;react&#39;;

type Todo = {
    id : number,
    value : string,
    status : string,
    isChecked : boolean,
}

const TodoPage : React.FC = () =&gt; {
    const [todos, setTodos] = useState&lt;Todo []&gt;([]);
    const [todo, setTodo] = useState&lt;Todo&gt;({
        id : 0,
        value : &#39;&#39;,
        status : &#39;TODO&#39;,
        isChecked : false,
    });

    const onChange = (e:React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
        setTodo({
            ...todo,
            value:e.target.value,
        })
    };

    const addTodo = () =&gt; {
        setTodos([
            ...todos, 
            todo
        ]);

        setTodo({
            ...todo,
            id: todo.id + 1,
            value: &#39;&#39;,
        })
    };

    return (
    &lt;div&gt;
            &lt;Input value={todo.value} onChange={(e) =&gt; onChange(e)} /&gt;
            &lt;Button name={&#39;추가&#39;} onClick={addTodo}/&gt;
            {todos.map((i, idx) =&gt; 
                &lt;div key={idx}&gt;
                    {i.value}
                &lt;/div&gt;
            )}
    &lt;/div&gt;
    )
}

export default TodoPage;
</code></pre>
<h2 id="step-2-custom-hook-사용해서-todolist를-리팩토링">STEP 2. custom hook 사용해서 todolist를 리팩토링</h2>
<pre><code class="language-javascript">// TodoPage 컴포넌트
import useTodo from &#39;hooks/useTodo&#39;;

const TodoPage : React.FC = () =&gt; {
    const {todo, todos, onChange, addTodo } = useTodo({
        id : 0,
        value : &#39;&#39;,
        status : &#39;TODO&#39;,
        isChecked : false,
    });

    return (
    &lt;div&gt;
        &lt;Input value={todo.value} onChange={onChange} /&gt;
        &lt;Button name={&#39;추가&#39;} onClick={addTodo}/&gt;
        {todos.map((i, idx) =&gt; 
             &lt;div key={idx}&gt;
                 {i.value}
             &lt;/div&gt;
         )}
    &lt;/div&gt;
    )
}</code></pre>
<pre><code class="language-javascript">// useTodo hook 컴포넌트
import { useState } from &quot;react&quot;;

type Todo = {
    id : number,
    value : string,
    status : string,
    isChecked : boolean,
}

const useTodo = (initialTodo: Todo) =&gt; {
  const [todos, setTodos] = useState&lt;Todo[]&gt;([]);
  const [todo, setTodo] = useState&lt;Todo&gt;(initialTodo);

  const inputFormChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    setTodo({
      ...todo,
      value: e.target.value,
    })
  }

    const hadleAddTodo = () =&gt; {
        setTodos([
            ...todos, 
            todo
        ]);

        setTodo({
            ...todo,
            id: todo.id + 1,
            value: &#39;&#39;,
        })
    }

  return {
    todo,
    todos,
    onChange : inputFormChange,
    addTodo : hadleAddTodo,
  }
}

export default useTodo;</code></pre>
<h3 id="custom-hook을-이용해서-ui와-로직을-분리했을때의-장점">custom hook을 이용해서 UI와 로직을 분리했을때의 장점</h3>
<blockquote>
<p> 기능은 동일하지만 UI가 다른 형태의 컴포넌트가 5개 있다고 가정해보겠습니다.
   이러한 경우 useTodo로 커스텀 hook을 만들어서 사용하면 로직 재사용이 가능합니다. </p>
</blockquote>
<p>   리액트에서 재사용성에 대해 집중하고 있는데,
   UI 즉, 스타일이 다르다면 결국 컴포넌트를 재사용한다라는 것은 어렵다고 생각합니다.
   컴포넌트 재사용에 대한 개념을 잘못 이해하다 보면 코드가 오히려 복잡해지고, 의존성이 강한 코드가 되어 버려 유지 보수가 힘들어 지는 코드가 되어 버립니다.</p>
<p>   커스텀 훅을 잘 사용하면 진짜 리액트에서 강조하는 재사용을 할 수 있습니다.</p>
<p>   처음부터 큰 숲을 생각하여 설계가 잘된 코드가 나오면 좋겠지만, 설계를 잘하는 일은 쉽지 않다. 많은 경험과 리팩토링을 통해 배울 수 있다고 합니다.
   그렇지만 리액트 컴포넌트 설계뿐만 아니라 재사용에 대해 충분한 고민을 통해 좋은 코드로 나아갈 수 있기를 바래봅니다.</p>
<h2 id="step-3-render-hooks을-이용해서-todolis를-리팩토링">STEP 3. render hooks을 이용해서 todolis를 리팩토링</h2>
<pre><code class="language-javascript">// TodoPage 컴포넌트
import useTodo from &#39;hooks/useTodo&#39;;

const TodoPage : React.FC = () =&gt; {
    const {todo, onChange, addTodo, renderTodos} = useTodo({
        id : 0,
        value : &#39;&#39;,
        status : &#39;TODO&#39;,
        isChecked : false,
    });

    return (
    &lt;div&gt;
            &lt;Input value={todo.value} onChange={onChange} /&gt;
            &lt;Button name={&#39;추가&#39;} onClick={addTodo}/&gt;
            {renderTodos()}
    &lt;/div&gt;
    )
}

export default TodoPage;</code></pre>
<pre><code class="language-javascript">// useTodo hook 컴포넌트
import { useState } from &quot;react&quot;;

type Todo = {
    id : number,
    value : string,
    status : string,
    isChecked : boolean,
}

const useTodo = (initialTodo: Todo) =&gt; {
  const [todos, setTodos] = useState&lt;Todo[]&gt;([]);
  const [todo, setTodo] = useState&lt;Todo&gt;(initialTodo);

  const inputFormChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    setTodo({
      ...todo,
      value: e.target.value,
    })
  }

    const hadleAddTodo = () =&gt; {
        setTodos([
            ...todos, 
            todo
        ]);

        setTodo({
            ...todo,
            id: todo.id + 1,
            value: &#39;&#39;,
        })
    }

  const renderTodos = () =&gt; {
   return (
     &lt;div&gt;
       {todos.map((i, idx) =&gt;
                  &lt;div key={idx}&gt;{i.value}&lt;/div&gt;
            )}
     &lt;/div&gt;
   )
  }

  return {
    todo,
    onChange : inputFormChange,
    addTodo : hadleAddTodo,
    renderTodos,
  }
}

export default useTodo;</code></pre>
<h3 id="render-hooks-패턴이란">render hooks 패턴이란?</h3>
<p>커스텀훅에 해당 상태값들을 렌더링시켜주는 책임도 가지고 이 책임을 함수로 반환하는 패턴입니다. 자세한 내용은 아래 라인기술블로그에 나와있습니다.</p>
<p><a href="https://engineering.linecorp.com/ko/blog/line-securities-frontend-3/">https://engineering.linecorp.com/ko/blog/line-securities-frontend-3/</a></p>
<p>결국 step2에서 개발한 커스텀훅에 할일목록을 렌더링하는 책임도 useTodo훅으로 넘겨주는것 입니다. renderHooks를 사용하면 어떤 장점이 있을까요? 투두리스트 화면의 복잡도가 높아져서 page역할을 하는 컴포넌트에 여러 컴포넌트가 복잡하게 섞여있고 이를 렌더링하는 로직이 들어가게되면 페이지컴포넌트에서 적절하게 원하는 ui를 배치한다는 책임을 넘어서서 여러 로직을 처리해야하는 일이 발생합니다. 하지만, 각 state를 렌더링시켜주는 책임을 각 customHook으로 넘겨주면 페이지컴포넌트에서는 페이지에 적절한 ui컴포넌트를 배치한다는 책임만 가지므로 복잡성을 다루기 좋지 않을까 생각합니다. 예를들어 같은 상태값에 대해서 조건부 렌더링을 처리해야할경우 이를 render함수에서 처리한다면 페이지컴포넌트에서는 이런 구체적인 세부사항을 알지 못하더라도 화면에 ui를 배치한다는 역할만 충실히 할 수 있습니다.</p>
<p>또한, 상태값별 여러가지 케이스에 해당하는 렌더링을 다르게 처리해야한다면 로직으로써의 커스텀훅과 렌더링으로써의 훅을 또다시 조합해서 로직재사용 + ui 렌더링별 훅을 적절하게 조합해서 사용할 수 있을것 같습니다. </p>
<p>render hooks의 장점과 기대되는 내용만 적었지만 결국 어떻게 설계했냐에 따라서 좋은설계가 될수도 있고 이상한 설계가 될수도 있을것 같습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useEffect 의존성 배열 활용하여 비동기 처리]]></title>
            <link>https://velog.io/@seong-dodo/useEffect-%EC%9D%98%EC%A1%B4%EC%84%B1-%EB%B0%B0%EC%97%B4-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@seong-dodo/useEffect-%EC%9D%98%EC%A1%B4%EC%84%B1-%EB%B0%B0%EC%97%B4-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 26 Jun 2022 15:18:26 GMT</pubDate>
            <description><![CDATA[<ul>
<li>useEffect에 대해서 다시 생각해보기</li>
<li>useEffect에서 의존성배열의 역할</li>
<li>setState는 동기적일까 비동기적일까</li>
<li>useEffect에서 여러 상태를 변경해야하는경우 이를 동기적으로 처리하는 방법</li>
</ul>
<p>&lt; 이슈 &gt;</p>
<p>필터링 기능이 완성 되지 않은 상태 → 필터링 기능 개선 + 개선과정에서 발생한 문제와 이를 해결한 과정</p>
<p>&lt; 요구 사항 분석 &gt;</p>
<ul>
<li>필터링 조건이 설정되면 페이지는 항상 1페이지여야 한다.</li>
<li>필터링 조건 및 페이지가 변경된 상태에서 특정 상품 페이지로 이동한 다음 뒤로가기 버튼을 눌렀을 때 이전 필터링 상태가 보존되어야 한다.</li>
</ul>
<p>&lt; AS - IS &gt;</p>
<ol>
<li>전체 카테고리 목록이 포함되어있는 api를 호출한다.</li>
<li>필터를 적용한 경우 검색 API를 호출해서 필터링된 상품 리스트를 조회한다.</li>
<li>상품을 선택해서 상품 상세페이지로 진입한다.</li>
<li>뒤로가기 버튼을 클릭하면 모든 필터는 초기화되고 전체카테고리와 1페이지로 이동한다.</li>
</ol>
<p>&lt; TO - BE &gt;</p>
<ol>
<li>전체 카테고리 목록이 포함되어 있는 API를 호출한다.</li>
<li>필터를 적용한 경우 검색 API를 호출하면서 router query를 이용해서 선택한 필터정보를 url에 저장한다.</li>
<li>상품을 선택해서 상품 상세페이지로 진입한다.</li>
<li>뒤로가기 버튼을 클릭하면 이전에 저장된 필터 정보에 해당하는 페이지로 이동한다.</li>
</ol>
<p>개선해야할 작업의 2번과정에서 setState가 동기적으로 처리되지 않고 비동기적으로 한번에 묶어서 batch update한다는 사실을 알게되었습니다.</p>
<p>따라서 useEffect 훅에서 의존성 배열을 활용해서 비동기작업에 대한 순서를 제어할 수 있도록 처리했습니다.</p>
<pre><code class="language-javascript">const Product = () =&gt; {

  const [categories, setCategories] = useState([]);
  const [filter, setFilter] = useState({});
  const [selectedCategory, setSelectedCategory] = useState({});

  useEffect(() =&gt; {
    const fetch = async() =&gt; {
       //1. 카테고리 목록을 조회한다.
             await getCategories();
       //2. 필터를 적용하고 상품상세를 조회하고 뒤로가기를 한 경우
       if(router.isFilter) {
         //기존에 사용했던 필터를 그대로 다시 적용한다.
         setFilter({
            orderBy : router.query.orderBy,
                        search : router.query.serach,
                        category : router.query.category
         });
         //카테고리 선택 ui에서 선택한 카테고리를 설정시키기 위해 
         //selectedCategory를 기존에 선택한 값으로 변경
         setSelectedCategory(categories.filter(c =&gt; c.id === router.query.category)[0]);
         //3. 필터가 적용된 상품을 조회힌다.
                 await getProducts();
             }
    }
    fetch();
  },[]);

}
</code></pre>
<p>위의 코드를 예시로 설명하면, 2번과정에서 문제가 발생했습니다.  카테고리를 조회하고 조회해온 카테고리를 categories라는 state에 업데이트 해주고 기존에 선택했던 카테고리 선택 ui를 변경시켜주기 위해서 selectedCategory값을 기존에 저장한 값으로 변경시켜주는 코드입니다.</p>
<p>selectedCategory에 기존에 필터에서 설정한 카테고리값을 변경시켜주었지만 ui상에서 재랜더링을 하면서 카테고리가 변경되지 않는 문제가 있었습니다.</p>
<p>원인은, 1번과정에서 카테고리 목록을 조회하고 setCategories를 실행할때 setState가 동기적으로 처리되는것이 아니라 핸들러 내부에서는 모든 상태값 변경을 한번에 모아서 batch update해주기 때문에 selectedCategory를 변경해주는 시점에는 전체카테고리가 존재하지 않기때문에 저장했던 카테고리 id에 해당하는 카테고리 정보를 찾는것이 불가능했습니다.</p>
<p>이를 해결하기 위해서는 useEffect내부에서 카테고리를 항상 먼저 조회하고 categories라는 state에 상태값이 업데이트되고나서 필터관련 상태변경이 일어나야했습니다. 즉, 비동기적인 작업에대한 순서를 제어해야했습니다.</p>
<p>이를 위해서는 useEffect훅에서 사용하는 의존성 배열을 이용하면 처리할 수 있습니다.</p>
<p>즉, 카테고리가 조회되고나서 나머지 로직을 실행해야하므로 카테고리는 항상 조회해야하므로 의존성배열을 설정하지 않고 카테고리가 조회되고나서 실행되야 하는 로직은 의존성 배열로 카테고리를 설정하면 이 둘의 순서를 제어할 수 있습니다.</p>
<pre><code class="language-javascript">const Product = () =&gt; {

  const [categories, setCategories] = useState([]);
  const [filter, setFilter] = useState({});
  const [selectedCategory, setSelectedCategory] = useState({});

  //의존성 배열을 설정하지 않았기때문에 컴포넌트 랜더링 과정에서 항상 처음으로 실행되는 useEffect
  useEffect(()=&gt; {
            //1. 카테고리 목록을 조회한다.
            getCategories();
  },[]);

  //의존성배열로 categories를 설정했으므로 categories가 변경된 경우에 해당 useEffect훅이 실행
  useEffect(() =&gt; {
         //2. 필터를 적용하고 상품상세를 조회하고 뒤로가기를 한 경우
       if(router.isFilter) {
         //기존에 사용했던 필터를 그대로 다시 적용한다.
         setFilter({
            orderBy : router.query.orderBy,
                        search : router.query.serach,
                        category : router.query.category
         });
         //카테고리 선택 ui에서 선택한 카테고리를 설정시키기 위해 
         //selectedCategory를 기존에 선택한 값으로 변경
         setSelectedCategory(categories.filter(c =&gt; c.id === router.query.category)[0]);
         //3. 필터가 적용된 상품을 조회힌다.
                 await getProducts();
             }
  },[categories]);

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 자바스크립트 이미지 슬라이드 구현하기]]></title>
            <link>https://velog.io/@seong-dodo/TIL-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seong-dodo/TIL-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 22 Mar 2022 05:01:48 GMT</pubDate>
            <description><![CDATA[<h2 id="1-이미지-슬라이드">1. 이미지 슬라이드</h2>
<h2 id="2-이미지-슬라이드-구현하는-방법">2. 이미지 슬라이드 구현하는 방법</h2>
<p>이전, 다음 버튼 클릭으로 이미지를 이동할 수 있어야한다.
이미지 하단의 버튼을 클릭하면 순서도에 일치하는 이미지를 확인 할 수 있어야한다.
이미지 슬라이드가 일정 시간마다 자동으로 변경되도록 하고, 일시정지 버튼을 클릭하면 슬라이드가 자동으로 변경되는 것을 제어할 수 있다.</p>
<h2 id="3-이미지-슬라이드-구현-과정에서-배운-기술">3. 이미지 슬라이드 구현 과정에서 배운 기술</h2>
<ul>
<li><p>clientWidth 
요소 내부 너비, 패딩이 포함되지만 테두리, 여백 및 세로 스크롤 막대는 제외
<img src="https://images.velog.io/images/seong-dodo/post/e51623d2-62b3-4027-96be-eccf03f17fef/image.png" alt=""></p>
</li>
<li><p>setInterval(함수, 시간)
함수를 지정한 시간 간격으로 반복저으로 호출</p>
</li>
<li><p>clearInterval()
이전에 설정된 시간이 지정된 반복 작업을 취소</p>
</li>
<li><p>createDocumentFragment()
메모리상에만 존재
(자바스크립트의 DOM 객체는 연산을 수행할 때마다 DOM tree라는 자료구조에 접근해야 하기 때문에 자바스크립트의 성능을 저하시키는 주된 요인 중 하나이다. 따라서, 자바스크립트의 성능을 최적화하기 위해서는 DOM 객체 접근을 최소화하도록 코드를 작성해야 한다.)</p>
</li>
</ul>
<p>참조 자료: <a href="https://hoya-kim.github.io/2021/10/12/DocumentFragment%EC%99%80-%EB%A6%AC%ED%94%8C%EB%A1%9C%EC%9A%B0/">https://hoya-kim.github.io/2021/10/12/DocumentFragment%EC%99%80-%EB%A6%AC%ED%94%8C%EB%A1%9C%EC%9A%B0/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[구현 능력 강화 Project]  react-card-payment ]]></title>
            <link>https://velog.io/@seong-dodo/%EA%B5%AC%ED%98%84-%EB%8A%A5%EB%A0%A5-%EA%B0%95%ED%99%94-Project-react-card-payment</link>
            <guid>https://velog.io/@seong-dodo/%EA%B5%AC%ED%98%84-%EB%8A%A5%EB%A0%A5-%EA%B0%95%ED%99%94-Project-react-card-payment</guid>
            <pubDate>Fri, 05 Nov 2021 10:55:28 GMT</pubDate>
            <description><![CDATA[<h1 id="👊-구현-능력-강화-프로젝트">👊 구현 능력 강화 프로젝트</h1>
<br>

<h1 id="💻--react-card-payment">💻  react-card-payment</h1>
<br>
<br>

<hr>
<h2 id="목표">목표</h2>
<h3 id="🎯-첫-번째---요구사항-분석">🎯 첫 번째 - 요구사항 분석</h3>
<h3 id="🎯-두-번째---요구사항-구현을-위한-전략-세우기">🎯 두 번째 - 요구사항 구현을 위한 전략 세우기</h3>
<hr>
<br>
<br>

<h2 id="🎯-첫-번째---요구사항-분석-1">🎯 첫 번째 - 요구사항 분석</h2>
<blockquote>
<p>사용자 시나리오 형태로 작성 
 예시) ooo하면 ~ 한다.</p>
</blockquote>
<br>

<h3 id="요구사항-1-카드-추가-화면">요구사항 1. 카드 추가 화면</h3>
<ul>
<li><p><input disabled="" type="checkbox">  추가(+) 버튼을 클릭하면 카드 정보 등록 화면으로 이동한다.</p>
</li>
<li><p><input disabled="" type="checkbox">  보유카드가 존재하면 화면에서 확인할 수 있다.</p>
<pre><code>- 카드 등록은 최대 5개까지 등록 가능합니다.
- 보유카드 이름 오름차순으로 보여진다.</code></pre></li>
</ul>
<br>

<h3 id="요구사항-2-카드-정보-등록-화면--카드-컬러-등록-화면">요구사항 2. 카드 정보 등록 화면 &amp; 카드 컬러 등록 화면</h3>
<ul>
<li><p><input disabled="" type="checkbox">  카드 정보를 입력하면 카드 정보를 등록할 수 있다.</p>
<pre><code>2-1. 카드 번호 입력 폼
- 카드 번호 입력폼은 4개의 input으로 구성되어 있습니다.
- 입력값은 4자리 숫자 형태로 입력할 수 있습니다.
- placeholder는 0000 으로 보여집니다.
- 1번, 2번 input에 입력값을 입력하면 입력폼 &amp; 카드에 입력한 카드번호(숫자)가 보여집니다.
- 3번, 4번 input에 입력값을 입력하면 입력폼 &amp; 카드에 *(비밀번호) 형태로 보여집니다.

2-2. 만료일 입력 폼
- 만료일 입력폼은 2개의 input으로 구성되어 있습니다.
- 입력값은 2자리 숫자 형태로 입력할 수 있습니다.
- 1번 input의 placeholder는 &quot;MM&quot; 으로 보여집니다.
- 2번 input의 placeholder는 &quot;YY&quot; 으로 보여집니다.
- 1번, 2번에 입력값을 입력하면 입력폼 &amp; 카드에 입력한 만료일(월/년)이 보여집니다.

2-3. 카드 소유자 이름(영문) 입력 폼
- 카드 소유자 이름 입력폼의 입력할 수 있는 글자 수는 30으로 제한되어 있습니다.
- placeholder는 &quot;카드에 표시된 이름과 동일하게 입력하세요&quot;라고 쓰여 있습니다.
- 입력값을 영문으로로 입력할 수 있으며, 소문자와 대문자 구분없이 영문자 형태로 입력하면 대문자로 입력폼과 카드에 보여집니다.
- 입력값을 입력하면 입력값의 글자 수가 자동으로 계산되어 보여집니다.

2-4. 보안코드(CVC/CVV) 입력 폼
- 보안코드 입력폼에 3자리 숫자형태로 입력할 수 있습니다.
- 보안코드를 입력하면 입력폼에 *(비밀번호) 형태로 보여집니다.
- 물음표 버튼을 클릭하면 CVC/CVV에 대한 안내 문구를 확인할 수 있습니다.
   - 안내 문구: 카드 뒷면 끝번호 3자리

2-5. 카드 비밀번호 입력 폼
- 카드 비밀번호 입력폼은 4개의 input으로 구성되어 있습니다.
- 카드 비밀번호 앞자리 두 자리를 1번, 2번 input에 숫자 형태로 입력할 수 있습니다. 
- 카드 비밀번호 뒷자리 두 자리는 . . 으로 보여집니다.
- 카드 비밀번호 앞자리 두 자리를 입력하면  입력폼에 *(비밀번호) 형태로 보여집니다.</code></pre></li>
<li><p><input disabled="" type="checkbox">  색상 선택 버튼을 클릭하면 카드 색상을 변경할 수 있는 화면을 확인할 수 있다.</p>
<pre><code>- 하단에 카드 색상 모달창이 보여집니다.
- 8개의 색상을 확인할 수 있습니다.</code></pre></li>
<li><p><input disabled="" type="checkbox">  카드 색상을 선택하면 선택한 색상으로 카드 색상이 변경된 것을 확인할 수 있다.</p>
</li>
<li><p><input disabled="" type="checkbox">  모든 내용을 입력하고 &quot;다음&quot; 버튼을 클릭하면 카드 이름 등록 화면으로 이동할 수 있다.</p>
<pre><code>- 카드 번호 입력 폼의 입력값이 없을 경우 &quot;다음&quot; 버튼을 클릭하면 &quot;카드번호를 입력해주세요&quot; 라는 알림창이 보여집니다.
- 만료일 입력 폼의 입력값이 없을 경우 &quot;다음&quot; 버튼을 클릭하면 &quot;만료일을 입력해주세요&quot; 라는 알림창이 보여집니다.
- 카드 소유자 이름(영문) 입력 폼의 입력값이 없을 경우 &quot;다음&quot; 버튼을 클릭하면 &quot;카드 소유자 이름을 입력해주세요&quot; 라는 알림창이 보여집니다.
- 보안코드 입력 폼의 입력값이 없을 경우 &quot;다음&quot; 버튼을 클릭하면 &quot;보안코드를 입력해주세요&quot; 라는 알림창이 보여집니다.
- 카드 비밀번호 입력 폼의 입력값이 없을 경우 &quot;다음&quot; 버튼을 클릭하면 &quot;카드 비밀번호를 입력해주세요&quot; 라는 알림창이 보여집니다.</code></pre></li>
</ul>
<br>

<h3 id="요구사항-3-카드-이름-등록-화면">요구사항 3. 카드 이름 등록 화면</h3>
<ul>
<li><p><input disabled="" type="checkbox">  카드 등록이 완료되면 등록한 카드의 정보를 확인할 수 있다.</p>
</li>
<li><p><input disabled="" type="checkbox">  카드 이름을 입력하고 &quot;완료&quot; 버튼을 클릭하면 카드 추가를 할 수 있다.</p>
<pre><code>- placeholder는 &quot;카드 이름을 입력해주세요.&quot; 으로 보여집니다.
- 완료 버튼을 클릭하고 나면 카드 정보 등록 입력폼 및 카드 색상이 초기화되어집니다.</code></pre></li>
</ul>
<br>

<hr>
<h2 id="회고">회고</h2>
<p>이전에 나는 기능 개발, 코드 구현을 할 때 &#39;요구사항 분석&#39; 및 &#39;요구사항에 대한 전략&#39;을 세우긴 하였지만 상세하게 세우지 않은 상태에서 바로 코드부터 작성했던 것 같다.</p>
<p>머릿 속에서 논리는 그려지는데 한글로 논리를 옮겨 적는 것이 어렵기도 했었다. 이런 맥락으로 봤을 때 테스트 코드가 요구사항 분석에 대한 상세 명세서였던 것이다.</p>
<p>어쨌든 나에게 부족한 부분은 무엇인가 라는 물음표를 던졌을 때 코드 작성에 가장 중요한 부분은 요구사항 분석이라고 생각한다.</p>
<p>이렇게 요구사항 분석을 통해 그 다음 단계는 어떻게 이루어져야 하는가, 몇 가지의 예외 경우는 무엇인지에 대한 상세한 분석이 필요하고 연습이 필요하다고 생각한다.</p>
<p>왜냐면 지금 나는 아주 조금 성장하였다고 생각한다.
몇 가지의 기능 구현을 접하면서 내가 놓쳤던 예외 사항 처리에 대한 경험들이 쌓이면서 하나씩 눈에 보이기 때문이다. (아직 부족한 점도 있겠지만..) 앞으로 더 많은 input을 통해 더 넓은 시야를 확보하기 위해 차근차근 연습해보자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 생활코딩 WEB2 - Javascript ]]></title>
            <link>https://velog.io/@seong-dodo/TIL-%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-WEB2-Javascript</link>
            <guid>https://velog.io/@seong-dodo/TIL-%EC%83%9D%ED%99%9C%EC%BD%94%EB%94%A9-WEB2-Javascript</guid>
            <pubDate>Wed, 03 Nov 2021 02:54:55 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드 개발자에게 필수 Javascript에 대한 기본기를 탄탄하게 다지면 어떤 언어를 배우더라도 쉽게 배울 수 있고 흡수할 수 있다고 생각합니다.</p>
<p>프론트엔트 개발 공부에는 끝이 없습니다. 공부했던 내용일지라도 여러번 반복학습을 통해 개념을 되새기고 익히고 구현능력을 기르는 학습이 필요하다고 생각합니다.</p>
<p>그래서 이번에 생활코딩에서 제공하는 강의를 통해 프론트엔드 개발자에 필요한 역량을 기르기 위한 기본기를 다지기 위해 강의를 들으면서 한 번 더 개념을 상기하고, 100% 채워지지 않았던 요소들을 보충 보강하는 시간을 가져보려고 합니다.</p>
<p>자바스크립트 강의를 보고 궁금한 내용 및 학습 내용에 대하여 간략하게 정리하려고 합니다.</p>
<h2 id="자바스크립트javascript란">자바스크립트(Javascript)란</h2>
<p><img src="https://images.velog.io/images/seong-dodo/post/baaa2ca0-9769-434b-9239-52f4e236fb1b/image.png" alt=""></p>
<p>자바스크립트라는 프로그래밍언어를 이야기할때 &#39;웹브라우저&#39;라는 단어는 필연적인 단어이다.
웨브라우저의 형태로 분류되는 소프트웨어를 프로그래밍적 언어로 제어하기 위한 언어이기 때문이다.</p>
<h2 id="프로그래밍적-제어란-무엇인가">프로그래밍적 제어란 무엇인가</h2>
<p>프로그래밍적 제어란 자바스크립트로 코드를 작성해서 브라우저를 프로그래밍적으로 제어할 수 있는 것을 프로그래밍적 제어라고 한다.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/141e8a0f-528e-405b-ab9c-21792e2244e5/image.png" alt="">
사용자 관점에서 웹브라우저에서 <code>Hello world</code>라는 버튼을 확인할 수 있는데 <code>Hello world</code> 버튼을 클릭하면 브라우저에서 제공하는 자바스크립트 알림창을 확인할 수 있다.
이렇게 브라우저가 이미 가지고 있는 경고창을 확인할 수 있는 것은 개발자가 자바스크립트 언어로 코드를 작성했기 때문에 이러한 커뮤니케이션이 가능한 것이다. 즉, 자바스크립트는 프로그래밍적으로 웹브라우저를 제어하기 위한 도구이다.</p>
<p>프로그래밍적 제어에 대한 개념에 대해 이정도만 알고 넘어가자.</p>
<h2 id="웹서버에서-사용되는-기술">웹서버에서 사용되는 기술</h2>
<p>웹브라우저에 주소를 입력하면 주소에 해당하는 컴퓨터를 찾아가서 그 컴퓨터에서 필요한 정보를 요청하게 된다. 사용자에게 응답하기 위해 사용하는 언어로 자바 ,php, 루비, 파이썬 등등이 있다.</p>
<h2 id="self-키워드란">self 키워드란</h2>
<blockquote>
<p>self는 스크립트가 실행되는 컨텓스트의 전역 객체를 반환하는 속성</p>
</blockquote>
<p>self는 window 컨텍스트가 아닌 웹 워커 컨텍스트에서 주로 활용한다.</p>
<h2 id="self-키워드-this-키워드-차이">self 키워드 this 키워드 차이</h2>
<p>this 키워드는 함수 호출하는 방법에 따라 가르키는 주체가 달라진다. 현재 컨텍스트(객체)를 참조</p>
<p>self 키워드는 window 전역 객체를 참조한다.</p>
<blockquote>
<p>출처 : <a href="https://opentutorials.org/course/1">생활코딩 홈</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] grid]]></title>
            <link>https://velog.io/@seong-dodo/CSS-grid</link>
            <guid>https://velog.io/@seong-dodo/CSS-grid</guid>
            <pubDate>Sat, 30 Oct 2021 05:09:20 GMT</pubDate>
            <description><![CDATA[<p>전체 컨테이너 태그안에 아홉개 item 태그가 있다.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/ef9d3782-85fd-4377-aea9-ac742570c978/image.png" alt=""></p>
<h2 id="display--grid-속성-활용해보기">display : grid 속성 활용해보기</h2>
<p><img src="https://images.velog.io/images/seong-dodo/post/9698ba01-8cbd-4aae-90f7-8159be43c92d/image.png" alt=""></p>
<p>전체 컨테이너에 넣어주었주도록 한다.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/eb9d74fb-20c9-4a3e-b05a-e8105f1b6d82/image.png" alt=""></p>
<p>그리드 사용시 % 단위보다 fr단위를 사용을 권장</p>
<p>colum은 열 | | |</p>
<p>row는 행
ㅡ
ㅡ
ㅡ</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/0d76fd47-fa82-4c24-99fb-0db880a750af/image.png" alt=""></p>
<h4 id="가로">가로</h4>
<p> justify-items : start        왼쪽으로 붙음
 justify-items : end          오른쪽으로 붙음
 justify-items : center       가운데 위치</p>
<h4 id="세로">세로</h4>
<p> align-items : start         위쪽으로 붙음
 align-items : end           아래쪽으로 붙음
 align-items : center        가운데 위치</p>
<hr>
<p> 아래 컨테이너 자식 태그 아이템중 5번째 자식의 위치 조정할 시<br> 아래와 같이 nth-child(5)에 코드 작성하기</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/2b5dd2fc-39e9-4a1a-a33b-0e9159309620/image.png" alt=""></p>
<p>참고: <img src="https://images.velog.io/images/seong-dodo/post/826cb92a-2e55-4c69-b8fd-4d1967026281/image.png" alt=""></p>
<hr>
<p>1번 아이템을 아래와 같은 그리드를 표현하려고 하면</p>
<p>아래 기준을 잘 생각하면 쉬움!!!!</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/a73f0367-8a73-4798-b141-68e4f0efbfd5/image.png" alt=""></p>
<p>gird-colum: 1/4; 이렇게 적어주면되는데,
1부터 4까지 배치하겠다는 의미이다. </p>
<p><img src="https://images.velog.io/images/seong-dodo/post/ed30e5e6-bf46-43c4-8404-64f991e1c84b/image.png" alt=""></p>
<p>4번째 아이템을 아래와 같은 그림으로 만들려면</p>
<p>grid-row: 2/4; 이렇게 적어주면 
2부터 4까지 배치하도록 하는 것이다. </p>
<p>그런데 위치가 순서대로 만들어지지 않는 것을 확인할 수 있음.
이유는 공간때문에 이러한 현상이 생김!</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/3e4c65bb-a36a-4b1e-857e-b6d5d106c9e4/image.png" alt=""></p>
<p>그래서  아래와 같이 원하는 순서와 그리드 모습으로 만들기 위해서
코드를 추가해주어야 한다.</p>
<p><strong>gird-colum: 3;</strong>
grid-row: 2/4;</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/593e8394-ba07-48e5-89b5-133ec6fd9efc/image.png" alt=""></p>
<hr>
<h4 id="4번-아이템-위치는-그대로-있고-9번-아이템을-4번-아이템이랑-겹치게-하고-싶다면">4번 아이템 위치는 그대로 있고 9번 아이템을 4번 아이템이랑 겹치게 하고 싶다면???</h4>
<p>영역을 겹치게 하고 싶으면 억지로 아래와 같은 코드로 만들 수 있음.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/c6712563-6173-47c9-b5d7-2392dc0527c5/image.png" alt=""></p>
<br/>

<blockquote>
<p>출처 : 1분코딩 유투브</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] float 사용한 레이아웃 / 가상 엘리먼트 만들어주는 방법]]></title>
            <link>https://velog.io/@seong-dodo/CSS-float-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EA%B0%80%EC%83%81-%EC%97%98%EB%A6%AC%EB%A8%BC%ED%8A%B8-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%A3%BC%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@seong-dodo/CSS-float-%EC%82%AC%EC%9A%A9%ED%95%9C-%EB%A0%88%EC%9D%B4%EC%95%84%EC%9B%83-%EA%B0%80%EC%83%81-%EC%97%98%EB%A6%AC%EB%A8%BC%ED%8A%B8-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%A3%BC%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 29 Oct 2021 14:01:18 GMT</pubDate>
            <description><![CDATA[<p>자식 엘리먼트가 float로 배치를 했으면 부모 엘리먼트 끝나는 시점에 clear를 해주어야 한다. (이유: 부모 엘리먼트가 정상적으로 높이를 확보하도록)</p>
<p>예전에는 아래와 같이 html에 clear 코드를 추가해주었음!
<img src="https://images.velog.io/images/seong-dodo/post/0336169c-bbb4-4f23-9a14-c2d3d53678d6/image.png" alt=""></p>
<p>더 세련된 방법으로 아래와 같이 가상 엘리먼트 after를 만들어주는 방법이 있다.
<img src="https://images.velog.io/images/seong-dodo/post/81fd55bf-3e8f-45fd-a54f-c924f006a273/image.png" alt=""></p>
<p>이외에도 다른 방법이 있으니 다른 강의 참조할 것!!! (오버플로워 등)</p>
<blockquote>
<p>출처: 1분 코딩</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] CSS Reset]]></title>
            <link>https://velog.io/@seong-dodo/CSS-CSS-Reset</link>
            <guid>https://velog.io/@seong-dodo/CSS-CSS-Reset</guid>
            <pubDate>Fri, 29 Oct 2021 13:25:55 GMT</pubDate>
            <description><![CDATA[<p>참고 자료: <a href="https://cssdeck.com/blog/scripts/eric-meyer-reset-css/">Eric Meyer’s “Reset CSS” 2.0</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] box-sizing ]]></title>
            <link>https://velog.io/@seong-dodo/CSS-box-sizing</link>
            <guid>https://velog.io/@seong-dodo/CSS-box-sizing</guid>
            <pubDate>Fri, 29 Oct 2021 13:10:03 GMT</pubDate>
            <description><![CDATA[<h1 id="box-sizing--content-box-기본값">box-sizing : content-box (기본값)</h1>
<p><img src="https://images.velog.io/images/seong-dodo/post/7531c99c-21f0-49d8-9a2b-05dfead2ba00/image.png" alt=""></p>
<br/>

<h1 id="box-sizing--border-box-border까지-width에-포함">box-sizing : border-box (border까지 width에 포함)</h1>
<p><img src="https://images.velog.io/images/seong-dodo/post/96de90ee-c316-4a69-8d14-a03d7dc6d581/image.png" alt=""></p>
<pre><code>** box-sizing 속성 IE8부터 지원</code></pre><br/>

<blockquote>
<p>출처 : <a href="https://www.youtube.com/watch?v=Zny5Vxqk6Mk">1분 코딩 YouTube</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[라이브러리 없이 무한 스크롤 구현하기]]></title>
            <link>https://velog.io/@seong-dodo/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%97%86%EC%9D%B4-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@seong-dodo/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-%EC%97%86%EC%9D%B4-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 28 Oct 2021 06:21:01 GMT</pubDate>
            <description><![CDATA[<p>이번에는 라이브러리 없이 무한 스크롤 구현을 해보겠습니다.</p>
<h2 id="무한스크롤을-구현하는-하는-방법">무한스크롤을 구현하는 하는 방법</h2>
<pre><code>1. Scroll event

2. intersection observer</code></pre><br/>



<h1 id="1-scroll-event">1. Scroll event</h1>
<p>스크롤 이벤트의 경우 현재 위치를 구해야 합니다.</p>
<pre><code>body : 3093
scrollHeight : 3093
scrollTop : 131 -&gt; 2207
clinentHeight : 886</code></pre><p>아래와 같이 스크롤 이벤트를 구현해주면 됩니다.</p>
<pre><code class="language-javascript">import renderList from &#39;./renderList&#39;;

const app = document.querySelector(&#39;#app&#39;);
const fetchMoreTrigger = document.querySelector(&#39;#fetchMore&#39;);
let page = 0;


const fetchMore = async () =&gt; {
  const target = page ? fetchMoreTrigger : app;
  target.classList.add(&#39;loading&#39;);
  await renderList(page++);
  target.classList.remove(&#39;loading&#39;);
};

const onScroll = e =&gt; {
  const {
   scrollHeigt,
   scrollTop,
   clientHeigt,
  } = e.target.scrollingElement;
  if (scrollTop + clientHeigt === scrollHeigt) {
    fetchMore()
  } 
};

document.addEventListener(&#39;scroll&#39;, onScroll);
fetchMore();</code></pre>
<p>스크롤 이벤트를 사용하면 계속 실행이 되기 때문에 성능 저하가 될 수 있기 때문에
연속으로 발생하는 이벤트에 대해서 아래와 같은 처리를 해주어야 합니다.</p>
<h4 id="1-throttle--일정-시간-간격으로-한-번씩만-실행">(1) throttle : 일정 시간 간격으로 한 번씩만 실행</h4>
<h4 id="2-debounce-마지막-한-번만-실행">(2) debounce: 마지막 한 번만 실행</h4>
<p>debounce를 활용해서 시간지연을 시켜주도록 하는 코드를 추가하여 성능을 개선할 수 있습니다.</p>
<pre><code class="language-javascript">const debounce = (event, delay) =&gt; {
  let timeoutId = null;
  return (...args) =&gt; {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(event.bind(null, ...arg), delay);
};

// 코드 생략 ... 

document.addEventListener(&#39;scroll&#39;, debounce(onScroll, 500));
fetchMore();</code></pre>
<p>500ms 동안에 발생하는 스크롤 이벤트 모두 취소하고 마지막 한 번만 실행하는 코드를 만들 수 있습니다.</p>
<br/>
<br/>

<h1 id="2-intersection-observer">2. intersection observer</h1>
<p>HTML, CSS, 자바스크립트가 개입하지 않는 문법을 고민하는게 좋은 방법이라고 하여 자바스크립트에서 제공해주는 Intersection Observer API에 대해서도 알아보도록 하겠습니다.</p>
<p>Intersection Observer API는 타겟 요소와 상위 요소 또는 최상위 document 의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법입니다.</p>
<p>intersection observer는 화면에 보여지는 여부를 판단합니다. 감시하고자하는 요소가 뷰포트에 들어가거나 나갈때 두 요소의 교차부분이 변경될 때 마다 실행될 콜백 함수를 등록할 수 있게 합니다. 교차 영역 관리를 최적화할 수 있는 방법입니다.</p>
<p>[ 공식 문서 링크 : <a href="https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API">Intersection Observer API</a> ]</p>
<blockquote>
<h3 id="요구-사항">요구 사항</h3>
</blockquote>
<ul>
<li>처음에 10개만 불러오기</li>
<li>1.5초가 지나면 추가로 10개 불러오기 및 스크롤이 최하단에 닿을 때마다 10개씩 추가하기</li>
</ul>
<p>요구 사항에 맞게 구현한 화면 모습입니다.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/8f9bd89c-7bb8-4d4f-bbb1-b398fb2501ef/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-10-28-%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE-2.14.02.gif" alt=""></p>
<br />

<h4 id="app-컴포넌트-코드">App 컴포넌트 코드</h4>
<p>아래와 같이 코드를 구현해주면 됩니다.</p>
<img src='https://images.velog.io/images/seong-dodo/post/bf474a0e-330e-48b7-92db-1b620c6db52c/image.png' width='80%' height='80%'>

<p>console.log(entry)를 찍어서 확인해보겠습니다.
우리가 체크해야할 부분은 <strong>isIntersecting</strong> 입니다. </p>
<img src='https://images.velog.io/images/seong-dodo/post/666d41cb-4377-474e-a06e-0bac36049c0d/image.png' width='60%'>


<p><strong>isIntersecting이 false인지 true인지</strong>에 대해 관찰해주면 됩니다.</p>
 <img src='https://images.velog.io/images/seong-dodo/post/bdb913ac-e0ae-4ea8-85eb-09bfeb2d9879/image.png' width='80%' height='80%'>
 <img src='https://images.velog.io/images/seong-dodo/post/4848524b-155c-46f0-a8bd-a041f51849b7/image.png' width='80%' height='80%'>


<p>이렇게 무한스크롤을 구현해보았습니다.</p>
<br/>
<br/>


<blockquote>
<p>출처: <a href="https://youtu.be/hVcriryAVbg">https://youtu.be/hVcriryAVbg</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입스크립트란?]]></title>
            <link>https://velog.io/@seong-dodo/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%9E%80</link>
            <guid>https://velog.io/@seong-dodo/TypeScript-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%9E%80</guid>
            <pubDate>Tue, 26 Oct 2021 13:11:25 GMT</pubDate>
            <description><![CDATA[<h1 id="📓-타입스크립트란">📓 타입스크립트란?</h1>
<p>2012년 마이크로소프트에서 발표한 타입스크립트(TypeScript)는 자바스크립트(Javascript)에 타입을 부여한 프로그래밍 언어입니다. </p>
<blockquote>
<p><strong>&quot;Typescript is a typed superset of Javascript that compiles to plain Javascript&quot;</strong></p>
</blockquote>
<p>[출처 : <a href="https://www.typescriptlang.org/%5D">https://www.typescriptlang.org/]</a></p>
<br />
<br />

<h1 id="✏️-타입스크립트의-특징">✏️ 타입스크립트의 특징</h1>
<h3 id="☑️-정적-타입-언어">☑️ 정적 타입 언어</h3>
<p>타입스크립트는 자바스크립트 기반으로 정적 타입 문법을 추가한 프로그래밍 언어로 코드 작성 단계에서 타입을 체크해서 오류를 확인할 수 있고, 미리 타입을 결정하기 때문에 실행속도가 매우 빠른 장점이 있는 반면, 코드 작성 시 매번 타입을 결정해야하기 때문에 번거롭고 코드량이 상대적으로 많은 특징이 있습니다.</p>
<h3 id="☑️-컴파일-언어">☑️ 컴파일 언어</h3>
<p>타입스크립트는 컴파일러 또는 바벨을 통해 자바스크립트 코드로 변환되는 언어입니다. 자바스크립트 언어에 비해 상대적으로 코드 작성량이 많으므로 컴파일 시간이 오래걸리는 단점이 있습니다.</p>
<h3 id="☑️-자바스크립트-슈퍼셋superset">☑️ 자바스크립트 슈퍼셋(Superset)</h3>
<p>타입스크립트는 자바스크립트의 슈퍼셋입니다. 자바스크립트 기본 문법에 타입스크립트의 문법을 추가한 언어입니다. </p>
<pre><code>📌  슈퍼셋이란? 상위확장을 일컫는다.</code></pre><h3 id="☑️-객체-지향-프로그래밍-지원">☑️ 객체 지향 프로그래밍 지원</h3>
<p>타입스크립트는 ES6 이상 문법과 클래스, 인터페이스, 상속, 모듈 등과 같은 객체 지향 프로그래밍 패턴을 사용할 수 있습니다.</p>
<br />
<br />

<h1 id="🎯-타입스크립트-사용하면-좋은점">🎯 타입스크립트 사용하면 좋은점</h1>
<p>타입스크립트는 아래와 같은 관점에서 자바스크립트 코드의 품질과 개발 생산성을 높일 수 있습니다.</p>
<pre><code>1️⃣  에러의 사전 방지
2️⃣  코드 가이드 및 자동 완성으로 개발 생산성 향상</code></pre><p>타입스크립트는 코드에 목적을 명시하고 목적에 맞지 않는 타입의 변수나 함수들에서 에러를 발생시켜 버그를 사전에 방지합니다. 또한 코드 자동 완성이나 실행 전 피드백 제공하여 코드 개발 생산성을 향상시킬 수 있습니다.</p>
<br />
<br />
<br />





<blockquote>
<p>참고자료 : <a href="https://www.samsungsds.com/kr/insights/TypeScript.html">https://www.samsungsds.com/kr/insights/TypeScript.html</a>
참고자료 : <a href="https://namu.wiki/w/TypeScript">https://namu.wiki/w/TypeScript</a>
참고자료: <a href="https://velog.io/@pluviabc1/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%99%80-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%B0%A8%EC%9D%B4%EC%A0%90">https://velog.io/@pluviabc1/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%99%80-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%B0%A8%EC%9D%B4%EC%A0%90</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 로딩 컴포넌트 개발 (spinner 스타일)]]></title>
            <link>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C-spinner-%EC%8A%A4%ED%83%80%EC%9D%BC</link>
            <guid>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C-spinner-%EC%8A%A4%ED%83%80%EC%9D%BC</guid>
            <pubDate>Sun, 10 Oct 2021 09:08:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/seong-dodo/post/3888ed94-b732-4c79-a274-7d8796ce2715/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-10-10-%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE-6.07.01.gif" alt=""></p>
<p>로딩 컴포넌트는 사용자 경험에 있어 필수적으로 개발되어야하는 컴포넌트로 이번에는 spinner 스탕일로 만들어 보겠습니다.
emotion keyframes을 사용해서 css만으로 로딩중인 상태를 나타내도록 만들어 보았습니다.</p>
<p><img src="https://images.velog.io/images/seong-dodo/post/63151413-1ed7-4181-aef0-9a9869b95f05/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 로딩 컴포넌트 개발 (bubble 스타일)]]></title>
            <link>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C-bubble-%EC%8A%A4%ED%83%80%EC%9D%BC</link>
            <guid>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C-bubble-%EC%8A%A4%ED%83%80%EC%9D%BC</guid>
            <pubDate>Sun, 10 Oct 2021 09:00:08 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/seong-dodo/post/e75a0230-7449-46c5-b22d-7181965b1396/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-10-10-%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE-5.56.41.gif" alt=""></p>
<p>로딩 컴포넌트는 사용자 경험에 있어 필수적으로 개발되어야하는 컴포넌트로  bubble 버전으로 만들어 보겠습니다.
emotion keyframes을 사용해서 css만으로 로딩중인 상태를 나타내도록 만들어 보았습니다.</p>
<pre><code class="language-javascript">import { keyframes } from &#39;@emotion/react&#39;;
import styled from &#39;@emotion/styled&#39;;

const bubble = keyframes`
  0%,
  80%,
  100% {
    box-shadow: 0 2.5em 0 -1.3em;
  }
  40% {
    box-shadow: 0 2.5em 0 0;
  }
`;

const Container = styled.div({
  width: &#39;80px&#39;,
  margin: &#39;0 auto&#39;,
});

const BoxStyle = styled.div({
  float: &#39;left&#39;,
  width: &#39;30%&#39;,
  padding: &#39;5px&#39;,
});

const LoadingIcon = styled.div({
  width: &#39;20px&#39;,
  height: &#39;20px&#39;,
  borderRadius: &#39;100%&#39;,
  animation: `${bubble} 3s ease infinite`,
});

export default function Loading() {
  return (
    &lt;&gt;
      &lt;Container&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
      &lt;/Container&gt;
    &lt;/&gt;
  );
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 로딩 컴포넌트 개발 (bounce 스타일) ]]></title>
            <link>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@seong-dodo/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Sun, 10 Oct 2021 08:47:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/seong-dodo/post/3855d460-3a10-4a9c-82af-5257b8dcf874/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB-%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8-2021-10-10-%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE-5.44.19.gif" alt=""></p>
<p>로딩 컴포넌트는 사용자 경험에 있어 필수적으로 개발되어야하는 컴포넌트로 bounce 스타일로 만들어 보겠습니다.
emotion keyframes을 사용해서 css만으로 로딩중인 상태를 나타내도록 만들어 보았습니다.</p>
<pre><code class="language-javascript">import { keyframes } from &#39;@emotion/react&#39;;
import styled from &#39;@emotion/styled&#39;;
import colors from &#39;../style/colors&#39;;

const bounce = keyframes`
  0 {
    transform: translateY(0);
  }
  50% {
      transform: translateY(-15px);
  }
  100% {
      transform: translateY(0);
  }
`;

const Text = styled.div({
  width: &#39;80px&#39;,
  margin: &#39;0 auto&#39;,
  animation: `${bounce} 3s ease infinite`,
  fontSize: &#39;13px&#39;,
  textAlign: &#39;center&#39;,
  color: `${colors.gray_text02}`,
});

const Container = styled.div({
  width: &#39;80px&#39;,
  margin: &#39;0 auto&#39;,
});

const BoxStyle = styled.div({
  float: &#39;left&#39;,
  width: &#39;30%&#39;,
  padding: &#39;5px&#39;,
});

const LoadingIcon = styled.div({
  width: &#39;20px&#39;,
  height: &#39;20px&#39;,
  borderRadius: &#39;100%&#39;,
  background: `${colors.gray_text}`,
  animation: `${bounce} 3s ease infinite`,
});

export default function Loading() {
  return (
    &lt;&gt;
      &lt;Text&gt;
        로딩중
      &lt;/Text&gt;
      &lt;Container&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
        &lt;BoxStyle&gt;
          &lt;LoadingIcon /&gt;
        &lt;/BoxStyle&gt;
      &lt;/Container&gt;
    &lt;/&gt;
  );
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[바닐라 자바스크립트] 요구사항 분석 및 구현 연습 일기]]></title>
            <link>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0-z0uq63s4</link>
            <guid>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0-z0uq63s4</guid>
            <pubDate>Fri, 01 Oct 2021 12:49:16 GMT</pubDate>
            <description><![CDATA[<h2 id="바닐라-자바스크립트-요구사항-분석-구현-연습">[바닐라 자바스크립트] 요구사항 분석 구현 연습</h2>
<h3 id="세-번째-미션">세 번째 미션</h3>
<pre><code> - 웹서버를 띄우고, api를 요청하여 메뉴판을 관리하기</code></pre><blockquote>
<h4 id="🎯-step3-요구사항---서버와의-통신을-통해-메뉴-관리하기">🎯 step3 요구사항 - 서버와의 통신을 통해 메뉴 관리하기</h4>
</blockquote>
<ul>
<li>웹 서버를 띄워서 실제 서버에 요청하는 형태로 리팩터링한다.<ul>
<li>fetch api 사용하는 부분을 async await을 사용하여 구현한다.</li>
<li>서버 통신에서 실패하는 부분에 대해 예외처리를 진행한다.</li>
</ul>
</li>
<li>중복되는 메뉴는 추가할 수 없다.</li>
</ul>
<hr>
<h3 id="step-3-요구사항-구현을-위한-전략">step 3. 요구사항 구현을 위한 전략</h3>
<h4 id="todo-서버-요청">TODO 서버 요청</h4>
<ol>
<li>서버에 카테고리에 따라 새로운 메뉴가 추가될 수 있도록 요청을 보낸다.</li>
<li>서버에 카테고리별 메뉴 리스트를 조회하도록 요청한다.</li>
<li>서버에 메뉴 이름 수정을 요청한다.</li>
<li>서버에 메뉴 품절 상태 및 품절 상태가 아닌 상태가 되도록 요청을 보낸다.</li>
<li>서버에 메뉴 삭제를 할 수 있도록 요청을 보낸다.</li>
</ol>
<h4 id="todo-리팩토링">TODO 리팩토링</h4>
<ol>
<li>로컬스토리지에 저장하는 로직은 지운다. </li>
<li>fetch 비동기 api 사용하는 부분을 async await을 사용하여 구현한다.</li>
</ol>
<pre><code>- POST 추가 메서드 : 카테고리별 메뉴 이름 저장 요청하기
- GET 조회 메서드 : 카테고리별 메뉴 리스트를 조회 요청하기
- PUT 수정 메서드 : 메뉴 이름 수정 요청보내기
- PUT 수정 메서드 : 메뉴 품절 상태 변경 요청보내기
- DELETE 수정 메서드 : 메뉴 이름 삭제 요청보내기</code></pre><h4 id="todo-사용자-경험">TODO 사용자 경험</h4>
<ol>
<li>서버 통신 실패하는 경우에 대해 사용자가 알수 있도록 alert으로 예외처리를 진행한다.</li>
<li>중복되는 메뉴는 추가할 수 없도록 한다.</li>
</ol>
<hr>
<h3 id="step-3-과정에서-배운-내용-및-회고">step 3 과정에서 배운 내용 및 회고</h3>
<ol>
<li>요구 사항 구현을 위한 전략을 나누는 방법에 대해 알게되었습니다.</li>
<li>HTTP_METHOD를 객체로 만들어서 사용 및 reques 함수 생성으로 코드 리팩토링할수 있는 것을 배울 수 있었습니다.</li>
<li>가독성을 높이는 코드 작성 방법에 대해 배우게 되었습니다.</li>
<li>사용자 경험 및 사용자 관점에서 코드를 작성해야하는 것에 대한 중요성에 대해 배우게 되었습니다.</li>
<li>웹 고향과 웹의 아버지 등 웹에 대해 배우게 되었습니다.</li>
<li>이번 강의를 통해 자바스크립트 기본기를 갖추는 것이 중요하고 요구사항 분석이 중요하다는 것에 대해 다시 한 번 깨우치게 되었습니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[바닐라 자바스크립트] 요구사항 분석 및 구현 연습 일기]]></title>
            <link>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0-qjswws69</link>
            <guid>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0-qjswws69</guid>
            <pubDate>Wed, 29 Sep 2021 13:28:02 GMT</pubDate>
            <description><![CDATA[<h2 id="바닐라-자바스크립트-요구사항-분석-구현-연습">[바닐라 자바스크립트] 요구사항 분석 구현 연습</h2>
<h3 id="두-번째-미션">두 번째 미션</h3>
<pre><code> - 카페의 메뉴판 여러개 만들기</code></pre><blockquote>
<h4 id="🎯-step2-요구사항---상태-관리로-메뉴-관리하기">🎯 step2 요구사항 - 상태 관리로 메뉴 관리하기</h4>
</blockquote>
<ul>
<li>localStorage에 데이터를 저장하여 새로고침해도 데이터가 남아있게 한다.</li>
<li>에스프레소, 프라푸치노, 블렌디드, 티바나, 디저트 각각의 종류별로 메뉴판을 관리할 수 있게 만든다.<ul>
<li>페이지에 최초로 접근할 때는 에스프레소 메뉴가 먼저 보이게 한다.</li>
</ul>
</li>
<li>품절 상태인 경우를 보여줄 수 있게, 품절 버튼을 추가하고 sold-out class를 추가하여 상태를 변경한다.</li>
</ul>
<hr>
<h3 id="step-2-요구사항-구현을-위한-전략">step 2. 요구사항 구현을 위한 전략</h3>
<h4 id="todo-로컬스토리지-데이터-저장-및-데이터-불러오기">TODO 로컬스토리지 데이터 저장 및 데이터 불러오기</h4>
<ol>
<li>로컬스토리지에 데이터를 저장한다.</li>
</ol>
<pre><code> 세부사항
 1-1. 에스프레소 메뉴판을 클릭했을 경우 
  - 메뉴 추가 : 에스프레소 메뉴 이름을 입력하고 확인 버튼을 클릭하면 로컬스토리지에 입력값이 에스프레소 메뉴판에 저장된다.
  - 메뉴 수정 : 생성된 메뉴 이름의 수정 버튼을 클릭하여 메뉴 이름을 수정하면 업데이트된 입력값이 로컬스토리지에 수정되어 저장된다.
  - 메뉴 삭제 : 생성된 메뉴 이름의 삭제 버튼을 클릭하면 로컬스토리지에 저장된 해당 입력값이 삭제된다.
  1-2. 에스프레소, 프라푸치노, 블랜디드, 티바나, 디저트 각각의 메뉴판 클릭시 1.1과 동일
  1-3. 로컬스토리지 저장 {Key: value} 
       key &lt;- 카테고리 이름 : 에스프레소, 프라푸치노 ...
       value &lt;- 메뉴 이름 (배열 형태로 저장)</code></pre><ol start="2">
<li>로컬스토리지에 저장된 데이터를 불러온다.</li>
</ol>
<h4 id="todo-카테고리별-메뉴판-관리">TODO 카테고리별 메뉴판 관리</h4>
<ol>
<li>에스프레소 메뉴판 관리</li>
<li>프라푸치노 메뉴판 관리</li>
<li>블랜디드 메뉴판 관리</li>
<li>티바나 메뉴판 관리</li>
<li>디저트 메뉴판 관리</li>
</ol>
<pre><code>세부사항
1) 메뉴판 이름에 대한 클릭 이벤트를 등록해준다. (카테리고리 지정 및 각 해당하는 데이터 읽어오기)
2) e.target이 에스프레소이면 로컬스토리지 key = 에스프레소로 저장되어진다.
- 메뉴판 타입이 에스프레소이면 Key = 에스프레소
- 메뉴판 타입이 프라푸치노이면 Key = 프라푸치노
- 메뉴판 타입이 블랜디드이면 Key = 블랜디드
- 메뉴판 타입이 티바나이면 Key = 티바나
- 메뉴판 타입이 디저트이면 Key = 디저트</code></pre><h4 id="todo-페이지-접근시-최초-화면-데이터-read--rendering">TODO 페이지 접근시 최초 화면 데이터 read &amp; rendering</h4>
<ol>
<li>에스프레소 메뉴판을 기본값으로 설정하여 최초 화면에 에스프레소 메뉴가 보이도록 로컬스토리지에서 해당 데이터의 메뉴를 모두 읽어온다.</li>
<li>에스프레소 메뉴를 페이지에 그려준다.</li>
</ol>
<pre><code>세부사항
- 로컬스토리지에 저장된 데이터 모두 꺼내온다.(key,value)
- 메뉴판 각각을 클릭하면 로컬스토리지에 저장되어 있는 카테고리별 메뉴를 모두 꺼내와서 보여지도록 한다.</code></pre><h4 id="todo-품절-상태-관리">TODO 품절 상태 관리</h4>
<ol>
<li>품절 상태인 경우를 보여줄 수 있게, 품절 버튼을 추가하고 sold-out class를 추가하여 상태를 변경한다.</li>
<li>품절 상태인 경우 품절 버튼을 그려준다.</li>
<li>품절 버튼을 클릭하면 로컬스토리지에 상태값이 저장된다.</li>
<li>품절 상태인 태그에 sold-out class를 추가한다.</li>
</ol>
<hr>
<h3 id="step-2-과정에서-배운-내용-및-회고">step 2 과정에서 배운 내용 및 회고</h3>
<ol>
<li>this 키워드가 객체 자신을 가지기 때문에 각 각의 인스턴스가 가지고 있는 상태나 메서드를 객체 외부에서 사용할 때 유용하게 사용할 수 있고 사용하는 방법에 대해 배우게 되었습니다.</li>
<li>상태값의 중요하다는 것에 대해 또 한번 느끼게 되었습니다.</li>
<li>재사용가능하도록 구현하는 방법에 대해 배우게 되었습니다.</li>
<li>data-set 사용 및 활용하는 방법에 대해 알게 되었습니다.</li>
<li>객체로 key, value 값을 정의하는 방법에 대해 깨닫게 되었습니다.</li>
<li>코드리팩토링을 통해 가독성 좋은 코드로 나아가기위한 방법에 대해 배우게 되었습니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[바닐라 자바스크립트] 요구사항 분석 및 구현 연습 일기]]></title>
            <link>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0</link>
            <guid>https://velog.io/@seong-dodo/%EB%B0%94%EB%8B%90%EB%9D%BC-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9A%94%EA%B5%AC%EC%82%AC%ED%95%AD-%EB%B6%84%EC%84%9D-%EB%B0%8F-%EA%B5%AC%ED%98%84-%EC%97%B0%EC%8A%B5-%EC%9D%BC%EA%B8%B0</guid>
            <pubDate>Wed, 29 Sep 2021 06:32:36 GMT</pubDate>
            <description><![CDATA[<h2 id="바닐라-자바스크립트-요구사항-분석-구현-연습">[바닐라 자바스크립트] 요구사항 분석 구현 연습</h2>
<h3 id="첫-번째-미션">첫 번째 미션</h3>
<pre><code> - 카페의 에스프레소 메뉴판 만들기</code></pre><blockquote>
<h4 id="🎯-step1-요구사항---돔-조작과-이벤트-핸들링으로-메뉴-관리하기">🎯 step1 요구사항 - 돔 조작과 이벤트 핸들링으로 메뉴 관리하기</h4>
</blockquote>
<ul>
<li>에스프레소 메뉴에 새로운 메뉴를 확인 버튼 또는 엔터키 입력으로 추가한다.<ul>
<li>메뉴가 추가되고 나면, input은 빈 값으로 초기화한다.</li>
<li>사용자 입력값이 빈 값이라면 추가되지 않는다.</li>
</ul>
</li>
<li>메뉴의 수정 버튼을 눌러 메뉴 이름 수정할 수 있다.<ul>
<li>메뉴 수정시 브라우저에서 제공하는 prompt 인터페이스를 활용한다.</li>
</ul>
</li>
<li>메뉴 삭제 버튼을 이용하여 메뉴 삭제할 수 있다.<ul>
<li>메뉴 수정시 브라우저에서 제공하는 confirm 인터페이스를 활용한다.</li>
</ul>
</li>
<li>총 메뉴 갯수를 count하여 상단에 보여준다.</li>
</ul>
<hr>
<h3 id="step-1-요구사항-구현을-위한-전략">step 1. 요구사항 구현을 위한 전략</h3>
<h4 id="todo-메뉴-추가">TODO 메뉴 추가</h4>
<ol>
<li>메뉴의 이름을 입력 받고 엔터키 입력으로 추가한다.</li>
</ol>
<pre><code>   세부사항
   1-1. form 태그가 자동으로 전송되지 않도록 막아준다.
   1-2. input태그에 메뉴의 이름을 입력받도록 한다.
   1-3. 확인 버튼의 클릭 이벤트를 등록해준다.
   1-4. espresso-menu-list에 메뉴 리스트 태그가 생성되고 추가된다.</code></pre><ol start="2">
<li>메뉴의 이름을 입력 받고 확인 버튼을 누르면 메뉴가 추가된다.</li>
<li>메뉴가 추가되고 나면, input은 빈 값으로 초기화한다</li>
<li>사용자 입력값이 빈 값이라면 추가되지 않는다.</li>
<li>총 메뉴 갯수를 count하여 상단에 보여준다. (TODO 메뉴 총 갯수 카운팅)</li>
</ol>
<h4 id="todo-메뉴-수정">TODO 메뉴 수정</h4>
<ol>
<li>메뉴의 수정 버튼을 클릭하면 메뉴 이름을 수정할 수 있는 prompt 창이 열린다. </li>
</ol>
<pre><code>   세부사항
   1-1. 메뉴 수정시 브라우저에서 제공하는 &#39;propmt&#39; 인터페이스를 활용</code></pre><ol start="2">
<li>수정 창에 메뉴 이름을 변경하고 완료버튼을 클릭하면 메뉴 이름이 수정된다.</li>
</ol>
<h4 id="todo-메뉴-삭제">TODO 메뉴 삭제</h4>
<ol>
<li>메뉴 삭제 버튼을 클릭하면 해당 메뉴가 삭제된다.</li>
</ol>
<pre><code>  세부사항
  1-1. 메뉴 삭제시 브라우저에서 제공하는 &#39;confirm&#39; 인터페이스를 활용</code></pre><ol start="2">
<li>총 메뉴 갯수를 count하여 상단에 보여준다. (TODO 메뉴 총 갯수 카운팅)</li>
</ol>
<hr>
<h3 id="step-1-과정에서-배운-내용-및-회고">step 1 과정에서 배운 내용 및 회고</h3>
<ol>
<li>이벤트 위임이란 무엇이고 실제로 어떻게 적용하느지에 대해 알게 되었습니다.</li>
<li>요구사항을 전략적으로 접근하기 위해 단계별로 세세하게 분석하는 것이 중요하다는 것을 알게 되었습니다.</li>
<li>DOM 요소를 가져올때는 &#39;$표시를 사용하여 변수처럼 사용&#39;할 수 있는 것을 배우게 되었습니다.</li>
<li>새로운 메서드 insertAdjacentHtml, closest, contains을 알게 되었습니다.</li>
<li>window 내장 함수 prompt, confirm 사용 방법에 대해 알게 되었습니다.</li>
<li>form 태그가 가지고 있는 기본값 이벤트에 대해 알게 되었습니다.</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>