<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>🌵</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 14 Nov 2023 08:40:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>🌵</title>
            <url>https://velog.velcdn.com/images/p_seo_hn/profile/9f45f76f-c9ec-44f9-8536-077b135bae81/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 🌵. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/p_seo_hn" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[web socket]]></title>
            <link>https://velog.io/@p_seo_hn/web-socket</link>
            <guid>https://velog.io/@p_seo_hn/web-socket</guid>
            <pubDate>Tue, 14 Nov 2023 08:40:40 GMT</pubDate>
            <description><![CDATA[<h1 id="websocket-프로토콜이란">WebSocket 프로토콜이란</h1>
<ul>
<li>클라이언트와 서버를 연결하고 실시간으로 통신이 가능하도록 하는 첨단 기술</li>
<li>연결이 설정되면 별도의 요청을 보내지 않고도 데이터를 수실할 수 있다.</li>
</ul>
<blockquote>
<p>작동 방식</p>
</blockquote>
<ul>
<li>클라이언트와 서버간의 연결은 당사자 중 하나에 의해 종료되거나 시간초과에 의해 닫힐 때 까지 열린 상태로 유지된다.</li>
<li>설정된 연결은 열린 상태로 유지되며 클라이언트 도는 서버 츨에서 연결이 종료될 때 까지 동일한 채널을 사용하여 통신이 수행된다.</li>
</ul>
<blockquote>
<p>웹소켓은 언제 사용하는가</p>
</blockquote>
<p>실시간 데이터 업데이트와 클라이언트 메세지를 보내는 기능이 필요할 때 이상적이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[6. useEffect의 실행 순서에 대해 설명해주세요.]]></title>
            <link>https://velog.io/@p_seo_hn/6.-useEffect%EC%9D%98-%EC%8B%A4%ED%96%89-%EC%88%9C%EC%84%9C%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/6.-useEffect%EC%9D%98-%EC%8B%A4%ED%96%89-%EC%88%9C%EC%84%9C%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Thu, 12 Oct 2023 04:27:24 GMT</pubDate>
            <description><![CDATA[<ol>
<li>컴포넌트 렌더링</li>
<li>DOM 업데이트</li>
<li>useEffect 실행</li>
</ol>
<p>만약 useEffect가 의존성 배열을 가지고 있다면 그 배열 내의 값이 변결될 때마다 useEffect가 다시 실행됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[5. useRef에 대해 설명해주세요.]]></title>
            <link>https://velog.io/@p_seo_hn/5.-useRef%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/5.-useRef%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Thu, 12 Oct 2023 02:23:22 GMT</pubDate>
            <description><![CDATA[<p>useRef는 리액트의 Hook 중 하나로, 랜더 사이클에 영향을 주지 않는 참조를 만들 때 사용합니다.</p>
<p>useRef를 사용하면 직접적으로 리얼DOM 엘리먼트에 접근할 수 있습니다.
예를 들어 특정 input 엘리먼트에 포커스를 주거나, 엘리먹트 크리와 위치 정보를 얻을 때 사용합니다.</p>
<p>컴포넌트의 렌더링 사이클에 영향을 미치지 않는 변수를 저장할 때에도 사용합니다.
예를 들어 타이머ID, 애니메이션 등을 저장하고 관리할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[3. Redux 말고 다른 전역 상태관리 아는 것 하나와 차이점을 말해주세요]]></title>
            <link>https://velog.io/@p_seo_hn/3.-Redux-%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EC%95%84%EB%8A%94-%EA%B2%83-%ED%95%98%EB%82%98%EC%99%80-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%84-%EB%A7%90%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/3.-Redux-%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%EC%A0%84%EC%97%AD-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EC%95%84%EB%8A%94-%EA%B2%83-%ED%95%98%EB%82%98%EC%99%80-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%84-%EB%A7%90%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Thu, 12 Oct 2023 02:18:33 GMT</pubDate>
            <description><![CDATA[<p>Reciol</p>
<p>기본적인 단위는 Atom과 Selector입니다.</p>
<ul>
<li>Atom은 상태 단위이고 Selector는 파생 상태를 만들 수 있습니다.
Atom은 key라는 고유한 식별자, default라는 초기상태를 가집니다.</li>
<li>Selector는 하나 이상의 Atom을 입력 받아 새로운 상태 값을 계산합니다.
예를 들어 할 일 목록과 완료된 할 일 목록이 각 각 Atom에 저장되어 있다면 완료되지 않은 할 일 목록을 Selector로 만들 수 있습니다.</li>
</ul>
<p>Recoil은 React의 기존 Hooks API와 유사한 API를 제공하므로 더욱 React 스럽게 느껴집니다.</p>
<p>상태가 직접 연결괴므로 상태의 데이터 흐름을 쉽게 추적할 수 있습니다.</p>
<p>차이점
Redux는 액션과 리듀서를 정의애햐하므로 초기 설정이 복잡할 수 있습니다.
Recoil은 상태를 쿼리할 수 있는 Selector를 제공합니다. Redux는 별도의 라이브러리나 추가 로직이 필요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[12. JSX란 무엇인가요?]]></title>
            <link>https://velog.io/@p_seo_hn/12.-JSX%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/12.-JSX%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 13:42:33 GMT</pubDate>
            <description><![CDATA[<p>JavaScript XML의 줄임말로, 리액트에서 사용되는 문법 중 하나입니다. 
HTML과 비슷하게 생겼지만, 실제로는 JavaScript의 확장 문법입니다. 
JSX를 통해 UI 구조를 더 직관적이고 가독성 높게 표현할 수 있습니다.</p>
<p>리액트 컴포넌트를 간결하고 명료아게 표현할 수 있습니다.
자바스크립트 표현식을 사용할 때에는 중괄호안에 넣어 사용할 수 있습니다. 
속성 설정은 class대신 className을 사용하거나 for대신 htmlFore을 사용하듯이 몇가지 이름이 다릅니다.</p>
<p>제가 사용하였을때에는 페이지 컴포넌트를 만들 때 return문 안에 페이지의 요소들을 만들으며 사용하였습니다. onClick 함수나 다른 함수들을 만들 때에는 return문 위에서 작성하기 때문에 일반적인 자바스크립트 문법을 사용하였습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[8. Async/Await와 Promise의 차이에 대해 설명해주세요.]]></title>
            <link>https://velog.io/@p_seo_hn/8.-AsyncAwait%EC%99%80-Promise%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/8.-AsyncAwait%EC%99%80-Promise%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 13:33:58 GMT</pubDate>
            <description><![CDATA[<p>Async/Await와 Promise는 모두 자바스크립트에서 비동기 처리를 위한 방법입니다. 
사용 방식과 가독성에 차이가 있습니다.</p>
<p>비동기란 프로그램이 특정 작업을 완료하는 동안 다른 작업을 동시에 수행할 수 있게 하는 처리 방식을 말합니다.</p>
<p>Promise
비동기작업의 최종완료 또는 실패를 나타내는 객체입니다.
.then() .catch() 메서드를 사용하여 비동기 작업이 성공했을때와 실패했을때의 로직을 분리할 수 있습니다.
여러개의 .then()을 연결하여 비동기 작업을 순차적으로 처리할 수 있습니다.</p>
<p>Async/Await
비동기 코드를 마치 동기 코드처럼 작성할 수 있습니다.
async 함수 내에서 await 키워드를 사용하면 해당 비동기 작업이 완료될 때 까지 함수의 실행을 일시적으로 중단합니다.
try catch 블록을 사용하여 에러 처리를 할 수 있으므로 가독성이 높아지고, 에러를 쉽게 잡을 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[10 ‘==’와 ‘===’ 연산자의 차이는 무엇인지 설명해주실 수 있을까요?]]></title>
            <link>https://velog.io/@p_seo_hn/10-%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%8B%A4-%EC%88%98-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/10-%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%8B%A4-%EC%88%98-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 13:28:05 GMT</pubDate>
            <description><![CDATA[<p>&#39;==&#39; 는 동등 연산자입니다.
두 값이 같은지 비교하기 전에 타입을 자동으로 변환합니다. 따라서 다른 타입의 값을 비교할 때에도 사용할 수 있습니다.</p>
<p>&#39;===&#39; 일치 연산자 입니다.
타입 변환을 허용하지 않습니다. 값, 타입 모두 정확히 일치하는지 확인합니다. 따라서 값이 같더라도 타입이 다르면 false를 반환합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[4. 버츄얼 돔과 리얼 돔의 차이를 설명해주세요.]]></title>
            <link>https://velog.io/@p_seo_hn/4.-%EB%B2%84%EC%B8%84%EC%96%BC-%EB%8F%94%EA%B3%BC-%EB%A6%AC%EC%96%BC-%EB%8F%94%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/4.-%EB%B2%84%EC%B8%84%EC%96%BC-%EB%8F%94%EA%B3%BC-%EB%A6%AC%EC%96%BC-%EB%8F%94%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%84%A4%EB%AA%85%ED%95%B4%EC%A3%BC%EC%84%B8%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 13:25:01 GMT</pubDate>
            <description><![CDATA[<p>DOM은 Document Object Model을 말합니다.</p>
<p>실제 DOM
웹페이지의 구조를 나타내는 객체 모델입니다.
웹페이지의 각 요소(태그, 속성, 텍스트 등)에 대한 정보와 이들의 관계를 표현합니다.</p>
<p>실제 DOM을 직접 수정하면 화면에 바로 반영이 됩니다.
하지만 실제 DOM을 변경할 때 마다 페이지 전체가 다시 렌더링 되는 경우가 있어서 성능에 문제가 생길 수 있습니다.</p>
<p>가상 DOM
실제 DOM을 추상화 한 개념으로 리얼돔과 유사한 특성을 가지지만 메모리 내에 존재합니다.</p>
<p>가상 DOM을 변경하면 메모리에서 변경이 일어나기 때문에 실제 DOM을 직접 수정하는것보다 빠릅니다.
변경된 가상 DOM과 이전 가상 DOM을 비교하여 최소한의 변경사항을 찾아낸 다음 그 변경사항만을 실제 DOM에 반영합니다. 이렇게 하면 불필요한 렌더링을 줄일 수 있어 성능이 향상됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2. Redux가 무엇인가요, 왜 Redux를 사용하시나요?]]></title>
            <link>https://velog.io/@p_seo_hn/2.-Redux%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-%EC%99%9C-Redux%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%8B%9C%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/2.-Redux%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-%EC%99%9C-Redux%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%8B%9C%EB%82%98%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 13:18:07 GMT</pubDate>
            <description><![CDATA[<p>Redux란 
자바스크립트 상태 관리 라이브러리입니다.
리액트와 함께 사용되며, 앱 전체의 상태를 한 곳에서 관리할 수 있게 해줍니다.
리덕스는 스토어라는 하나의 큰 저장소를 두고 이 곳에서 모든 상태 정보를 관리합니다.</p>
<p>Redux를 사용하는 이유</p>
<p>첫 번째 일관성 입니다.
리덕스를 사용하면 어느 컴포넌트에서든 같은 상태를 참조하게 되니 일관성이 유지됩니다.
예를 들어 사용자의 로그인 상태를 보여주려면 리덕스에서 한 번만 관리하면 되기 때문에 편리합니다.</p>
<p>두 번째 컴포넌트 간 상태 공유 입니다.
여러 컴포넌트에서 같은 정보를 보여주거나 수정해야할 때, 모든 컴포넌트가 그 정보를 쉽게 가져다 쓸 수 있습니다.</p>
<p>세 번째 디버깅과 테스트가 용이합니다.
Redux DevTools를 사용하면 어떤 액션을 통해 상태가 어떻게 바뀌었는지 쉽게 확인할 수 있습니다.</p>
<p>네 번째 시간여행 디버깅 입니다.
Redux는 앱의 모든 상태 변화를 순차적으로 기록합니다. 그래서 언제든지 과거로 돌아가서 문제를 해결할 수 있습니다.</p>
<p>다섯번째 코드 재사용성과 유지보수 입니다.
액션 생성자나 리듀서같은 로직을 여러 곳에서 재사용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1. 상태관리를 왜 할까요? 그리고 평소 state 관리는 어떻게 하시나요?]]></title>
            <link>https://velog.io/@p_seo_hn/1.-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%99%9C-%ED%95%A0%EA%B9%8C%EC%9A%94-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%8F%89%EC%86%8C-state-%EA%B4%80%EB%A6%AC%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%95%98%EC%8B%9C%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@p_seo_hn/1.-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%99%9C-%ED%95%A0%EA%B9%8C%EC%9A%94-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%ED%8F%89%EC%86%8C-state-%EA%B4%80%EB%A6%AC%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%ED%95%98%EC%8B%9C%EB%82%98%EC%9A%94</guid>
            <pubDate>Wed, 11 Oct 2023 12:58:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<p>리액트는 실제 DOM 변경 전에 내부적으로 가상 DOM이라는 개념이 사용됩니다.
가상 DOM에서 미리 변화를 적용해 본 뒤 실제 DOM과 비교해서 다른 부분만 업데이트해줍니다.
그렇기 때문에 직접적으로 DOM을 조작하지 않고 HTML과 비슷한 JSX 문법을 통해 View를 정의하되
특정 상태값에 따라 컴포넌트를 어떤식으로 렌더링할지 선언하는 방식입니다.</p>
<p>상태관리를 하는 이유는</p>
<p>첫번째로
상태 관리를 통해 앱의 동작을 예측 가능하게 만들 수 있습니다.
예를 들어  버튼을 누르면 팝업이 뜨고, 그 팝업에서 확인을 누르면 데이터가 저장되는 등
상태를 잘 관리하면 이런 동작들이 일관되게 작동합니다.</p>
<p>두 번째는 컴포넌트 간 상태 공유입니다.
여러 컴포넌트에서 같은 상태를 사용해야 할 때, 이 상태를 효율적으로 관리 해 주어야 합니다.
A, B, C 세 개의 컴포넌트가 동일한 데이터를 참조하거나 수정할 때 상태관리가 없으면 A에서 변경한 값을 B, C가 모르게 됩니다.
상태 관리를 통해 이 상태를 &quot;중앙에서&quot; 관리하게 되면, A 컴포넌트에서 상태를 변경했을 때 그 변경이 B와 C에도 자동으로 반영되게 할 수 있습니다.</p>
<p>세 번째는 성능 최적화 입니다.
상태를 잘 관리하면 불필요한 렌더링을 줄일 수 있어 성능에 긍정적인 영향을 미치게 됩니다.</p>
<p>네 번째 가독성과 유지보수입니다.
상태관리 방식이 일관되면 코드 가독성도 좋아지고 나중에 다른 사람이 코드를 봤을 때 이해하기 쉬워집니다.</p>
<p>평소 State 관리는 
간단한 상태 로직에서 useState를 이용합니다. 상위 컴포넌트에서 상태를 관리하고 하위 컴포넌트에세 props로 상태를 전달 해 줍니다.
만약 상태 공유가 복잡하거나 여러 컴포넌트에서 상태를 공유해야 할 경우 전역 상태 관리 라이브러리를 사용합니다. 라이브러리는 Redux, Recoil을 사용 해 보았습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 준비]]></title>
            <link>https://velog.io/@p_seo_hn/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%80%EB%B9%84</link>
            <guid>https://velog.io/@p_seo_hn/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%80%EB%B9%84</guid>
            <pubDate>Wed, 04 Oct 2023 00:28:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="🐸-설치-라이브러리">🐸 설치 라이브러리</h1>
<p><code>yarn create react-app final-sample --template typescript</code></p>
</blockquote>
<pre><code>yarn add  
react-query 
recoil 
@mui/material 
@mui/icons-material 
tailwindcss 
clsx 
react-router-dom</code></pre><pre><code>yarn tailwindcss init</code></pre><p><img src="https://velog.velcdn.com/images/p_seo_hn/post/28ab79ed-d433-47f1-852d-c26b000bf0e9/image.png" alt=""></p>
<p>📁 shared / Router.tsx</p>
<ul>
<li>웹 앱에서 라우팅 로직을 중앙에서 관리하는 역할</li>
<li>jsx 문법이 들어가기 때문에 확장자명을 <code>.tsx</code>로 지정해야 한다.<pre><code class="language-javascript">import React from &#39;react&#39;;
import { BrowserRouter, Route, Routes } from &#39;react-router-dom&#39;;
import Home from &#39;../pages/Home&#39;;
import Signin from &#39;../pages/SignIn&#39;;
import SignUp from &#39;../pages/SignUp&#39;;
</code></pre>
</li>
</ul>
<p>const Router = () =&gt; {
  return (
    <BrowserRouter>
      <Routes>
        &lt;Route path=&quot;/&quot; element={<Home />} /&gt;
        &lt;Route path=&quot;/signin&quot; element={<Signin />} /&gt;
        &lt;Route path=&quot;/signup&quot; element={<SignUp />} /&gt;
      </Routes>
    </BrowserRouter>
  );
};</p>
<p>export default Router;</p>
<pre><code>
📁 App.tsx
```javascript
import &#39;./App.css&#39;;
import Router from &#39;./shared/Router&#39;;
import React from &#39;react&#39;;

function App() {
  return (
    &lt;Router /&gt;
  );
}

export default App;</code></pre><p>📁 App.tsx</p>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import { Link } from &#39;react-router-dom&#39;;


const Home = () =&gt; {
  return (
    &lt;div&gt;
      &lt;Link to={`/signin`}&gt;SIGN IN&lt;/Link&gt;
      &lt;br /&gt;
      &lt;Link to={`/signup`}&gt;SIGN UP&lt;/Link&gt;
    &lt;/div&gt;
  );
};
export default Home;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹 소켓]]></title>
            <link>https://velog.io/@p_seo_hn/%EC%9B%B9-%EC%86%8C%EC%BC%93</link>
            <guid>https://velog.io/@p_seo_hn/%EC%9B%B9-%EC%86%8C%EC%BC%93</guid>
            <pubDate>Mon, 02 Oct 2023 15:26:37 GMT</pubDate>
            <description><![CDATA[<ul>
<li>서버와 유저가 데이터 주고 받으려면 http 요청을 이용한다.</li>
<li>유저 : 데이터 정보를 주세요 (http 요청을 날림)</li>
<li>서버 : 유저에게 해당 데이터를 보내줌</li>
</ul>
<h1 id="웹소켓">웹소켓</h1>
<ul>
<li>유저와 서버의 <strong>양방향 통신</strong></li>
</ul>
<br>

<h2 id="준비">준비</h2>
<ul>
<li>폴더 생성
<img src="https://velog.velcdn.com/images/p_seo_hn/post/fa2f4142-0195-4698-9211-baf6ca9aaba6/image.png" alt=""></li>
<li><code>server.js</code>파일 성성 후 터미널에 <code>yarn init</code><ul>
<li>package.json 파일이 생성된다.
<img src="https://velog.velcdn.com/images/p_seo_hn/post/9a8798b7-42e9-460d-8680-5ff8475b8020/image.png" alt=""></li>
</ul>
</li>
<li><code>yarn add express ws</code><ul>
<li>express : 서버를 만들어주는 라이브러리</li>
<li>ws : 웹소켓 연결을 뚫어주는 라이브러리
<img src="https://velog.velcdn.com/images/p_seo_hn/post/27e76ded-119f-4114-866d-0f62833b65a4/image.png" alt=""></li>
</ul>
</li>
</ul>
<br>

<h2 id="웹서버-만드는-코드-작성">웹서버 만드는 코드 작성</h2>
<ul>
<li>📁 server.js<pre><code class="language-javascript">const express = require(&#39;express&#39;);
const app = express();
</code></pre>
</li>
</ul>
<p>app.use(&#39;/&#39;, function (req, res) {
  res.sendFile(__dirname + &#39;/index.html&#39;);
});</p>
<p>app.listen(8080);</p>
<pre><code>
&lt;br&gt;

## 유저가 접속 할 html
- 📁 index.html
![](https://velog.velcdn.com/images/p_seo_hn/post/339814c4-fa40-43e5-a4be-7d73e75b3ac2/image.png)
```html
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;title&gt;웹소켓 연습하기&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h4&gt;채팅페이지입니다&lt;/h4&gt;
  &lt;button id=&quot;send&quot;&gt;메세지 보내기&lt;/button&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><ul>
<li>실행
<img src="https://velog.velcdn.com/images/p_seo_hn/post/61ed2106-2897-44d6-982b-78a5c73ae232/image.png" alt="">
<img src="https://velog.velcdn.com/images/p_seo_hn/post/9ac75c89-7554-4326-a241-25adbe563804/image.png" alt=""></li>
</ul>
<br>

<h2 id="유저-웹소켓-연결하기">유저 웹소켓 연결하기</h2>
<ul>
<li>📁 server.js 코드 추가 <pre><code class="language-javascript">const webSocket = require(&#39;ws&#39;);
</code></pre>
</li>
</ul>
<p>const socket = new webSocket.Server({
  port: 8081
})</p>
<pre><code>
&lt;br&gt;

## 유저가 웹소켓 요청하기
- 📁 index.html 코드 추가
```html
&lt;script&gt;
  let socket = new webSocket(&quot;ws://localhost:8081&quot;)
&lt;/script&gt;</code></pre><br>

<h2 id="웹소켓으로-유저가-서버에게-메세지-보내기">웹소켓으로 유저가 서버에게 메세지 보내기</h2>
<ul>
<li>📁 index.html 코드 수정<pre><code class="language-html">&lt;button id=&quot;send&quot; onclick=&quot;socket.send(&#39;원하는 문자 입력&#39;)&quot;&gt;메세지 보내기&lt;/button&gt;</code></pre>
</li>
</ul>
<h2 id="서버에서-메세지-수신하기">서버에서 메세지 수신하기</h2>
<ul>
<li>📁 server.js 코드 추가<pre><code class="language-javascript">socket.on(&#39;connection&#39;, (ws, req) =&gt; {
ws.on(&#39;message&#39;, (msg) =&gt; {
  console.log(&#39;유저가 보낸거 : &#39; + msg);
  ws.send(&#39;서버에서 유저에게 보내는 메세지&#39;);
});
});</code></pre>
</li>
</ul>
<blockquote>
<p>ws대신 socket.io라이브러리 쓰면</p>
</blockquote>
<ol>
<li>연결 끊기면 자동 재접속 기능</li>
<li>웹소켓 접속자마다 자도 ㅇid 부여</li>
<li>모든 웹소켓 유저에게 전체 메세지 전송 가능</li>
<li>웹소켓방을 생성 가능</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript]]></title>
            <link>https://velog.io/@p_seo_hn/TypeScript-80c5sx5v</link>
            <guid>https://velog.io/@p_seo_hn/TypeScript-80c5sx5v</guid>
            <pubDate>Sat, 16 Sep 2023 13:38:33 GMT</pubDate>
            <description><![CDATA[<h1 id="터미널에-tsc--w-입력">터미널에 <code>tsc -w</code> 입력</h1>
<ul>
<li>브라우저는 ts파일을 못읽는다.</li>
<li>명령어 입력하면 자동으로 js파일로 변환해준다.</li>
</ul>
<br>

<hr>
<br>

<h1 id="타입-지정">타입 지정</h1>
<pre><code class="language-javascript">  const 사람: {name? : string, age : number} = { age : 20}</code></pre>
<ul>
<li>?를 붙이면 그 속성은 옵션이다. (넣어도 되고 안넣어도 됨)<br>

</li>
</ul>
<pre><code class="language-javascript">const 생일: string | number = &quot;2020-01-01&quot;;</code></pre>
<ul>
<li>다양한 타입 지정 ( Union type )</li>
</ul>
<br>

<pre><code class="language-javascript">type ManyType = string | number | Boolean;
const 이것저것: ManyType = 123;</code></pre>
<ul>
<li>타입을 변수로 지정하여 사용 가능 </li>
<li>일반 변수명과 차별화 하기 위해 맨 앞은 대문자로 작성</li>
</ul>
<br>

<hr>
<br>

<h1 id="여러-타입">여러 타입</h1>
<pre><code class="language-javascript">function 함수2(x: number | string) : void {
  if(typeof x === &#39;number&#39;){
    console.log(x + 3)
  }
}
함수2(15);</code></pre>
<ul>
<li><code>number | string</code> : 새로운 타입</li>
<li>if문이 없다면 오류가 난다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모두의 테스트] 1일차-기획]]></title>
            <link>https://velog.io/@p_seo_hn/%EB%AA%A8%EB%91%90%EC%9D%98-%ED%85%8C%EC%8A%A4%ED%8A%B8-1%EC%9D%BC%EC%B0%A8-%EA%B8%B0%ED%9A%8D</link>
            <guid>https://velog.io/@p_seo_hn/%EB%AA%A8%EB%91%90%EC%9D%98-%ED%85%8C%EC%8A%A4%ED%8A%B8-1%EC%9D%BC%EC%B0%A8-%EA%B8%B0%ED%9A%8D</guid>
            <pubDate>Sat, 16 Sep 2023 02:26:45 GMT</pubDate>
            <description><![CDATA[<p>팀원들을 처음 만나는날, 기획하는 날이다.
spring boot를 주특기로 가지시는 분들과 만났다.</p>
<br>

<h1 id="아이디어-회의">아이디어 회의</h1>
<blockquote>
<p>음악을 공유 sns </p>
</blockquote>
<ul>
<li>이 주제로 했을 때 나중에 취업을 생각하면 이런 기능 구현을 필요로하는 회사들이 별로 없을 것 같다.</li>
<li>2주 프로젝트로 하기엔 스코프가 너무 크다</li>
</ul>
<blockquote>
<p>사용자가 직접 만드는 테스트 ( 설문조사 )</p>
</blockquote>
<ul>
<li>사용자가 직접 설문지를 만들고 그것을 공유할 수 있는 플랫폼을 만들기로 했다.</li>
</ul>
<br>

<h1 id="프론트앤드-회의">프론트앤드 회의</h1>
<blockquote>
<p>기능 분담</p>
</blockquote>
<ul>
<li>헤더, 푸터 - 서현</li>
<li>홈 화면 ( + 무한 스크롤, 인기순 슬라이드 ) - 채연</li>
<li>로그인, 회원 가입, 로그아웃 (+ 소셜 로그인) - 유진</li>
<li>마이 페이지 (프로필, 수정, 참여 테스트, 만든 테스트, 회원 탈퇴 ) - 유진</li>
<li>테스트 만들기 - 서현</li>
<li>테스트 ( 공유하기, 결과페이지, 댓글 )  - 채연</li>
</ul>
<blockquote>
<p>컴포넌트 역할 분담</p>
</blockquote>
<ul>
<li>사진업로드 - 채연</li>
<li>button - 서현</li>
<li>test-input - 서현</li>
<li>로그인,회원가입,-input- 유진</li>
</ul>
<blockquote>
<p>컨텐츠 너비</p>
</blockquote>
<p>1200px</p>
<p>bg-white</p>
<blockquote>
<p>페이지 만들며 고려해볼것</p>
</blockquote>
<p>point color : blue
font-size, </p>
<p>font-family</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[thunk 심화]]></title>
            <link>https://velog.io/@p_seo_hn/thunk-%EC%8B%AC%ED%99%94</link>
            <guid>https://velog.io/@p_seo_hn/thunk-%EC%8B%AC%ED%99%94</guid>
            <pubDate>Thu, 14 Sep 2023 08:05:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/p_seo_hn/post/ca9ce498-1174-48eb-ac02-309368b4b9d7/image.png" alt=""></p>
<h1 id="기본-코드">기본 코드</h1>
<p>📁 index.js</p>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import ReactDOM from &#39;react-dom/client&#39;;
import &#39;./index.css&#39;;
import App from &#39;./App&#39;;
import reportWebVitals from &#39;./reportWebVitals&#39;;
import { Provider } from &#39;react-redux&#39;;
import store from &#39;./redux/config/configStore&#39;;

const root = ReactDOM.createRoot(document.getElementById(&#39;root&#39;));
root.render(
  &lt;Provider store={store}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;
);

reportWebVitals();</code></pre>
<br>

<p>📁 App.jsx</p>
<pre><code class="language-javascript">import React from &#39;react&#39;

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

export default App</code></pre>
<br>

<p>📁 redux / config / configstore.js</p>
<pre><code class="language-javascript">import todos from &quot;../modules/todosSlice&quot;;
import { configureStore } from &quot;@reduxjs/toolkit&quot;;

const store = configureStore({
  reducer: {
    todos,
  },
});

export default store;</code></pre>
<br>

<p>📁 redux / modules / todosSlice.js</p>
<pre><code class="language-javascript">import { createSlice } from &quot;@reduxjs/toolkit&quot;;

const initialState = {
  todos: [],
}

export const todosSlice = createSlice({
  name: &quot;todos&quot;,
  initialState,
  reducers: {}
})

export const {} = todosSlice.actions;
export default todosSlice.reducer;</code></pre>
<br>

<p>📁 db.json</p>
<pre><code class="language-javascript">{
  &quot;todos&quot;: []
}</code></pre>
<br>

<hr>
<br>

<h1 id="순서">순서</h1>
<ol>
<li>trunk함수 구현</li>
<li>리듀서 로직 구현 : reducers -&gt; extraReducers<ul>
<li>tjqj xhdtls : 100% 성공(x)</li>
<li>지금까지의 redux state(todos, counter)</li>
<li>앞으로의 state(isLoading, isError, data)</li>
</ul>
</li>
<li>기능 확인(network) + devTools</li>
<li>Store의 값을 조회 + 화면에 렌더링</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[thunk 소개]]></title>
            <link>https://velog.io/@p_seo_hn/thunk-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@p_seo_hn/thunk-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Wed, 13 Sep 2023 20:07:49 GMT</pubDate>
            <description><![CDATA[<h1 id="thunk란">thunk란?</h1>
<ul>
<li>dispatch할 때 객체가 아닌 함수를 dispatch할 수 있게 해준다.</li>
<li>중간에 우리가 하고자 하는 작업을 함수를 통해 넣을 수 있고, 그것이 중간에 실행되는것이다.
<code>dispatch(함수) → 함수실행 → 함수안에서 dispatch(객체)</code></li>
</ul>
<h1 id="기본-코드">기본 코드</h1>
<p><img src="https://velog.velcdn.com/images/p_seo_hn/post/0c8c5883-e9f5-47a2-9905-999060646ad5/image.png" alt="">
📁 index.js</p>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom/client&quot;;
import &quot;./index.css&quot;;
import App from &quot;./App&quot;;
import reportWebVitals from &quot;./reportWebVitals&quot;;
import { Provider } from &quot;react-redux&quot;;
import store from &quot;./redux/config/configStore&quot;;

const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;));
root.render(
  &lt;Provider store={store}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;
);

reportWebVitals();</code></pre>
<br>

<p>📁 App.jsx</p>
<pre><code class="language-javascript">import logo from &quot;./logo.svg&quot;;
import &quot;./App.css&quot;;
import { useDispatch, useSelector } from &quot;react-redux&quot;;
import { addNumber, minusNumber } from &quot;./redux/modules/counter&quot;;
import { useState } from &quot;react&quot;;

function App() {
  const globalNumber = useSelector((state) =&gt; state.counter.number);
  const [number, setNumber] = useState(0);

  const dispatch = useDispatch();

  const onPlusButtonclickHandler = () =&gt; {
    dispatch(addNumber(+number));
  };

  const onMinusButtonClickHandler = () =&gt; {
    dispatch(minusNumber(+number));
  };

  return (
    &lt;div&gt;
      &lt;div&gt;{globalNumber}&lt;/div&gt;
      &lt;input
        type=&quot;number&quot;
        onChange={(e) =&gt; {
          setNumber(e.target.value);
        }}
      /&gt;
      &lt;br /&gt;
      &lt;button onClick={onPlusButtonclickHandler}&gt;더하기&lt;/button&gt;
      &lt;button onClick={onMinusButtonClickHandler}&gt;빼기&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<br>

<p>📁 redux / config / configStore.js</p>
<pre><code class="language-javascript">import counter from &quot;../modules/counter&quot;;

const { configureStore } = require(&quot;@reduxjs/toolkit&quot;);

const store = configureStore({
  reducer: {
    counter: counter,
  }
})

export default store;</code></pre>
<p>📁 redux / modules / counter.js</p>
<pre><code class="language-javascript">import { createSlice } from &quot;@reduxjs/toolkit&quot;

// 초기 상태(state)
const initialState = {
  number: 0
}

const counterSlice = createSlice({
  name: &#39;counter&#39;,
  initialState,
  reducers: {
    addNumber: (state, action) =&gt; {
      state.number = state.number + action.payload
    },
    minusNumber: (state, action) =&gt; {
      state.number = state.number - action.payload
    }
  }
});

export default counterSlice.reducer
export const {addNumber, minusNumber} = counterSlice.actions</code></pre>
<br>
<br>

<h1 id="순서">순서</h1>
<ol>
<li>thunk 함수 만들기 : createAsyncThunk<ul>
<li>reduxToolkit 내장 API</li>
</ul>
</li>
<li>createSlice &gt; extraReducer에 thunk 등록</li>
<li>dispatch</li>
<li>테스트</li>
</ol>
<h1 id="실습">실습</h1>
<p>📁 redux / modules / counter.js</p>
<pre><code class="language-javascript">import { createAsyncThunk, createSlice } from &quot;@reduxjs/toolkit&quot;;

//2개의 input
// (1) 이름 : 의미는 크게 없음
// (2) 함수
export const __addNumber = createAsyncThunk(
  &quot;ADD_NUMBER_WAIT&quot;,
  (payload, thunkAPI) =&gt; {
    // 수행하고 싶은 동작 : 3초 기다리게 할 예정
    setTimeout(() =&gt; {
      thunkAPI.dispatch(addNumber(payload));
    }, 3000);
  }
);

export const __minusNumber = createAsyncThunk(
  &quot;MINUS_NUMBER_WAIT&quot;,
  (payload, thunkAPI) =&gt; {
    // 수행하고 싶은 동작 : 3초 기다리게 할 예정
    setTimeout(() =&gt; {
      thunkAPI.dispatch(minusNumber(payload));
    }, 3000);
  }
);

// 초기 상태(state)
const initialState = {
  number: 0,
};

const counterSlice = createSlice({
  name: &quot;counter&quot;,
  initialState,
  reducers: {
    addNumber: (state, action) =&gt; {
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) =&gt; {
      state.number = state.number - action.payload;
    },
  },
});

export default counterSlice.reducer;
export const { addNumber, minusNumber } = counterSlice.actions;
</code></pre>
<br>

<p>📁 App.jsx</p>
<pre><code class="language-javascript">import &quot;./App.css&quot;;
import { useDispatch, useSelector } from &quot;react-redux&quot;;
import { useState } from &quot;react&quot;;
import { __addNumber, __minusNumber } from &quot;./redux/modules/counter&quot;; // 추가

function App() {
  const globalNumber = useSelector((state) =&gt; state.counter.number);
  const [number, setNumber] = useState(0);

  const dispatch = useDispatch();

  const onPlusButtonclickHandler = () =&gt; {
    dispatch(__addNumber(+number)); // 수정
  };

  const onMinusButtonClickHandler = () =&gt; {
    dispatch(__minusNumber(+number)); // 수정
  };

  return (
    &lt;div&gt;
      &lt;div&gt;{globalNumber}&lt;/div&gt;
      &lt;input
        type=&quot;number&quot;
        onChange={(e) =&gt; {
          setNumber(e.target.value);
        }}
      /&gt;
      &lt;br /&gt;
      &lt;button onClick={onPlusButtonclickHandler}&gt;더하기&lt;/button&gt;
      &lt;button onClick={onMinusButtonClickHandler}&gt;빼기&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<br>

<br>

<blockquote>
<p>리덕스 미들웨어를 사용하면, 액션이 리듀서로 전달되기 전에 중간에 어떤 작업을 더 할수 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[fetch, axios]]></title>
            <link>https://velog.io/@p_seo_hn/fetch-axios</link>
            <guid>https://velog.io/@p_seo_hn/fetch-axios</guid>
            <pubDate>Wed, 13 Sep 2023 17:29:28 GMT</pubDate>
            <description><![CDATA[<h1 id="fetch">Fetch</h1>
<ul>
<li>Promise 기반 비동기 통신 라이브러리</li>
<li>별도 설치 필요하지 않다.</li>
<li>단점<ul>
<li>미지원 브라우저 존재</li>
<li>개발자에게 불친절한 response (jon으로 변환 과정 필요)</li>
<li>axios에 비해 부족한 기능</li>
</ul>
</li>
<li>사용 예시<ul>
<li>두 개의 then 필요<pre><code class="language-javascript">const url = &quot;http://jsonplaceholder.typicode.com/todos&quot;;
fetch(url)
.then(response =&gt; response.json())
.then(console.log());</code></pre>
</li>
</ul>
</li>
<li>개발자가 일일히 then() 안에 모든 케이스에 대한 HTTP 에러 처리를 해야 한다.</li>
<li>예시<pre><code class="language-javascript">const url = &quot;https://jsonplaceholder.typicode.com/todos&quot;;
</code></pre>
</li>
</ul>
<p>fetch(url)
  .then((response) =&gt; {
    if (!response.ok) {
      throw new Error(
        <code>This is an HTTP error: The status is ${response.status}</code>
      );
    }
    return response.json();
  })
  .then(console.log)
  .catch((err) =&gt; {
    console.log(err.message);
  });</p>
<pre><code>
# axios
```javascript
const url = &quot;http://jsonplaceholder.typicode.com/todos&quot;;
axios.get(url).then(response =&gt; console.log(response.data))</code></pre><br>

<ul>
<li>에러메세지 확인<pre><code class="language-javascript">const url = &quot;https://jsonplaceholder.typicode.com/todos&quot;;
</code></pre>
</li>
</ul>
<p>axios
  .get(url)
  .then((response) =&gt; console.log(response.data))
  .catch((err) =&gt; {
    console.log(err.message);
  });</p>
<pre><code>- 사용 예시
```javascript
const url = &quot;https://jsonplaceholder.typicode.com/todos&quot;;

// axios 요청 로직
axios
  .get(url)
  .then((response) =&gt; console.log(response.data))
    .catch((err) =&gt; {

        // 오류 객체 내의 response가 존재한다 = 서버가 오류 응답을 주었다    
        if (err.response) {

        const { status, config } = err.response;

            // 없는 페이지
        if (status === 404) {
          console.log(`${config.url} not found`);
        }

            // 서버 오류
        if (status === 500) {
          console.log(&quot;Server error&quot;);
        }

        // 요청이 이루어졌으나 서버에서 응답이 없었을 경우
      } else if (err.request) {
        console.log(&quot;Error&quot;, err.message);
        // 그 외 다른 에러
      } else {
        console.log(&quot;Error&quot;, err.message);
      }
    });</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[axios-post,delete,fetch]]></title>
            <link>https://velog.io/@p_seo_hn/axios-postdeletefetch</link>
            <guid>https://velog.io/@p_seo_hn/axios-postdeletefetch</guid>
            <pubDate>Wed, 13 Sep 2023 17:17:49 GMT</pubDate>
            <description><![CDATA[<h1 id="🫧화면-구성">🫧화면 구성</h1>
<p>📁 App.jsx</p>
<pre><code class="language-javascript">import { useEffect, useState } from &quot;react&quot;;
import &quot;./App.css&quot;;
import axios from &quot;axios&quot;;

function App() {
  const [todos, setTodos] = useState(null);

  const fetchTodos = async () =&gt; {
    const { data } = await axios.get(&quot;http://localhost:4000/todos&quot;);
    setTodos(data);
  };

  useEffect(() =&gt; {
    // db로부터 값을 가져올 것이다
    fetchTodos();
  }, []);

  return (
    &lt;&gt;
      &lt;div&gt;
        {/* input 영역 */}
        &lt;form&gt;
          &lt;input type=&quot;text&quot; /&gt;
          &lt;button&gt;추가&lt;/button&gt;
        &lt;/form&gt;
      &lt;/div&gt;

      &lt;div&gt;
        {/* 데이터 영역 */}
        {todos ? (
          todos.map((item) =&gt; (
            &lt;div key={item.id}&gt;
              {item.id} : {item.title}
            &lt;/div&gt;
          ))
        ) : (
          &lt;p&gt;Loading...&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default App;</code></pre>
<p><img src="https://velog.velcdn.com/images/p_seo_hn/post/f11ac38e-f485-4958-8a1f-42e1b9fe5c33/image.png" alt=""></p>
<br>

<h1 id="🫧추가-삭제-수정-기능-구현">🫧추가, 삭제, 수정 기능 구현</h1>
<p>📁 App.jsx</p>
<pre><code class="language-javascript">import { useEffect, useState } from &quot;react&quot;;
import &quot;./App.css&quot;;
import axios from &quot;axios&quot;;

function App() {
  const [todos, setTodos] = useState(null);
  const [inputValue, setInputValue] = useState({
    title: &quot;&quot;,
  });
  const [targetId, setTargetId] = useState(&quot;&quot;);
  const [contents, setContents] = useState(&quot;&quot;);

  // 조회 함수
  const fetchTodos = async () =&gt; {
    const { data } = await axios.get(&quot;http://localhost:4000/todos&quot;);
    setTodos(data);
  };

  // 추가 함수
  const onSubmitHandler = async () =&gt; {
    axios.post(&quot;http://localhost:4000/todos&quot;, inputValue);
    // setTodos([...todos, inputValue]); // 화면에 id값이 바로 뜨지 않는다.
    fetchTodos(); // DB를 다시 읽어온다.
    setInputValue({ title: &quot;&quot; }); 
  };

  // 삭제 함수
  const onDeleteButtonClickHandler = async (id) =&gt; {
    axios.delete(`http://localhost:4000/todos/${id}`);
    setTodos(
      todos.filter((item) =&gt; {
        return item.id !== id;
      })
    );
  };

  //수정 함수
  const onUpdateButtonClickHandler = async () =&gt; {
    axios.patch(`http://localhost:4000/todos/${targetId}`, {
      title: contents,
    });

    setTodos(
      todos.map((item) =&gt; {
        if (item.id == targetId) {
          return { ...item, title: contents };
        } else {
          return item;
        }
      })
    );
  };

  useEffect(() =&gt; {
    // db로부터 값을 가져올 것이다
    fetchTodos();
  }, []);

  return (
    &lt;&gt;
      &lt;div&gt;
        {/* 수정 영역 */}
        &lt;div&gt;
          &lt;input
            type=&quot;text&quot;
            placeholder=&quot;수정할 아이디&quot;
            value={targetId}
            onChange={(e) =&gt; {
              setTargetId(e.target.value);
            }}
          /&gt;
          &lt;input
            type=&quot;text&quot;
            placeholder=&quot;수정할 내용&quot;
            value={contents}
            onChange={(e) =&gt; {
              setContents(e.target.value);
            }}
          /&gt;
          &lt;button onClick={onUpdateButtonClickHandler}&gt;수정&lt;/button&gt;
          &lt;br /&gt;
          &lt;br /&gt;
          &lt;br /&gt;
        &lt;/div&gt;

        {/* input 영역 */}
        &lt;form
          onSubmit={(e) =&gt; {
            e.preventDefault(); // 버튼을 눌렀을 때 새로고침을 막는다.

            // 버튼 클릭 시 , input에 들어있는 값(state)을 이용하여 DB에 저장(post요청)
            onSubmitHandler();
          }}
        &gt;
          &lt;input
            type=&quot;text&quot;
            value={inputValue.title}
            onChange={(e) =&gt; {
              setInputValue({
                title: e.target.value,
              });
            }}
          /&gt;
          &lt;button type=&quot;submit&quot;&gt;추가&lt;/button&gt;
        &lt;/form&gt;
      &lt;/div&gt;

      &lt;div&gt;
        {/* 데이터 영역 */}
        {todos ? (
          todos.map((item) =&gt; (
            &lt;div key={item.id}&gt;
              {item.id} : {item.title}
              &amp;nbsp;&amp;nbsp;&amp;nbsp;
              &lt;button onClick={() =&gt; onDeleteButtonClickHandler(item.id)}&gt;
                삭제
              &lt;/button&gt;
            &lt;/div&gt;
          ))
        ) : (
          &lt;p&gt;Loading...&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/&gt;
  );
}

export default App;
</code></pre>
<br>
]]></description>
        </item>
        <item>
            <title><![CDATA[tailwind]]></title>
            <link>https://velog.io/@p_seo_hn/tailwind</link>
            <guid>https://velog.io/@p_seo_hn/tailwind</guid>
            <pubDate>Tue, 12 Sep 2023 12:11:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>텍스트 관련 클래스</p>
</blockquote>
<ul>
<li>text-{색상}: 텍스트 색상 변경 (예: text-red-500).</li>
<li>text-{크기}: 텍스트 크기 변경 (예: text-lg).</li>
<li>font-{굵기}: 글꼴 굵기 변경 (예: font-bold).</li>
</ul>
<br>

<blockquote>
<p>배경 관련 클래스</p>
</blockquote>
<ul>
<li>bg-{색상}: 요소의 배경 색상 변경 (예: bg-blue-200).</li>
</ul>
<br>

<blockquote>
<p>패딩 및 마진 클래스:</p>
</blockquote>
<ul>
<li>p-{크기}: 패딩 설정 (예: p-4).</li>
<li>m-{크기}: 마진 설정 (예: m-2).</li>
</ul>
<br>

<blockquote>
<p>테두리 관련 클래스:</p>
</blockquote>
<ul>
<li>border: 요소에 테두리 추가.</li>
<li>border-{색상}: 테두리 색상 변경 (예: border-blue-500).</li>
</ul>
<br>

<blockquote>
<p>레이아웃 관련 클래스:</p>
</blockquote>
<ul>
<li>flex: 요소를 플렉스 컨테이너로 설정.</li>
<li>justify-{방향}: 주 축 방향 정렬 (예: justify-center).</li>
<li>items-{방향}: 교차 축 방향 정렬 (예: items-center).</li>
</ul>
<br>

<blockquote>
<p>폰트 아이콘 클래스:</p>
</blockquote>
<ul>
<li>icon-{아이콘명}: 폰트 아이콘 사용 (예: icon-heart).<br>

</li>
</ul>
<blockquote>
<p>반응형 클래스:</p>
</blockquote>
<ul>
<li>sm, md, lg, xl 등: 화면 크기에 따라 클래스를 적용하- 여 반응형 디자인을 구현할 수 있습니다 (예: lg:text-xl).</li>
</ul>
<br>
> 그리드 시스템 클래스:

<ul>
<li>grid: 그리드 컨테이너로 설정.</li>
<li>col-{숫자}: 열의 너비를 설정합니다 (예: col-6).</li>
</ul>
<br>

<blockquote>
<p>동적 클래스:</p>
</blockquote>
<ul>
<li>hover, focus, active 등: 요소에 호버 또는 포커스될 때 스타일을 변경할 수 있습니다.</li>
</ul>
<br>

<blockquote>
<p>애니메이션 클래스:</p>
</blockquote>
<ul>
<li>animate-{애니메이션명}: 애니메이션 효과를 추가할 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[5. 라우팅]]></title>
            <link>https://velog.io/@p_seo_hn/5.-%EB%9D%BC%EC%9A%B0%ED%8C%85</link>
            <guid>https://velog.io/@p_seo_hn/5.-%EB%9D%BC%EC%9A%B0%ED%8C%85</guid>
            <pubDate>Tue, 12 Sep 2023 11:42:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/p_seo_hn/post/67fd1e90-194d-4e42-a268-dfbb5c465d84/image.png" alt=""></p>
<ol>
<li><code>app / create / page.js</code> 폴더, 파일 생성
📁app / create / page.js<pre><code class="language-javascript">export default function Create() {
return &lt;&gt;Create&lt;/&gt;;
}</code></pre>
<img src="https://velog.velcdn.com/images/p_seo_hn/post/0dfc2790-04e6-4619-87bd-82009eb35763/image.png" alt=""></li>
</ol>
]]></description>
        </item>
    </channel>
</rss>