<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>devlog</title>
        <link>https://velog.io/</link>
        <description>frontend developer 📚</description>
        <lastBuildDate>Thu, 25 May 2023 07:23:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>devlog</title>
            <url>https://velog.velcdn.com/images/roses16-dev/profile/b6f5eca9-fe93-4a0e-a6df-5d5829720b9a/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. devlog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/roses16-dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[programmers] 12985. 예상 대진표
]]></title>
            <link>https://velog.io/@roses16-dev/programmers-12985.-%EC%98%88%EC%83%81-%EB%8C%80%EC%A7%84%ED%91%9C</link>
            <guid>https://velog.io/@roses16-dev/programmers-12985.-%EC%98%88%EC%83%81-%EB%8C%80%EC%A7%84%ED%91%9C</guid>
            <pubDate>Thu, 25 May 2023 07:23:35 GMT</pubDate>
            <description><![CDATA[<p>게임에서 승리할 경우 대진번호는 <code>(a + 1) // 2</code>의 값으로 변경되며 a와 b가 만나는 승리했을 경우의 대진번호가 같다. 
이를 그대로 코드로 정리하면 아래와 같이 작성할 수 있다.</p>
<pre><code class="language-python">def solution(n,a,b):
    answer = 0

    while a != b:       
        a = (a + 1) // 2
        b = (b + 1) // 2
        answer += 1

    return answer</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입 별칭 & Interface]]></title>
            <link>https://velog.io/@roses16-dev/TypeScript-Type-Interface</link>
            <guid>https://velog.io/@roses16-dev/TypeScript-Type-Interface</guid>
            <pubDate>Wed, 26 Apr 2023 13:09:52 GMT</pubDate>
            <description><![CDATA[<h3 id="타입-별칭type-aliases">타입 별칭(Type Aliases)</h3>
<p>변수 타입의 이름을 생성한다. 새로운 변수타입을 생성하는 것이 아닌 지정할 수 있는 <strong>이름</strong>을 생성한다.</p>
<pre><code class="language-ts">type Name = string;            // 선언
let student: Name = &quot;Kim&quot;;    // 사용
</code></pre>
<p>제네릭, 교차 타입과 함께 사용하여 아래와 같은 LinkedList 형태를 만들 수 있다.</p>
<pre><code class="language-ts">type LinkedList&lt;T&gt; = T &amp; { next: LinkedList&lt;T&gt; };

interface Data {
    name: string;
}

let people: LinkedList&lt;Data&gt;;
let s = people.name;
let s = people.next.name;
let s = people.next.next.name;</code></pre>
<hr>
<h3 id="interface">Interface</h3>
<p>변수 타입을 정의하는 데에 사용하는 구문. 프로젝트 내/외부에서 사용하는 코드의 룰을 정의하는데 유용하다.</p>
<ul>
<li>선언<pre><code class="language-ts">interface LabeledValue {
  label: string;
  size: number;
}</code></pre>
</li>
<li>사용
변수 및 함수 선언 등 데이터 타입 지정이 필요한 경우 동일하게 사용할 수 있다.<pre><code class="language-ts">let label: LabeledValue;
function printLabel(labelObj: LabeledValue){
 // ...
}</code></pre>
</li>
</ul>
<h4 id="선택적-프로퍼티optional-properties">선택적 프로퍼티(Optional Properties)</h4>
<p>Interface에서 Key이름에 붙여 사용한다. 해당 프로퍼티의 할당이 선택적임을 말한다.</p>
<pre><code class="language-ts">let obj: { name:string, age?:number } = { name:&#39;A&#39;}; // 성공</code></pre>
<h4 id="읽기-전용-프로퍼티readonly-properties">읽기 전용 프로퍼티(Readonly properties)</h4>
<p><code>readonly</code> 구문을 이용하여 생성한다. 객체가 처음 생성된 이후 수정할 수 없다.</p>
<pre><code class="language-ts">interface Point {
    readonly x: number;
    readonly y: number;
}

let p: Point = {x: 1, y: 2};
p.x = 2; // Error</code></pre>
<p>※ <code>ReadOnlyArray&lt;T&gt;</code> 타입을 통해 생성 후 변경이 불가한 배열을 생성할 수 있다. <code>ReadOnlyArray&lt;T&gt;</code>는 <code>Array&lt;T&gt;</code> 타입과 다른 타입으로 인식하므로 대입이 필요한 경우 타입 단언으로 오버라이드하여 사용한다.</p>
<h4 id="초과-프로퍼티-검사excess-property-checks">초과 프로퍼티 검사(Excess Property Checks)</h4>
<p>선택적 프로퍼티를 이용한 interface는 초과 프로퍼티가 검사된다. 이는 &quot;대상 타입 (target type)&quot;이 갖고 있지 않은 프로퍼티를 갖고 있을 경우 에러를 발생시킨다.</p>
<pre><code class="language-ts">interface LabelValue {
  name?: string;
  size?: number;
}

let myLabel: LabelValue = { name: &quot;Devlog&quot; };
let myLabel: LabelValue = { name: &quot;Devlog&quot;, width: 10}; // Error</code></pre>
<h4 id="함수-타입function-types">함수 타입(Function Types)</h4>
<p>함수 매개변수와 반환값의 타입을 지정할 수 있다.</p>
<ul>
<li><p>선언</p>
<pre><code class="language-ts">interface SearchFunc {
   (source: string, subString: string): boolean;
}</code></pre>
<p><code>(source: string, subString: string)</code> : 매개변수 이름과 타입
<code>: boolean</code> : 반환값 타입</p>
</li>
<li><p>사용</p>
<pre><code class="language-ts">let func: SearchFunc;
func = function(src, sub) {
// ...
return false;
}</code></pre>
<p>매개변수는 같은 위치에 대응되는 값을 검사한다. 때문에 위와 같이 타입을 지정하지 않을 수 있다.</p>
</li>
</ul>
<h4 id="인덱서블-타입indexable-types">인덱서블 타입(Indexable Types)</h4>
<p>Key와 Value로 이루어진 프로퍼티에서 Key의 데이터 타입에 따른 Value의 데이터 타입을 지정할 수 있다.</p>
<pre><code class="language-ts">interface StudentValue {
  name: string;
  [index: number]: string;    // Indexable type
}

let student: StudentValue = {
  name: &quot;Kim&quot;,
  1: &quot;A&quot;                    // Indexable type
};</code></pre>
<hr>
<h3 id="타입-별칭type-aliases과-interface-비교">타입 별칭(Type Aliases)과 Interface 비교</h3>
<ul>
<li>확장성
같은 이름의 Interface를 여러번 선언하면 자동으로 병합된다. 반면 타입 별칭은 재선언이 불가하다.</li>
<li>결합 가능성
Interface는 <code>extends</code> 구문을 통해 확장이 가능하다.</li>
<li>구현 가능성
interface는 클래스나 객체의 구현을 위한 목적으로 사용될 수 있다. 반면 타입 별칭은 보다 일반적인 타입 정의를 위해 사용된다.</li>
<li>유니온 타입과 인터섹션 타입
interface는 인터섹션 타입 <code>&amp;</code>의 사용이 가능하다. 타입 별칭은 유니온 타입<code>|</code>과 인터섹션 타입<code>&amp;</code> 모두 사용이 가능하다.</li>
</ul>
<hr>
<blockquote>
<p><del>내용만 정리해 둔 메모장이라 프로젝트에서 실사용하며 수정될 가능성 있음.</del></p>
</blockquote>
<hr>
<p><strong>📌 출처</strong></p>
<ul>
<li><a href="https://typescript-kr.github.io/">https://typescript-kr.github.io/</a></li>
<li><a href="https://youtu.be/OIMPLNICzoc">https://youtu.be/OIMPLNICzoc</a></li>
<li><a href="https://blog.naver.com/secondpage_of/223067201224">https://blog.naver.com/secondpage_of/223067201224</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] React18에서 달라진 내용]]></title>
            <link>https://velog.io/@roses16-dev/React-React18%EC%97%90%EC%84%9C%EB%8B%AC%EB%9D%BC%EC%A7%84%EC%A0%90</link>
            <guid>https://velog.io/@roses16-dev/React-React18%EC%97%90%EC%84%9C%EB%8B%AC%EB%9D%BC%EC%A7%84%EC%A0%90</guid>
            <pubDate>Wed, 19 Apr 2023 12:51:58 GMT</pubDate>
            <description><![CDATA[<h3 id="기능">기능</h3>
<ul>
<li><p>자동배치
기존 배치 기능은 Promise 내부의 업데이트, setTimeout, 기본 이벤트 핸들러 또는 기타 이벤트에서는 처리되지 않았으나, 이번 업데이트의 자동배치 기능을 통해 지원하게 되었다. 자동 배치를 사용하기 위해서는 컴포넌트 트리를 기존의 ReactDOM.render 함수 대신 새로운 ReactDOM.createRoot 함수를 사용해야 한다.</p>
</li>
<li><p>Transitions(전환)
전환은 긴급 업데이트와 긴급하지 않은 업데이트를 구분하기 위한 React의 새로운 개념이다. React 18 이전까지는 상태 업데이트를 긴급과 전환 업데이트로 명시하는 방법이 없이 모든 상태는 긴급 업데이트로 적용하기 때문에, setTimeout이나 throttle, debounce 등의 테크닉을 사용해 긴급 업데이트 방해를 우회하는 것이 최선이었다.
하지만, React 18부터는 startTransitionAPI를 제공함으로써 전환 업데이트를 명시적으로 구분하여 상태 업데이트를 진행할 수 있게 되었다.</p>
</li>
<li><p>서스펜스(Suspense)를 지원하는 새로운 서버 사이드 렌더링 아키텍처
React18에서는 새로운 서버 사이드 렌더링(이하 SSR) 아키텍처가 적용되었다. 새롭게 pipeToNodeWritable API가 추가 되었고, 이 API를 사용하면 SSR을 통해 를 사용할 수 있게 되었다.</p>
</li>
</ul>
<hr>
<h3 id="hooks">Hooks</h3>
<ul>
<li><p>useId
클라이언트와 서버간의 hydration의 mismatch를 피하면서 유니크 아이디를 생성할 수 있는 새로운 훅이다.</p>
</li>
<li><p>useTransition, startTransition
일부 상태 업데이트를 긴급하지 않은 것(not urgent)로 표시할 수 있다. 이 것으로 표시되지 않은 상태 업데이트는 긴급 업데이트로 간주한다.</p>
</li>
<li><p>useDeferredValue
급하지 않은 부분의 재렌더링을 지연할 수 있다. 이는 &#39;debounce&#39;와 비슷하지만, 몇 가지 더 장점이 있다. 고정된 지연 시간이 없으므로, 리액트는 첫 번째 렌더링이 반영되는 즉시 지연 렌더링을 시도한다. 이 지연된 렌더링은 인터럽트가 가능하며, 사용자 입력을 차단하지 않는다.</p>
</li>
<li><p>useSyncExternalStore
스토어에 대한 업데이트를 강제로 동기화하여 외부 스토어가 concurrent read를 지원할 수 있도록하는 새로운 훅이다. 외부 데이터의 원본에 대한 subscript를 필요로 할 때 더 이상 &#39;useEffet&#39;를 사용하지 않고, 이는 리액트 외부 상태와 통합되는 모든 라이브러리에 권장된다.</p>
</li>
<li><p>useInsertionEffect
css-in-js 라이브러리가 렌더링 도중에 스타일을 삽입할 때 성능 문제를 해결할 수 있는 새로운 훅이다.
이 훅은 DOM이 한번 mutate된 이후에 실행되지만, layout effect가 일어나기 전에 새 레이아웃을 한 번 읽는다. 이는 React 18 이전의 문제를 해결할 수 있으며, React 18에서는 나아가 concurrent 렌더링 중에 브라우저에 리액트가 값을 반환하므로, 레이아웃을 한번 더 계산할 수 있는 기회가 생겨 매우 중요하다.</p>
</li>
</ul>
<hr>
<p>*<em>📌 참조 *</em></p>
<ul>
<li><a href="https://github.com/facebook/react/releases">https://github.com/facebook/react/releases</a></li>
<li><a href="https://velog.io/@woodong/React-18-%EC%A3%BC%EC%9A%94-%EB%B3%80%EA%B2%BD%EC%A0%90">https://velog.io/@woodong/React-18-주요-변경점</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Firebase auth 서비스를 이용하여 회원가입/로그인 구현하기]]></title>
            <link>https://velog.io/@roses16-dev/React-Firebase-web</link>
            <guid>https://velog.io/@roses16-dev/React-Firebase-web</guid>
            <pubDate>Mon, 17 Apr 2023 12:23:12 GMT</pubDate>
            <description><![CDATA[<h3 id="firebase">Firebase</h3>
<p>📌 <a href="https://firebase.google.com/">https://firebase.google.com/</a></p>
<p>Firebase는 모바일 및 웹 어플리케이션을 만들기 위한 여러 기능을 지원하는 서비스이다. 주요 기능으로는 noSql 기반의 database, 회원가입/로그인 기능을 위한 Authentication 등이 있다. 
Back-end 코드 없이 1인 포트폴리오를 만들기 위해 사용하였으나 일반적으로 실제 서비스에서는 사용되지 않는다.</p>
<hr>
<h3 id="install--initialize">install &amp; initialize</h3>
<ol>
<li><p>Firebase 및 React 프로젝트를 생성한다.</p>
</li>
<li><p>Web, App, Flutter 등 프로젝트에 맞는 Firebase App을 생성한다.</p>
</li>
<li><p>React 내 Firebase를 설치한다.
<code>&lt;script&gt;</code> 태그로 사용할 수 있으나 연습 때에는 <code>yarn add firebase</code> 로 설치</p>
</li>
<li><p>Firebase App 생성 시 아래 코드와 같은 정보를 제공한다. 
React 내 해당 js파일을 작성한다.</p>
<pre><code class="language-js">// src/firebaseInstance.js
import { initializeApp } from &quot;firebase/app&quot;;

const firebaseConfig = {
 apiKey: &quot;&quot;,
 authDomain: &quot;&quot;,
 projectId: &quot;&quot;,
 storageBucket: &quot;&quot;,
 messagingSenderId: &quot;&quot;,
 appId: &quot;&quot;
};

const firebaseInstance = initializeApp(firebaseConfig);

export default firebaseInstance;</code></pre>
</li>
</ol>
<ol start="5">
<li><code>src/index.js</code> 파일에 import 한다.</li>
</ol>
<hr>
<h3 id="auth-interface">Auth Interface</h3>
<p>Firebase Auth 서비스를 사용할 수 있게 하는 인터페이스.
현재 인증된 유저 정보 접근, 유저 정보 업데이트 등 인증과 관련된 작업이 가능하다.</p>
<h4 id="--firebase-service-setup">- Firebase service setup</h4>
<ol>
<li>생성된 Firebase App 내 &#39;Authentication&#39; 메뉴에서 해당 서비스의 사용 여부를 설정한다.</li>
<li>&#39;Sign-in-method&#39; 메뉴에서 사용할 인증 방식을 선택한다.</li>
</ol>
<h4 id="--react에서-사용하기">- React에서 사용하기</h4>
<blockquote>
<p>instance와 method
📌 <a href="https://firebase.google.com/docs/reference/js/auth.auth">https://firebase.google.com/docs/reference/js/auth.auth</a></p>
</blockquote>
<ul>
<li>Interface 생성
<code>getAuth()</code> 함수를 통해 Auth 인터페이스를 생성한다.<pre><code class="language-js">// src/firebaseInstance.js
import { getAuth } from &quot;firebase/auth&quot;;
// ...
// firebase initialize
// ...
export const authService = getAuth(firebaseInstance);</code></pre>
</li>
</ul>
<h4 id="--sign-up-sign-in">- sign up, sign in</h4>
<p>아래 예시의 method는 E-mail&amp;Password 방식이다. Firebase에서 선택한 auth service 종류에 따라 method가 다르다. promise객체를 반환하는 비동기 method이다.</p>
<ul>
<li><p><code>createUserWithEmailAndPassword()</code>
sign up에 사용하는 method</p>
<pre><code class="language-js">// firebaseInstance.js
import { createUserWithEmailAndPassword } from &quot;firebase/auth&quot;;

export function createUser(email, password){
return createUserWithEmailAndPassword(authService, email, password);
}</code></pre>
</li>
<li><p><code>signInWithEmailAndPassword()</code>
sign in에 사용하는 method</p>
<pre><code class="language-js">import { signInWithEmailAndPassword } from &quot;firebase/auth&quot;;

export function signInUser(email, password){
return signInWithEmailAndPassword(authService, email, password);
}</code></pre>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 기초 문법 : 자료형]]></title>
            <link>https://velog.io/@roses16-dev/TypeScript-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-%EB%A9%94%EB%AA%A8%EC%9E%A5</link>
            <guid>https://velog.io/@roses16-dev/TypeScript-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-%EB%A9%94%EB%AA%A8%EC%9E%A5</guid>
            <pubDate>Wed, 12 Apr 2023 06:18:56 GMT</pubDate>
            <description><![CDATA[<h3 id="자료형">자료형</h3>
<p>데이터 타입을 동적으로 할당하는 JavaScript와 다르게 TypeScript는 선언 시 데이터의 타입을 지정해야한다. 지원하는 데이터 타입은 Javascript와 거의 동일하다.</p>
<ul>
<li><p>Boolean</p>
<pre><code class="language-ts">let isDone: boolean = false;</code></pre>
</li>
<li><p>Number
부동 소수 값. 16진수, 10진수 리터럴에 더불어, ECMAScript 2015에 소개된 2진수, 8진수 리터럴도 지원한다.</p>
<pre><code class="language-ts">let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744; </code></pre>
</li>
<li><p>String
JavaScript의 템플릿 문자열도 지원한다.</p>
<pre><code class="language-ts">let name: string = &#39;kim&#39;;
name = &quot;kim&quot;;</code></pre>
</li>
<li><p>Array
아래 두가지 선언 방식 모두 사용할 수 있다.</p>
<pre><code class="language-ts">let arr1: number[] = [1, 2, 3];
let arr2: Array&lt;number&gt; = [1, 2, 3];</code></pre>
</li>
<li><p>Tuple
요소의 타입과 개수가 고정된 배열을 표현할 때 사용한다.</p>
<pre><code class="language-ts">let tpl: [string, number, number];
tpl = [&quot;kim&quot;, 1, 2]; // 성공
tpl = [1, 2, &quot;kim&quot;]; // 오류
console.log(tpl[3]); // 오류</code></pre>
</li>
<li><p>Enum</p>
<pre><code class="language-ts">enum Stage {Start, Vote, End}
let eStageStatus: Stage = Stage.Start;
eStageStatus = Stage[1];    // Stage[1]의 이름인 &#39;Vote&#39;가 대입된다.</code></pre>
<p>각 요소는 숫자 0부터 순서대로 매치되나 아래와 같이 번호를 수동으로 매치할 수 있다.</p>
<pre><code class="language-ts">enum Stage {Start=1, Vote, End} // 1부터 순서대로 매치
enum Color {Red=1, Blue=3, Green=6}</code></pre>
</li>
<li><p>Any
타입 검사를 생략하는 타입으로 타입이 명확하지 않을 때 사용한다.</p>
<pre><code class="language-ts">let notSure: any = 4;
notSure = &quot;maybe a string instead&quot;;
notSure = false; // 성공</code></pre>
</li>
<li><p>Void
타입이 존재하지 않음을 나타낼 때 사용하며 null과 undefined만 할당할 수 있다. 일반적으로 Return이 없는 함수 선언에 사용된다.</p>
<pre><code class="language-ts">function func(): void {
  console.log(&quot;Hello World!&quot;);
}</code></pre>
</li>
<li><p>Null and Undefined
JavaScript에서의 사용과 같다. 기본적으로 모든 타입에도 대입될 수 있으나 <code>--strictNullChecks</code>를 사용한 경우 any와 각자의 타입(<code>null</code>, <code>undefined</code>)에서만 할당이 가능하다. ※예외, undefined는 void에도 할당이 가능하다.</p>
</li>
<li><p>Never
절대 발생할 수 없는 타입을 나타낸다. 모든 타입에 할당이 가능한 하위 타입이다. 함수 표현식에서 항상 오류를 발생시키거나, 절대 반환하지 않는 반환타입으로 사용된다. 
<del>(void와 유사하나 조금 더 강제성이 있다는 의미인 것 같다.)</del></p>
</li>
<li><p>Object
원시타입을 제외한 나머지 타입을 말한다.</p>
<pre><code class="language-ts">function func(obj: object): void;
func({ prop: 0 }); // 성공
func(42); // 오류
func(&quot;string&quot;); // 오류
func(false); // 오류
func(undefined); // 오류</code></pre>
</li>
</ul>
<hr>
<h3 id="유니언-타입discriminating-unions">유니언 타입(Discriminating Unions)</h3>
<p><code>|</code> 연산자를 사용하여 여러 데이터 타입 중 하나를 갖는 데이터 타입을 표현한다.</p>
<pre><code class="language-ts">let nickname: string|number;</code></pre>
<hr>
<h3 id="타입-단언type-assertions">타입 단언(Type assertions)</h3>
<p>형변환과 유사한 기능이지만 특별히 검사를 하거나 데이터를 재구성하지 않는다.</p>
<ul>
<li>&quot;angle-bracket&quot; 문법<pre><code class="language-ts">let someValue: any = &quot;this is a string&quot;;
let strLength: number = (&lt;string&gt;someValue).length;</code></pre>
</li>
<li>as-문법<pre><code class="language-ts">let someValue: any = &quot;this is a string&quot;;
let strLength: number = (someValue as string).length;</code></pre>
TypeScript를 JSX와 함께 사용할 때는, as-스타일의 단언만 허용된다.</li>
</ul>
<hr>
<p><strong>📌 출처</strong></p>
<ul>
<li><a href="https://typescript-kr.github.io/">https://typescript-kr.github.io/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] createRoot()와 render() ]]></title>
            <link>https://velog.io/@roses16-dev/React-Render</link>
            <guid>https://velog.io/@roses16-dev/React-Render</guid>
            <pubDate>Mon, 03 Apr 2023 13:50:17 GMT</pubDate>
            <description><![CDATA[<p>이번 포스트에서는 React Rendering에 대한 내용을 코드를 보며 이야기한다. </p>
<hr>
<h3 id="createroot">createRoot()</h3>
<pre><code class="language-jsx">const reactDOMroot = createRoot(container[, options]);
reactDOMroot.render(&lt;App /&gt;);</code></pre>
<p><code>createRoot()</code>함수는 주어진 container에 대해 React Root를 만들고 해당 Root를 반환한다. 반환된 Root의 <code>render()</code> 함수를 통해 React Element를 DOM으로 렌더링 할 수 있다.</p>
<p><code>options</code>에는 2가지 매개변수를 사용할 수 있다.</p>
<ul>
<li><code>onRecoverableError: &lt;FUNCTION&gt;</code> : 렌더링 중 오류가 발생한 경우 호출하는 함수를 설정한다.</li>
<li><code>identifierPrefix: &lt;STRING&gt;</code> : Default로 <code>React.useId</code>에 의해 생성된 ID를 사용하는데, 생성된 ID 앞에 설정된 <code>&lt;STRING&gt;</code>을 덧붙여준다. 동일 페이지에 여러 루트를 사용할 때 발생할 수 있는 충돌을 회피하는데 유용하다.</li>
</ul>
<p>생성된 Root는 <code>unmount()</code>로 해제할 수 있다.</p>
<hr>
<h3 id="fiberwork-📌">Fiber(work) <a href="https://github.com/acdlite/react-fiber-architecture">📌</a></h3>
<p>React Rendering/Update의 가장 작은 단위.
효율적인 업데이트를 위해 아래와 같은 조건을 갖는다.</p>
<ul>
<li>작업을 중지하고, 필요 시 다시 시작할 수 있어야 한다.</li>
<li>다양한 작업에 우선 순위를 부여할 수 있어야 한다.</li>
<li>이미 완료된 작업을 재사용 할 수 있어야 한다.</li>
<li>더 이상 필요 없게 된 작업을 중단할 수 있다.</li>
</ul>
<p>차일드, 시블링(자매), 리턴(부모)
(트리탐색방식 중 왼쪽부터 탐색하는 방식</p>
<hr>
<h3 id="render">render()</h3>
<p>렌더 함수는 아래 두가지 phase로 이루어진다.</p>
<ul>
<li>Render phase
업데이트를 수행하여 화면을 변경하는 것</li>
<li>Commit phase
변경된 화면을 실제 브라우저에 나타내는 것</li>
</ul>
<hr>
<p>*<em>📌 참조 *</em></p>
<ul>
<li><a href="https://ko.reactjs.org/">https://ko.reactjs.org/</a></li>
<li>강병진 강사님 강의</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 기초 문법 메모장]]></title>
            <link>https://velog.io/@roses16-dev/Python-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-%EB%A9%94%EB%AA%A8%EC%9E%A5</link>
            <guid>https://velog.io/@roses16-dev/Python-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95-%EB%A9%94%EB%AA%A8%EC%9E%A5</guid>
            <pubDate>Sun, 26 Mar 2023 04:28:52 GMT</pubDate>
            <description><![CDATA[<h3 id="참조할만한-사이트-링크">참조할만한 사이트 링크</h3>
<ul>
<li><a href="https://www.w3schools.com/python/">https://www.w3schools.com/python/</a></li>
</ul>
<hr>
<h3 id="출력">출력</h3>
<pre><code class="language-python">print(&#39;Hello World&#39;)</code></pre>
<h3 id="변수-선언-대입">변수 선언, 대입</h3>
<pre><code class="language-python">a = 1
b = True    # Boolean형은 첫자를 대문자로 기재한다.</code></pre>
<p>javascript와 같은 동적타입 언어로 선언 시 자료형을 명시하지 않는다.</p>
<h3 id="연산">연산</h3>
<pre><code class="language-python">a**b     # a^b</code></pre>
<p>사칙 연산과 나머지 연산은 생략한다.</p>
<h3 id="string">String</h3>
<pre><code class="language-python">name = &#39;kim&#39;+&#39;name&#39;    # kimname
a = 2+&#39;hello&#39;        # TypeError

text = &#39;abcdefghijk&#39;
len(text)            # 11        문자열 길이출력
text[:3]            # abc        index 3번까지 출력(3 미포함)
text[3:]            # defghijk    index 3번부터 출력
text[3:6]            # de         index 3번부터 6번까지 출력(6미포함)
text[:]                # 동일한 텍스트 복사

text.split(&#39;c&#39;)        # [&#39;ab&#39;, &#39;defghijk &#39;]</code></pre>
<h3 id="list">List</h3>
<pre><code class="language-python">a_list = [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;]
a_list[0]                    # &#39;A&#39;
a_list[1:2]                    # &#39;B&#39; index 1번부터 2번까지 출력(2 미포함)
len(a_list)                    # List의 길이 출력
a_list.append(&#39;D&#39;)            # List의 가장 마지막에 &#39;D&#39;추가
a_list.sort()                # 정렬
a_list.sort(reverse=True)    # 정렬 역순
result = (&#39;A&#39; in a_list)    # &#39;A&#39;가 a_list 내에 있는지를 Boolean값으로 반환</code></pre>
<h3 id="dictionaty">Dictionaty</h3>
<pre><code class="language-python">a_dict = {&#39;name&#39;:&#39;bob&#39;, &#39;age&#39;:10}
a_dict[&#39;height&#39;] = 170            # 값 추가
result = (&#39;height&#39; in a_dict)    # &#39;height&#39;가 a_dict 내에 있는지를 Boolean으로 반환</code></pre>
<h3 id="조건문">조건문</h3>
<pre><code class="language-python">if a &lt; 1000:
    print(&#39;1,000보다 작음&#39;)
elif a &lt; 2000:
    print(&#39;1,000보다 크고 2,000보다 작음&#39;)
else:
    print(&#39;2,000보다 큼&#39;)</code></pre>
<p>대부분의 언어는 일반적으로 <code>{}</code>를 사용하여 실행 구문을 구분하나, Python은 들여쓰기로 구분한다. </p>
<h3 id="반복문">반복문</h3>
<pre><code class="language-python">a_list = [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;]

for a in a_list:
    print(a)

for i, a in enumerate(a_list):
    print(i, a)        # i에 index를 출력한다.
    if(i &gt; 2):
        break;</code></pre>
<h3 id="함수">함수</h3>
<pre><code class="language-python">def hello(str=&#39;Stranger!&#39;):    # 함수 선언 Default 값 설정
    print(&#39;Hello&#39;)
    print(str)
    return &#39;Bye &#39;+str

result = hello(&#39;World!&#39;)    # Hello World!    함수 호출
print(result)                # Bye World!    리턴 값 출력

hello(str=&#39;World!&#39;)            # 매개변수 명을 지정하여 전달할 수 있다.</code></pre>
<h4 id="args-kwargs">args, kwargs</h4>
<pre><code class="language-python">def hello(*args)
    for e in args
        print(e)

# 매개변수를 갯수의 제한없는 list로 받을 때 사용한다.</code></pre>
<pre><code class="language-python">def hello(*kwargs)
    print(kwargs)

hello(name=&#39;Bob&#39;, age=25, weight=70)
# 매개변수를 dictionary로 받을 때 사용한다.</code></pre>
<h3 id="tuple">Tuple</h3>
<pre><code class="language-python">a_tuple = (&#39;A&#39;, &#39;B&#39;, &#39;C&#39;)

a_tuple[0] = &#39;Z&#39;        # TypeError</code></pre>
<p>List와 동일한 형태이나 값을 변경할 수 없다.</p>
<h3 id="set">Set</h3>
<pre><code class="language-python">a_list = [1, 2, 3, 4, 5, 1, 2, 3]
b_list = [4, 4, 5, 6, 7]

a_set = set(a_list)        # 1, 2, 3, 4, 5
b_set = set(b_list)        # 4, 5, 6, 7
# List를 통해 생성되며 중복을 제거한 값을 반환한다.

a_set &amp; b_set        # 교집합 4, 5
a_set | b_set        # 합집합 1, 2, 3, 4, 5, 6, 7
a_set - b_set        # 차집합 1, 2, 3
b_set - a_set        # 차집합 6, 7</code></pre>
<h3 id="f-string">f-string</h3>
<pre><code class="language-python">name = &#39;Bob&#39;
age = 18

print(f&#39;{name}은 {age}세 이다.&#39;)    # Bob은 18세이다.</code></pre>
<h3 id="예외처리-try-except-문">예외처리, try-except 문</h3>
<pre><code class="language-python">try:
    # 실행할 내용
except:
    # 위 try구문에서 Error 발생 시 실행할 내용</code></pre>
<h3 id="파일-불러오기">파일 불러오기</h3>
<pre><code class="language-python"># a_func.py
def say_hello():
    print(&#39;hello&#39;)</code></pre>
<pre><code class="language-python">from a_func import *    # 함수명으로 import도 가능하다. from a_func import say_hello 

say_hello()</code></pre>
<h3 id="삼항연산자">삼항연산자</h3>
<pre><code class="language-python">&#39;짝수&#39; if num % 2 == 0 else &#39;홀수&#39;</code></pre>
<p>True일 경우 값 <code>if</code> 조건문 <code>else</code> False일 경우 값</p>
<h3 id="한-줄-반복문">한 줄 반복문</h3>
<pre><code class="language-python">a_list = [1, 2, 3, 4, 5]
b_list = [a*2 for a in a_list]    # [2, 4, 6, 8, 10]</code></pre>
<h3 id="map">map</h3>
<pre><code class="language-python">list_people = [{&#39;name&#39;, &#39;bob&#39;, &#39;age&#39;: 25}, ...]

def check_adult(person):
    return &#39;성인&#39; if person[&#39;age&#39;] else &#39;청소년&#39;

result = map(check_adult, list_people)
print(list(result))    # [&#39;성인&#39;, ...]</code></pre>
<p><code>map(함수명, List명)</code> 의 형태로 작성한다.
list_people 내 각각의 요소를 check_adult의 매개변수 person에 대입한 값을 반환한다.</p>
<h3 id="filter">filter</h3>
<pre><code class="language-python">list_people = [{&#39;name&#39;, &#39;bob&#39;, &#39;age&#39;: 25}, ...]

def check_adult(person):
    return person[&#39;age&#39;] &gt; 20

result = filter(check_adult, list_people)
print(list(result))    # [{&#39;name&#39;, &#39;bob&#39;, &#39;age&#39;: 25}, ...]</code></pre>
<p><code>filter(함수명, List명)</code> 의 형태로 작성한다.
함수의 return값이 True인 요소만 반환한다.</p>
<pre><code class="language-python">result = filter(lambda x: x[&#39;age&#39;] &gt; 20, list_people)</code></pre>
<p>람다식을 사용할 때에는 관용적으로 매개변수 명을 x로 사용한다.</p>
<h3 id="lambda">lambda</h3>
<pre><code class="language-python">(lambda x, y: x + y)(10, 20)</code></pre>
<p>함수 선언을 단순화 하는 형태의 구문. <code>lambda 매개변수 : 표현식</code>  형태로 선언한다.</p>
<pre><code class="language-python">list_people = [{&#39;name&#39;, &#39;bob&#39;, &#39;age&#39;: 25}, ...]
result = map(lambda person: &#39;성인&#39; if person[&#39;age&#39;] else &#39;청소년&#39;, list_people)
# [&#39;성인&#39;, ...]</code></pre>
<p>위 map 예제를 위와 같이 작성할 수 있다.</p>
<h3 id="class">Class</h3>
<pre><code class="language-python">class Monster():    # 클래스 선언
    hp = 100

    def damage(self, attack):        # self, JavaScript의 this와 같은 역할
        self.hp = self.hp - attack

m = Monster()        # 인스턴스 생성
m2 = Monster()

m.damage(120)
m2.damage(90)</code></pre>
<hr>
<p>** 📌 출처 **</p>
<ul>
<li>Sparta coding club 강의</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[시간 복잡도와 공간 복잡도]]></title>
            <link>https://velog.io/@roses16-dev/%EC%8B%9C%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84%EC%99%80-%EA%B3%B5%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84</link>
            <guid>https://velog.io/@roses16-dev/%EC%8B%9C%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84%EC%99%80-%EA%B3%B5%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84</guid>
            <pubDate>Tue, 14 Mar 2023 18:16:12 GMT</pubDate>
            <description><![CDATA[<p>알고리즘의 성능을 판단하는 두 가지 기준을 말한다.</p>
<hr>
<h3 id="시간-복잡도-time-complexity">시간 복잡도 (Time Complexity)</h3>
<p>알고리즘을 수행하는데 이루어진 연산의 횟수이며 여기에서 연산의 종류는 산술, 대입, 비교, 이동을 말한다. </p>
<p>연산의 횟수는 변수의 갯수에 의존하여 결정된다. 때문에 아래 빅오 표기법과 같이 변수의 갯수에 따른 증가 추세를 나타내 보다 간편하게 표현한다.</p>
<ul>
<li><strong>빅오 표기법 (big-oh notation)Permalink</strong>
시간 복잡도 함수에서 불필요한 연산을 제거하여 보다 간편하게 시간/공간 복잡도를 표기하는 방법이다.
빅오 표기법은 정확한 연산의 갯수가 아니라 알고리즘의 일반적인 증가 추세를 표현한다. 알고리즘이 n에 정비례하여 실행 시간을 가질 경우 시간 복잡도가 O(n)이라 표시하고 ‘big-oh of n’이라고 읽는다.</li>
</ul>
<p>동일한 알고리즘이라도 입력되는 데이터에 따라 다른 실행시간을 보일 수 있다. 예를 들어 정렬 알고리즘의 경우 대부분 정렬되어있는 데이터와 그렇지 않은 데이터의 시간 복잡도가 크게 차이날 수 있다. 이 때 데이터의 집합에 따라 세가지 경우에 따라 나누어 평가한다.</p>
<ul>
<li>최선의 경우(Best Case) : 실행 시간이 가장 적은 경우를 말한다.</li>
<li>평균적인 경우(Average Case) : 모든 입력을 고려하고 각 입력이 발생하는 확률을 고려한 평균 수행 시간을 말한다.</li>
<li>최악의 경우(Worst case) : 알고리즘의 수행 시간이 가장 오래 걸리는 경우를 말한다.</li>
</ul>
<p>** 시간 복잡도를 계산할 때에는 최악의 경우를 주로 사용한다.**</p>
<hr>
<h3 id="공간-복잡도-space-complexity">공간 복잡도 (Space Complexity)</h3>
<p>프로그램의 실행~완료까지 필요로하는 자원 공간의 양을 말한다.</p>
<p>총 공간은 고정 요구 공간과 가변 요구 공간*의 합으로 나타낼 수 있다.</p>
<p>*가변 요구 공간 : 해결하려는 문제의 인스턴스에 의존하는 크기를 가진 공간. 즉, 동적으로 필요한 공간을 말한다.</p>
<hr>
<blockquote>
<p>좋은 알고리즘은 시간도 적게 걸리고 자원의 사용도 적어야 한다. 다만 시간과 공간은 반비례적인 경향이 있어 선택의 문제가 되는 경우도 있을 수 있다. 이 때 알고리즘의 척도는 시간 복잡도를 위주로 판단하는 편이다.</p>
</blockquote>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li><a href="https://madplay.github.io/post/time-complexity-space-complexity">https://madplay.github.io/post/time-complexity-space-complexity</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[NPM & yarn]]></title>
            <link>https://velog.io/@roses16-dev/NPM-yarn</link>
            <guid>https://velog.io/@roses16-dev/NPM-yarn</guid>
            <pubDate>Thu, 23 Feb 2023 08:01:31 GMT</pubDate>
            <description><![CDATA[<p>node로 프로젝트를 진행할 때 주로 사용되는 패키지 관리 툴.</p>
<ul>
<li>NPM(Node Package Manager)은 Node.js의 기본 패키지 관리 툴</li>
<li>yarn은 페이스북에서 개발한 패키지 관리 툴이다. npm에 비해 패키지 설치 속도가 빠르고 yarn.lock 파일을 통해 모든 디바이스에서 같은 패키지를 설치할 수 있도록 보장하므로 버전의 차이로 인해 발생하는 버그를 방지한다.</li>
</ul>
<hr>
<h3 id="명령어">명령어</h3>
<table>
<thead>
<tr>
<th align="left">npm</th>
<th align="left">yarn</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left">npm init</td>
<td align="left">yarn init</td>
<td align="left">초기화</td>
</tr>
<tr>
<td align="left">npm install</td>
<td align="left">yarn 또는 yarn install</td>
<td align="left">package.json의 패키지 설치</td>
</tr>
<tr>
<td align="left">npm install —save [package name]</td>
<td align="left">yarn add [package name]</td>
<td align="left">의존성으로 추가</td>
</tr>
<tr>
<td align="left">npm install —save-dev [package name]</td>
<td align="left">yarn add —dev [package name]</td>
<td align="left">개발 의존성으로 추가</td>
</tr>
<tr>
<td align="left">npm install —global [package name]</td>
<td align="left">yarn global add [package name]</td>
<td align="left">전역으로 추가</td>
</tr>
<tr>
<td align="left">npm update —save</td>
<td align="left">yarn upgrade</td>
<td align="left">패키지 업데이트</td>
</tr>
<tr>
<td align="left">npm run [스크립트명]</td>
<td align="left">yarn [스크립트명]</td>
<td align="left">package.json의 스크립트 명령 실행</td>
</tr>
<tr>
<td align="left">npm uninstall —save [package name]</td>
<td align="left">yarn remove [package name]</td>
<td align="left">패키지 삭제</td>
</tr>
<tr>
<td align="left">npm cache clean</td>
<td align="left">yarn cache clean</td>
<td align="left">캐시 삭제</td>
</tr>
<tr>
<td align="left">npm dedupe</td>
<td align="left">yarn dedupe</td>
<td align="left">중복 패키지 정리</td>
</tr>
</tbody></table>
<hr>
<h3 id="단축-플래그">단축 플래그</h3>
<table>
<thead>
<tr>
<th align="left">명령어</th>
<th align="left">단축 플래그</th>
<th align="left">의미</th>
</tr>
</thead>
<tbody><tr>
<td align="left">global</td>
<td align="left">-g</td>
<td align="left">전역 설치</td>
</tr>
<tr>
<td align="left">install</td>
<td align="left">i</td>
<td align="left">설치</td>
</tr>
<tr>
<td align="left">uninstall</td>
<td align="left">uni</td>
<td align="left">삭제</td>
</tr>
<tr>
<td align="left">—save-dev</td>
<td align="left">-D</td>
<td align="left">devDependencies 에 추가</td>
</tr>
<tr>
<td align="left">—save-exact</td>
<td align="left">-E</td>
<td align="left">^, ~대신 정확한 버전으로 설치</td>
</tr>
<tr>
<td align="left">—save-optional</td>
<td align="left">-O</td>
<td align="left">optionalDependencies에 추가 (선택정 의존성 모듈)</td>
</tr>
</tbody></table>
<hr>
<p>** 📌 출처 **</p>
<ul>
<li><a href="https://ui-tricks.netlify.app/posts/2020-03-10-npm-yarn/">https://ui-tricks.netlify.app/posts/2020-03-10-npm-yarn/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 설치 및 사용]]></title>
            <link>https://velog.io/@roses16-dev/TypeScript-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@roses16-dev/TypeScript-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Thu, 23 Feb 2023 07:47:26 GMT</pubDate>
            <description><![CDATA[<p>마이크로 소프트에서 개발/유지 중인 JavaScript 기반 언어.
JavaScript 보다 엄격한 문법과 자세한 Error message를 지원한다.</p>
<hr>
<h3 id="설치-및-사용">설치 및 사용</h3>
<h4 id="설치">설치</h4>
<p><code>npm install -g typescript</code>
※ node.js 최신버전 설치 필수</p>
<h4 id="파일-생성-및-사용">파일 생성 및 사용</h4>
<ul>
<li><p>확장자 <code>.ts</code>를 이용하여 생성한다.</p>
</li>
<li><p>브라우저는 TypeScript를 읽을 수 없으므로 브라우저로 읽히기 전 JavaScript로 컴파일 해야한다.
컴파일 명령어 : <code>tsc -w</code></p>
</li>
<li><p><code>.ts</code>파일과 같은 폴더 내에 <code>tsconfig.json</code>이라는 파일이 꼭 있어야한다. 
이는  ts를 js로 컴파일 할 때의 옵션을 명시해둔 파일이다.</p>
<pre><code class="language-json">{
    &quot;compilerOptions&quot;: {
      &quot;target&quot;: &quot;es5&quot;,
      &quot;module&quot;: &quot;commonjs&quot;,
    }
}</code></pre>
<ul>
<li><code>target</code> : ECMAScript 대상 버전 지정. 기본값은 &quot;ES3&quot;</li>
<li><code>module</code> : 모듈 코드 생성 지정. <code>None</code>, <code>CommonJS</code>, <code>AMD</code> 등</li>
</ul>
<p>그 외 옵션은 아래 출처 참조.</p>
</li>
</ul>
<hr>
<p>** 📌 출처 **</p>
<ul>
<li><a href="https://typescript-kr.github.io/">https://typescript-kr.github.io/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] A lock file already exists in the repository]]></title>
            <link>https://velog.io/@roses16-dev/Error-A-lock-file-already-exists-in-the-repository</link>
            <guid>https://velog.io/@roses16-dev/Error-A-lock-file-already-exists-in-the-repository</guid>
            <pubDate>Tue, 21 Feb 2023 09:04:21 GMT</pubDate>
            <description><![CDATA[<h3 id="⛔-error">⛔ Error</h3>
<pre><code>A lock file already exists in the repository, 
which blocks this operation from completing.</code></pre><p>Github에서 checkout, commit, push 등의 명령이 동작하지 않고 위와 같은 오류메세지가 출력된다.</p>
<hr>
<h3 id="✅-clear">✅ Clear</h3>
<p>GitHub 작업 중 충돌이 발생한 상태. 내 경우 GitHub desktop을 종료 후 재실행하니 정상화되었다. git bash를 사용중인 경우 충돌이 발생한 lock파일을 삭제하면 정상화된다고 한다.</p>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li><a href="https://greenhelix.tistory.com/137">https://greenhelix.tistory.com/137</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS/SCSS] sass 7-1 pattern]]></title>
            <link>https://velog.io/@roses16-dev/CSSSCSS-7-1-pattern</link>
            <guid>https://velog.io/@roses16-dev/CSSSCSS-7-1-pattern</guid>
            <pubDate>Thu, 16 Feb 2023 17:01:09 GMT</pubDate>
            <description><![CDATA[<p>7-1은 7개의 폴더와 1개의 파일을 말한다.</p>
<p>CSS전처리기를 통해 코드 베이스를 여러 파일로 분할하여 사용할 때 프로젝트에서 사용되는 다수의 스타일 파일을 7개의 폴더(abstracts, vendeors, base, layout, components, pages, themes)로 관리하고 이를 1개의 파일에 import하여 사용하는 방식이다.</p>
<p>각각의 폴더는 아래와 같은 내용을 담는다.</p>
<ul>
<li><p>abstracts
프로젝트 전체에서 사용하는 도구들을 담고 있다.
<code>_variables.scss</code>, <code>_mixins.scss</code>, <code>_functions.scss</code>, <code>_placeholders.scss</code> 등</p>
</li>
<li><p>vendors
외부 라이브러리 및 프레임워크의 CSS를 담는다. 외부 파일을 재정의해야하는 경우 vendors-extensions라는 폴더를 따로 생성하여 관리하는 것을 권장하고 있다.
<code>_bootstrap.scss</code>, <code>_jquery-ui.scss</code>, <code>_select2.scs</code></p>
</li>
<li><p>base
프로젝트의 전반적으로 사용될 디폴트 스타일, 폰트 등 공용 스타일을 담는다.
<code>_base.scss</code>, <code>_reset.scss</code>, <code>_typography.scss</code>, <code>_animations.scss</code></p>
</li>
<li><p>layout
사이트 구조/레이아웃을 담는다.
<code>_grid.scss</code>, <code>_header.scss</code>, <code>footer.scss</code>, <code>_sidebar.scss</code>, <code>_forms.scss</code></p>
</li>
<li><p>components
layout보다 작은 구성요소들을 담는다.
<code>_buttons.scss</code>, <code>_media.scss</code>, <code>_thumbnails.scss</code></p>
</li>
<li><p>pages
각 페이지 고유의 스타일을 담는다. 일반적으로 파일명은 페이지 이름과 동일하게 설정한다.
<code>_home.scss</code>, <code>_contact.scss</code></p>
</li>
<li><p>themes
테마를 설정할 수 있는 웹의 경우 테마와 관련된 스타일을 담는다.
<code>_theme.scss</code>, <code>_admin.scss</code></p>
</li>
</ul>
<p>위와같이 분류한 스타일 시트들은 1개의 파일에 모아 사용한다. 
일반적으로 <code>main.scss</code>의 파일명을 사용하는 편이나 변경해도 관계없다.
해당 파일은 아래 예시와 같이 단순히 import만을 담당하며, CSS는 순서에 의존하므로 아래와 같이 import의 순서를 통일하여 사용한다.</p>
<pre><code class="language-scss">// main.scss

@import
  &#39;abstracts/variables&#39;,
  &#39;abstracts/functions&#39;,
  &#39;abstracts/mixins&#39;,
  &#39;abstracts/placeholders&#39;;

@import
  &#39;vendors/bootstrap&#39;,
  &#39;vendors/jquery-ui&#39;;

@import
  &#39;base/reset&#39;,
  &#39;base/typography&#39;;

@import
  &#39;layout/navigation&#39;,
  &#39;layout/grid&#39;,
  &#39;layout/header&#39;,
  &#39;layout/footer&#39;,
  &#39;layout/sidebar&#39;,
  &#39;layout/forms&#39;;

@import
  &#39;components/buttons&#39;,
  &#39;components/carousel&#39;,
  &#39;components/cover&#39;,
  &#39;components/dropdown&#39;;

@import
  &#39;pages/home&#39;,
  &#39;pages/contact&#39;;

@import
  &#39;themes/theme&#39;,
  &#39;themes/admin&#39;;</code></pre>
<pre><code class="language-scss">// main.scss

@import &#39;abstracts/*&#39;;
@import &#39;vendors/*&#39;;
@import &#39;base/*&#39;;
@import &#39;layout/*&#39;;
@import &#39;components/*&#39;;
@import &#39;pages/*&#39;;
@import &#39;themes/*&#39;;</code></pre>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li><a href="https://sass-guidelin.es/#the-7-1-pattern">https://sass-guidelin.es/#the-7-1-pattern</a></li>
<li><a href="https://mine-it-record.tistory.com/594">https://mine-it-record.tistory.com/594</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Project] <라이어게임:비밀의문> 회고]]></title>
            <link>https://velog.io/@roses16-dev/Project-%EB%9D%BC%EC%9D%B4%EC%96%B4%EA%B2%8C%EC%9E%84%EB%B9%84%EB%B0%80%EC%9D%98%EB%AC%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@roses16-dev/Project-%EB%9D%BC%EC%9D%B4%EC%96%B4%EA%B2%8C%EC%9E%84%EB%B9%84%EB%B0%80%EC%9D%98%EB%AC%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Thu, 16 Feb 2023 16:23:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/roses16-dev/post/cc937eeb-f1ee-467e-9a28-ae78f7334185/image.png" alt=""></p>
<h3 id="💻-개요">💻 개요</h3>
<ul>
<li>개발 기간 : 2022.11.04~2022.12.16 ( 6주 )</li>
<li>사용 기술 : Javascript, React, Redux, SCSS, Axios, SockJS, Stomp, WebRTC, Open-vidu, AWS Amplify</li>
<li>발표 영상 : <a href="https://youtu.be/et2UZDITnOs">https://youtu.be/et2UZDITnOs</a></li>
</ul>
<hr>
<h3 id="📚-경험">📚 경험</h3>
<ul>
<li><strong>팀장</strong>으로써 전반적인 업무 리딩 및 회의 주도</li>
<li>시범 서비스를 통해 생성된 <strong>게임 방 669개, 회원 239명, 플레이된 게임 657판, 모든 유저 전체 플레이 약 30시간, 36건의 피드백 수집</strong> 및 반영/개선 경험</li>
<li>디자인 팀, 백엔드 팀과의 협업 경험</li>
<li>Github Issue, Projects, Pull requests 등 <strong>Issue tracker를 이용한 협업</strong> 경험</li>
<li>AWS Amplify를 이용한 자동배포<ul>
<li><strong>Git Actions</strong>를 이용한 자동배포도 경험하였으나 최종 사용되지않음</li>
</ul>
</li>
<li>라이어 게임 웹으로 구현<ul>
<li>SockJS와 Stomp를 이용한 <strong>소켓 통신</strong>으로 게임 룰 구현</li>
<li>WebRTC를 이용하여 <strong>화상 채팅 연결</strong> 및 게임 룰에 따른 Device 제어 구현</li>
</ul>
</li>
<li>Sentry를 이용하여 user side error log 실시간 수집 및 개선</li>
</ul>
<hr>
<h3 id="💬-회고">💬 회고</h3>
<h4 id="좋았던-점">좋았던 점</h4>
<ul>
<li>공부를 시작하며 만난 Javascript와 React의 코드들은 대부분 멘토님들께서 프로젝트에 알맞은 형태로 준비해주신 예제 코드들 이었는데 webRTC와 WebSocket을 알아가며 Google과 Github 등에서 만난 코드는 새롭고 당황스럽고 많은 부분이 내 프로젝트와는 달라 짜집어 고쳐가며 만들어야 했다.
덕분에 앞으로 새로운 기능이 주어지더라도 배우면 할 수 있겠다. 라는 무던한 마음이 생겼다.</li>
<li>Game rule을 기대한만큼 구현하였다. 디테일에서 아쉬운 점이 많았지만 커다란 로직은 생각대로 작동해주어서 즐거웠다.</li>
<li>Git issue, projects, PR을 조금은 잘 썼던 프로젝트였다.</li>
</ul>
<h4 id="아쉬운-점">아쉬운 점</h4>
<ul>
<li>redux, redux-toolkit 등 배운 기능의 능숙한 사용을 보여 주지는 못한 기획이었다. </li>
<li>scss의 이점을 살릴 수 있는 구조가 아니었던 것 같다. 차후에는 scss 7-1 pattern을 활용해보고 싶다.</li>
<li>open-vidu에서 제공한 소스가 class component로 작성된 코드였는데 이를 100% 활용하지 못했다. 시간이 넉넉했다면 전체 코드를 function component로 만드는 작업을 더 시도해보았을 것 같다.</li>
<li>유저 사이드에서 발생한 모든 버그를 해결하지 못했다. 왜 문제가 발생했는지, 어떤 케이스에서 발생한 문제인지 자세히 알고 싶고, 어떤 예외처리를 추가했어야했는지는 아직도 고민이 된다.</li>
<li>Typescript를 써보고 싶었다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Project] <라이어게임:비밀의문> Game rule 구현하기]]></title>
            <link>https://velog.io/@roses16-dev/Project-%EB%9D%BC%EC%9D%B4%EC%96%B4%EA%B2%8C%EC%9E%84%EB%B9%84%EB%B0%80%EC%9D%98%EB%AC%B8-Game-rule-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@roses16-dev/Project-%EB%9D%BC%EC%9D%B4%EC%96%B4%EA%B2%8C%EC%9E%84%EB%B9%84%EB%B0%80%EC%9D%98%EB%AC%B8-Game-rule-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 16 Feb 2023 16:17:16 GMT</pubDate>
            <description><![CDATA[<p>JavaScript와 React, webSocket(sockjs, stomp)을 사용하여 라이어게임을 web으로 구현한 방식에 대한 간단한 설명.</p>
<p>이번 포스트는 제가 작성한 방식을 간단하게 설명하는 내용이며 더 좋은 다른 방식이 있을 수 있습니다. 😃
Git : <a href="https://github.com/HangHae-TheFinalProject/FrontEnd">https://github.com/HangHae-TheFinalProject/FrontEnd</a></p>
<hr>
<p>라이어 게임의 룰을 살펴보면 크게 몇 단계의 스테이지로 이루어져 있다는 걸 알 수 있다.</p>
<ul>
<li>각 유저에게 할당된 라이어여부/키워드를 공개하는 스테이지</li>
<li>각 유저마다 키워드에 대해 발표하는 스테이지</li>
<li>라이어로 예상되는 유저를 투표하는 스테이지</li>
<li>라이어로 지목된 유저가 정답을 맞추는 스테이지</li>
<li>승/패를 출력하는 스테이지</li>
</ul>
<p>이를 stageNumber라는 변수로 표현하여 게임 룰을 진행한다.
(+) : enum 문을 사용했다면 더 좋았을 것 같다.</p>
<p>일반적인 web은 user interaction에 따른 제어가 대부분이나, 실시간 다대다 통신을 지원하는 웹게임은 websocket으로 전송받는 server 응답에 따라 모든 유저의 stageNumber를 동시에 변경해야한다. </p>
<p>때문에 user interation 또는 timer를 통해 상태가 변경되어야 하는 경우 아래 예시와 같이 서버로 그 내용을 전송하며 stageNumber를 변경하여 게임을 진행하지는 않는다.</p>
<pre><code class="language-javascript">// lier를 투표한 경우 그 nickname을 서버로 보내는 역할을 하는 함수.
const vote = (nickname) =&gt; {
  if (!client.current.connected) return;

  client.current.publish({
    destination: `/pub/lier/game/${id}/vote`,
    body: JSON.stringify({
      value: nickname,
    }),
  });
};</code></pre>
<pre><code class="language-jsx">// 투표 화면 내 onClick 이벤트에 위 vote함수 연결
&lt;figure onClick={() =&gt; {vote(member);}}&gt;
  &lt;figcaption&gt;{member}&lt;/figcaption&gt;
&lt;/figure&gt;</code></pre>
<p>stageNumber는 아래 예시와 같이 서버에서 약속한 값이 전송해주었을 때 변경한다.
아래 예시의 <code>LIER</code> 케이스는 모든 유저가 투표를 마친 후 투표 결과가 라이어를 맞춘 경우 전송되는 값이다. </p>
<pre><code class="language-javascript">const subscribe = () =&gt; {
  client.current.subscribe(`/sub/gameroom/${id}`, ({ body }) =&gt; {
    const data = JSON.parse(body);
    switch (data.type) {
        case &#39;LIER&#39;:
          setStageNumber(7);
        break;
    }
  });
};</code></pre>
<hr>
<p>위 내용 및 예시는 최대한 간단하게 작성된 내용이며 실제로는 게임에 사용되는 다양한 변수들의 제어가 필요하여 코드가 꽤 길고 복잡해질 수 밖에 없었다.</p>
<p>다양한 형태의 변수를 보다 용이하게 제어하는데에 enum문을 사용했다면 좋을 것 같다.
또한 게임 내 사용되는 다수의 컴포넌트 내에 stageNumber가 사용되므로 enum문을 사용한다면 해당 enum문의 형태를 공용으로 관리하는 파일을 따로 두는 편이 좋았을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Github] Github action&AWS S3&Gabia domain을 이용한 자동배포]]></title>
            <link>https://velog.io/@roses16-dev/Github-Github-actionAWS-S3Gabia-domain%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%8F%99%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@roses16-dev/Github-Github-actionAWS-S3Gabia-domain%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%9E%90%EB%8F%99%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Thu, 16 Feb 2023 15:28:57 GMT</pubDate>
            <description><![CDATA[<p>11월 17일. 오늘의 배움 <del>(삽질)</del> 
오늘의 포스팅은 제가 성공한 방법에 대한 메모입니다. 비교적 자세한 설명이 부족할 수 있습니다. 😥
Gabia domain이 있고, AWS 계정이 있고, Github repo가 만들어져 있다는 걸 전제로 시작합니다. 
이 방식은 AWS S3 정적 호스팅을 이용한 방식이며 http를 지원합니다. https 배포가 필요하다면 &quot;AWS EC2 + ACM&quot; 또는 &quot;AWS Amplify&quot;를 이용해야합니다.</p>
<hr>
<h3 id="목차">목차</h3>
<ol>
<li>AWS &#39;Route 53&#39; 호스팅 영역 생성  &amp; Gabia DNS 변경</li>
<li>AWS S3 버킷 생성 및 권한/속성 변경</li>
<li>AWS &#39;IAM&#39; 사용자 추가</li>
<li>Git Action </li>
</ol>
<hr>
<h3 id="1-aws-route-53-호스팅-영역-생성---gabia-dns-변경">1. AWS &#39;Route 53&#39; 호스팅 영역 생성  &amp; Gabia DNS 변경</h3>
<p>​    AWS에서 외부 Domain을 사용하기 위해서는 AWS의 DNS 서비스인 &#39;Route 53&#39;에 등록이 필요하며, Route 53의 DNS서버를 Gabia DNS 서버를 대체하여 사용합니다.</p>
<ul>
<li>AWS &#39;Route 53&#39; &gt; &#39;호스팅 영역&#39; &gt; &#39;호스팅 영역 생성&#39;
<img src="https://velog.velcdn.com/images/roses16-dev/post/ae8c530d-0048-4edb-80fa-cc42b6b0f9b9/image.png" alt=""></li>
</ul>
<p>​    <code>domain_name.dev</code>는 사용할 Domain으로 변경</p>
<ul>
<li>생성된 호스팅 click &gt; &#39;레코드 생성&#39;
<img src="https://velog.velcdn.com/images/roses16-dev/post/f3f162e9-014b-4bac-a390-352e013df3ae/image.png" alt=""></li>
</ul>
<ul>
<li>호스팅 영역 세부 정보 내 &#39;NS&#39; 유형의 값/트래픽 라우팅 대상 컬럼의 값을 Gabia DNS 서버로 설정
<img src="https://velog.velcdn.com/images/roses16-dev/post/d7bab8f6-82ad-4222-b8c0-b8f9c1608e38/image.png" alt=""></li>
</ul>
<hr>
<h3 id="2-aws-s3-버킷-생성-및-권한속성-변경">2. AWS S3 버킷 생성 및 권한/속성 변경</h3>
<ul>
<li><p>AWS &#39;S3&#39; &gt; &#39;버킷 만들기&#39; &gt; 아래와 같이 설정 후 &#39;버킷 만들기&#39;
<img src="https://velog.velcdn.com/images/roses16-dev/post/ec87cd18-df1d-4151-89fc-f32ad3e06dfd/image.png" alt=""></p>
</li>
<li><p>AWS &#39;S3&#39; &gt; 생성한 버킷 click &gt; &#39;권한&#39; &gt; 버킷 정책 &gt; 편집</p>
<pre><code>{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Id&quot;: &quot;Policy1668671586744&quot;,
    &quot;Statement&quot;: [
        {
            &quot;Sid&quot;: &quot;AddPerm&quot;,
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Principal&quot;: &quot;*&quot;,
            &quot;Action&quot;: &quot;s3:GetObject&quot;,
            &quot;Resource&quot;: &quot;arn:aws:s3:::domain_name.dev/*&quot;
        }
    ]
}</code></pre></li>
<li><p>AWS &#39;S3&#39; &gt; 생성한 버킷 click &gt; &#39;속성&#39; &gt; &#39;정적 웹 사이트 호스팅 편집&#39; &gt; 활성화</p>
</li>
</ul>
<hr>
<h3 id="3-iam-사용자-추가">3. IAM 사용자 추가</h3>
<p>이미 같은 설정으로 생성된 사용자가 있다면 생략해도 됩니다.</p>
<ul>
<li><p>AWS &#39;IAM&#39; &gt; &#39;사용자&#39; &gt; &#39;사용자 추가&#39;</p>
<ul>
<li>AWS 자격 증명 유형 : &#39;액세스 키 - 프로그래밍 방식 액세스&#39; 체크</li>
<li>Permissions : &#39;AmazonS3FullAccess&#39;</li>
</ul>
</li>
<li><p>추가 시 받을 수 있는 &#39;액세스 키&#39;, &#39;비밀 액세스 키&#39; 메모 </p>
</li>
</ul>
<hr>
<h3 id="4-드디어-git-action">4. 드디어 Git Action</h3>
<ul>
<li><p>원격 repo &gt; Actions &gt; &#39;set up a workflow yourself&#39;</p>
<pre><code class="language-yaml">name: Node.js Package

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    env: 
      CI: false
    steps:
      - uses: actions/checkout@v3

      - name: Install dependencies
        run: yarn

      - name: Build
        run: yarn build

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}            # AWS 사용자 ACCESS KEY
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}    # AWS 사용자 SECRET ACCESS KEY
          aws-region: ap-southeast-2

      - name: Deploy static site to S3 bucket
        run: aws s3 sync ./build s3://${{ secrets.S3_BUCKET }} --delete    # AWS BUCKET NAME</code></pre>
<p>.yml 파일의 작성 방식 설명은 생략하겠습니다.</p>
</li>
<li><p>위 예제에서 사용된 action secret key 는 Git repo &gt; Settings &gt; Secrets 에서 등록할 수 있습니다!</p>
</li>
</ul>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li><a href="https://eundol1113.tistory.com/210">https://eundol1113.tistory.com/210</a></li>
<li><a href="https://medium.com/marlinelee2/react-amazon-s3%EB%A1%9C-%ED%98%B8%EC%8A%A4%ED%8C%85-417aa93cf469">https://medium.com/marlinelee2/react-amazon-s3%EB%A1%9C-%ED%98%B8%EC%8A%A4%ED%8C%85-417aa93cf469</a></li>
<li><a href="https://hannut91.github.io/blogs/route53/gabia">https://hannut91.github.io/blogs/route53/gabia</a></li>
<li><a href="https://grasinnong-developer.tistory.com/88">https://grasinnong-developer.tistory.com/88</a></li>
<li><a href="https://velog.io/@cptkuk91/AWS-S3Route53-%ED%98%B8%EC%8A%A4%ED%8C%85-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%97%B0%EA%B2%B0">https://velog.io/@cptkuk91/AWS-S3Route53-%ED%98%B8%EC%8A%A4%ED%8C%85-%EB%8F%84%EB%A9%94%EC%9D%B8-%EC%97%B0%EA%B2%B0</a></li>
<li><a href="https://react-etc.vlpt.us/08.deploy-s3.html">https://react-etc.vlpt.us/08.deploy-s3.html</a></li>
<li><a href="https://blog.naver.com/ipzzinn/222925361366">https://blog.naver.com/ipzzinn/222925361366</a></li>
<li><a href="https://satisfactoryplace.tistory.com/361">https://satisfactoryplace.tistory.com/361</a></li>
<li><a href="https://doqtqu.tistory.com/331">https://doqtqu.tistory.com/331</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] Mac auto import error]]></title>
            <link>https://velog.io/@roses16-dev/Error-Mac-AUto-import-Error</link>
            <guid>https://velog.io/@roses16-dev/Error-Mac-AUto-import-Error</guid>
            <pubDate>Thu, 16 Feb 2023 15:24:51 GMT</pubDate>
            <description><![CDATA[<h3 id="⛔-error">⛔ Error</h3>
<pre><code>ERROR in ./node_modules/hoist-non-react-statics/node_modules/react-is/index.js
Module build failed (from ./node_modules/source-map-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open &#39;/Users/h****e/Desktop/FrontEnd/node_modules/hoist-non-react-statics/node_modules/react-is/index.js&#39;
ERROR in ./node_modules/mime/lite.js
Module build failed (from ./node_modules/source-map-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open &#39;/Users/h****e/Desktop/FrontEnd/node_modules/mime/lite.js&#39;
ERROR in ./node_modules/uuid/dist/esm-browser/index.js
Module build failed (from ./node_modules/source-map-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open &#39;/Users/h****e/Desktop/FrontEnd/node_modules/uuid/dist/esm-browser/index.js&#39;</code></pre><p>  Mac에서만 발생했던 오류로 file or directory를 찾을 수 없다는 메세지가 나타나는데 실제로 해당 file/directory는 존재하지않고 따로 import를 설정해 두지도 않았다. </p>
<h3 id="✅-clear">✅ Clear</h3>
<p>  찾아보니 Mac에서는 종종 이상한 경로로 Auto import가 작동하는 일이 있다고한다. 출처에서는 다양한 해결 방법을 제시해주셨으나 우리 프로젝트에서는 터미널을 껐다 다시 켜는 것으로 해결되었다.</p>
<hr>
<p>*<em>📌 참조 *</em></p>
<ul>
<li><a href="https://dotorimook.github.io/post/2021-10-14-auto-import-error/">https://dotorimook.github.io/post/2021-10-14-auto-import-error/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Image 객체]]></title>
            <link>https://velog.io/@roses16-dev/JavaScript-Image-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@roses16-dev/JavaScript-Image-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Thu, 16 Feb 2023 15:22:06 GMT</pubDate>
            <description><![CDATA[<p>Image 객체는 해당 이미지에 대한 정보를 담고 있다.</p>
<hr>
<ul>
<li><p>객체 생성 및 이미지 경로 지정</p>
<pre><code class="language-javascript">const image = new Image();    
// image 객체 생성

image.src = &#39;../IMAGE_PATH&#39;    
// image 경로 설정</code></pre>
</li>
<li><p>property
<code>image.border</code> : 테두리 값
<code>image.complete</code> : 이미지의 load가 완료되었는지 여부(boolean)
<code>image.width</code> : 이미지 width(px)
<code>image.height</code> : 이미지 height(px)
<code>image.src</code> : 이미지 경로</p>
</li>
<li><p>Event handler
<code>onAbort</code> : 이미지 로딩이 중간에 멈춰진 경우
<code>onError</code> : 이미지 로딩 중 오류가 발생한 경우
<code>onLoad</code> : 이미지 로딩이 완료된 경우</p>
</li>
</ul>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li><a href="https://velog.io/@lllen/Image-%EA%B0%9D%EC%B2%B4">https://velog.io/@lllen/Image-%EA%B0%9D%EC%B2%B4</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS/SCSS] String 말 줄임 처리]]></title>
            <link>https://velog.io/@roses16-dev/CSSSCSS-String-%EB%A7%90-%EC%A4%84%EC%9E%84-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@roses16-dev/CSSSCSS-String-%EB%A7%90-%EC%A4%84%EC%9E%84-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Thu, 16 Feb 2023 15:13:42 GMT</pubDate>
            <description><![CDATA[<p>줄을 넘어가는 string을 표시할 때 끝 부분을 &#39; ... &#39; 으로 표시하는 말 줄임 처리를 할 수 있는 코드</p>
<pre><code class="language-CSS">p{
    white-space: nowrap;    
    overflow: hidden;
    text-overflow: ellipsis;
}</code></pre>
<ul>
<li><p><code>white-space: nowrap</code> 
<code>white-space</code>는 문자열 내 공백과 개행 문자의 처리, 설정된 블록의 범위를 벗어난 Text의 개행 여부를 설정한다.
<code>nowrap</code>은 2개 이상의 공백을 1개로 축소하고, 개행 문자를 무시하며, 범위를 벗어난 Text도 개행없이 출력한다.</p>
</li>
<li><p><code>overflow: hidden</code>
<code>overflow</code>는 설정된 블록의 범위를 벗어난 컨텐츠의 처리를 설정한다.
<code>hidden</code>은 범위를 벗어난 컨텐츠는 숨긴다.</p>
</li>
<li><p><code>text-overflow: ellipsis</code> 
<code>text-overflow</code>는 설정된 블록의 범위를 벗어난 문자열의 처리를 설정한다.
<code>ellipsis</code>는 문자열의 뒷 부분을 &#39;...&#39;으로 말 줄임 처리를 한다.
단독으로는 말줄임 처리를 할 수 없으며 <code>overflow: hidden</code>과 함께 사용하여야 정상적으로 동작한다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Redux Dev Tools, Development server에서만 실행되게 설정하기]]></title>
            <link>https://velog.io/@roses16-dev/React-Redux-Dev-Tools-Development-server%EC%97%90%EC%84%9C%EB%A7%8C-%EC%8B%A4%ED%96%89%EB%90%98%EA%B2%8C-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@roses16-dev/React-Redux-Dev-Tools-Development-server%EC%97%90%EC%84%9C%EB%A7%8C-%EC%8B%A4%ED%96%89%EB%90%98%EA%B2%8C-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 16 Feb 2023 15:11:47 GMT</pubDate>
            <description><![CDATA[<p>Redux Dev Tools는 디버깅에 매우 유용한 기능이지만 Redux 내 유저에게 공개되어서는 안되는 정보가 담겨있을 수 있어 배포 버전에서는 사용을 제한해야하는 경우가 있다.
이 때 아래와 같이 사용한다.</p>
<hr>
<p><code>devTools: process.env.NODE_ENV !== &#39;production&#39;</code>  구문을 리듀서에 추가하여 설정할 수 있다.
<code>process.env.NODE_ENV</code> : 빌드 시 &#39;development&#39; 또는 &#39;production&#39; 문자열로 대체된다.</p>
<pre><code class="language-javascript">// configStore.js

import { configureStore } from &quot;@reduxjs/toolkit&quot;;

const store = configureStore({
  reducer: { },
  devTools: process.env.NODE_ENV !== &#39;production&#39;
}, );

export default store;</code></pre>
<hr>
<p>** 📌 참조 **</p>
<ul>
<li>갓재명님...🤩</li>
<li><a href="https://ui.toast.com/weekly-pick/ko_20191212">https://ui.toast.com/weekly-pick/ko_20191212</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Scroll event를 이용하여 Infinite Scroll 구현하기]]></title>
            <link>https://velog.io/@roses16-dev/React-Scroll-event%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-Infinite-Scroll-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@roses16-dev/React-Scroll-event%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-Infinite-Scroll-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 16 Feb 2023 15:05:38 GMT</pubDate>
            <description><![CDATA[<p>Infinite scroll을 구현하는 데에는 여러 방법이 있는데 그 중 scroll event를 이용하여 만들었다. 그 외 다른 방법은 아래 출처에 게시되어있다.</p>
<hr>
<p>현재 유저가 보고있는 view의 위치와 document의 전체 길이를 비교해서 유저가 보고있는 view가 document의 제일 아래인지를 확인하고, 가장 아래일 때 <code>isFetching</code>은 true를 반환하며 <code>useEffect(() =&gt; {}, [isFetching])</code> 함수를 통해 isFetching이 true일 경우 매개변수로 전달된  callback함수를 실행하는 custom hook이다.</p>
<pre><code class="language-javascript">// useInfiniteScroll.js

import { useState, useEffect } from &quot;react&quot;
// scroll event가 연속적으로 발생하지 않도록 throttle을 사용하여 최적화한다. lodash package 설치가 필요하다.
import { throttle } from &quot;lodash&quot;;

const THROTTLE_WAIT = 300;

export default function useInfiniteScroll(fetchCallback){
    const [isFetching, setIsFetching] = useState(false);

    // 유저가 보고있는 view가 document의 제일 아래인지 체크하는 함수
    // window.innerHeight : 뷰포트 높이를 px단위로 나타낸다.
    // document.documentElement.scrollTop : 스크롤의 위치를 px단위로 나타낸다. 가장 위는 0 아래로 내려갈수록 값이 커진다.
    // document.documentElement.offsetHeight : border를 포함한 박스의 길이
    const handleScrollThrottle = throttle(() =&gt; {
        if(window.innerHeight + document.documentElement.scrollTop &gt;= document.documentElement.offsetHeight){
            setIsFetching(true);
        }
    }, THROTTLE_WAIT);

    // Scroll Eventlistener를 등록하여 scroll event가 발생하면 handleScrollThrottle함수를 통해 유저의 view 위치를 계산한다. 
    useEffect(() =&gt; {
        window.addEventListener(&#39;scroll&#39;, handleScrollThrottle);
        return () =&gt; {
            window.removeEventListener(&#39;scroll&#39;, handleScrollThrottle);
        }
    }, []);

    // isFetching값이 true가되면 매개변수로 전달받은 콜백함수를 실행한다.
    useEffect(() =&gt; {
        if(!isFetching) {
            return;
        }
        fetchCallback();
    }, [isFetching])

    return [isFetching, setIsFetching]
}</code></pre>
<hr>
<p>위 코드는 React 학습 3주차 실습에 사용했고 repo 주소는 아래와 같다.</p>
<ul>
<li><a href="https://github.com/roses16-dev/react-week-3">https://github.com/roses16-dev/react-week-3</a></li>
</ul>
<hr>
<p>** 📌 출처 **</p>
<ul>
<li><a href="https://ha-young.github.io/2021/frontend/infinite-scroll/">https://ha-young.github.io/2021/frontend/infinite-scroll/</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>