MongoDB, lean을 사용한 속도 개선(mongoose)

쿼리에 lean() 추가를 통한 성능 개선

몽구스(mongoose) 쿼리의 리턴값은 Document 클래스의 인스턴스입니다.

이 인스턴스는 많은 state를 갖고 있어 다양한 작업이 가능하게 합니다.

.get(), .set(), .save(), toObject(), toJSON() 등 리턴값에 대해 여러 메서드 사용이 가능하고 이 결과로 다시 쿼리를 진행할 수 있습니다.

하지만 단지 결과 데이터만 목적으로 하는 find() 같은 작업은 다른 정보나 메서드를 사용하지 않습니다.

이 때 lean()을 유용하게 사용할 수 있습니다.

쿼리에 lean()을 추가하면 인스턴스가 아닌 POJO(Plain Old Javascript Object)를 리턴합니다.

따라서 필요 없는 데이터를 함께 반환하지 않으니 속도와 메모리 부분에서 큰 장점을 발휘합니다.

샘플 코드를 통해 결과를 확인해 보겠습니다.

import sizeof from 'object-sizeof';

const query = {'status':1};
const lean = await Product.find(query).lean();
const normal = await Product.find(query).exec();

console.log('lean: '+sizeof(lean));
console.log('-----------');
console.log('normal: '+sizeof(normal));

위에서 lean과 normal의 크기를 비교한 결과는 다음과 같습니다.

lean 하나로 객체의 사이즈가 약 10배가 넘게 차이 나는 결과가 발생합니다.

하지만 lean을 사용한 결과값은 .save(), .get() 등의 사용이 불가하니 필요에 따라서 사용해야 하는 점을 유의해야 합니다.

Faster Mongoose Queries With Lean



성능 개선은 뛰어난 안목과 분석력이 있어야만 가능한 것이 아니라 작은 부분 하나하나가 만들어내는 차이를 쌓아가는 부분이라고 생각합니다.

OnKeyPress는 왜 ESC가 인식이 안될까?(React.키 이벤트 처리)

Key 입력을 처리하는 속성

리액트 input에서 키 입력 이벤트를 처리할 때 onKeyPress, onKeyDown, onKeyUp 이벤트를 사용합니다.

자바스크립트와 같은 명칭의 속성들을 리액트는 camel case로 표기합니다.

다음과 같이 사용합니다.

const onKeyPress= e => {
    if(e.key==='Enter'){    
        findExecute();
    }   
}

........

<div onKeyPress={onKeyPress}>click</div>

이벤트가 발생하는 시점이 조금씩 다를 뿐 사용 방법은 같습니다.

그리고 각 이벤트 별 특징은 다음과 같습니다.

onKeyDown 👉 이벤트가 먼저 실행
onKeyUp 👉 text가 입력되면 실행
onKeyPress 👉 text 입력이 완료되면 실행 (Deprecated)

MDN의 공식 문서를 보면 이제 onKeyPress는 더 이상 사용되지 않는다고 하니 거의 비슷하게 동작하는 onKeyDown을 사용하는 것이 좋습니다.

MDN – keypress event


왜 onKeyPress에서 ESC가 동작하지 않을까?

onKeyPress는 기본적으로 ESC가 눌려졌을 때 이벤트가 생성되지 않기 때문입니다.

onKeyPress는 ESC, CTRL, ALT 등 function 기능을 갖는 키를 제외하고 알파벳과 숫자 키에서만 이벤트가 생성됩니다.

하지만 onKeyDown, onKeyUp은 onKeyPress에서 인식되지 기능 키들도 인식이 됩니다.

또한 onKeyPress는 이제 더 이상 지원되지 않는다고 하니 기본적으로는 onKeyDown을 사용하고 상황에 따라 onKeyUp을 사용하면 큰 문제 없이 원하는 방식으로 구현할 수 있을 것입니다.

각 키 값과 이슈 관련 페이지를 링크로 남기겠습니다.


키 코드를 직접 입력해보면서 알 수 있는 사이트 -> https://keycode.info/

관련 이슈 -> https://github.com/Leaflet/Leaflet/issues/5234

이진 탐색(binary search), 자바스크립트로 구현하기

이진 탐색과 구현방법

이진 탐색(binary search)은 데이터 집합에서 원하는 데이터를 찾을 때까지 집합을 이분(二分)하여 탐색하는 방법입니다.

데이터 집합을 둘로 나누고 찾는 데이터가 있는 집합을 선택하여 다시 반으로 나누고 다시 데이터가 있는 집합에 같은 과정을 계속 반복합니다.

따라서 아무리 큰 데이터라도 몇 번의 연산만으로 원하는 데이터를 찾을 수 있습니다.

하지만 이진 탐색은 조건이 있는데요.

데이터가 반드시 순서대로 정렬된 상태여야 합니다.

그림을 통해 탐색의 과정을 확인해 보겠습니다.

위와 같은 데이터 집합에서 2를 찾으려면 먼저 집합을 반으로 나누고 찾는 데이터가 속한 집합을 선택합니다.

그럼 첫 번째로 선택한 집합은 다음과 같습니다.

또 반을 나누고 2가 속한 집합만을 선택합니다.

여기서 반을 나누고 2가 속한 집합을 선택하면 다음과 같습니다.

이제 둘 중 하나를 확인하여 원하는 데이터를 선택하면 됩니다.

이진 탐색 코드는 다음과 같습니다.

const binarySearch=(target, data)=>{

  let low = 0;
  let high = data.length-1;
  
  while(low<=high){
    
    let mid = Math.floor((low+high)/2);    
  
    if(target===data[mid]){
       return mid;
    }else if(target>data[mid]){
      low = mid+1 
    }else if(target<data[mid]){
      high = mid-1
    }
  }

  return undefined;
}

이 탐색 방법은 데이터의 양이 많아지면 엄청난 효율을 자랑합니다.

데이터가 10000까지 있을 때 8000을 찾기 위해서 무차별 대입은 7999번의 연산을 진행해야 하지만 이진 탐색 방법은 13번의 연산이면 원하는 데이터를 찾을 수 있습니다.

자바스크립트를 이용한 BFS, DFS 구현하기(javascript)

데이터는 선형 구조(배열, 연결리스트, 스택, 큐) 또는 비선형 구조(트리, 그래프)로 이루어져 있으며, 순차적으로 나열된 선형 구조에 비해 비선형 구조의 데이터는 탐색이 어렵습니다.

하지만 비선형 구조의 대표적인 탐색 방법인 BFS, DFS를 사용하면 깔끔하게 탐색이 가능합니다.

두 방법 모두 무차별 탐색(Brute Force Search, 모든 데이터를 하나씩 탐색) 방법을 사용합니다.


DFS는 깊이 우선 탐색 방법으로 트리 구조의 데이터에서 노드마다 가장 깊이까지 탐색한 뒤 다음 노드로 이동하는 방법입니다.

위와 같은 트리 구조의 데이터가 있을 때, DFS는 한번 선택한 길은 끝까지 가본 뒤 다음 길을 탐색하는 방식과 같습니다.

그림으로 나타내면 다음과 같습니다.

검색 속도는 BFS에 비해서 느리지만 조금 더 간단합니다.

경로의 특징이 필요한 문제를 풀 때 DFS를 사용합니다.

const graph = {
  A: ["B", "C"],
  B: ["A", "D"],
  C: ["A", "E"],
  D: ["B", "F"],
  E: ["C","G"],
  F: ["D","H","I"],
  G: ["E","J","K"],
  H: ["F","L"],
  I: ["F", "M"],
  J: ["G","N"],
  K: ["G","O"],
  L: ["H"],
  M: ["I","P"],
  N: ["J"],
  O: ["K"],
  P: ["M"]
};

const bfs = (graph, start) => {

    const checked = [];    // 탐색 완료 데이터
    const willCheck = [];  // 탐색 예정 데이터
    
    willCheck.push(start);
    
    while(willCheck.length!==0){
      const node = willCheck.pop();  // 스택(Last In First Out)
      if(!checked.includes(node)){
       	 checked.push(node);
         //reverse() 제거 시 그림의 4,3,2,1 순서로 탐색     
      	 willCheck.push(...graph[node].reverse());  
        
      }
   }
	return checked;
}

console.log(bfs(graph, "A"));
// ['A', 'B', 'D', 'F', 'H', 'L', 'I', 'M', 'P', 'C', 'E', 'G', 'J', 'N', 'K', 'O']

BFS는 너비 우선 탐색 방법으로 트리 구조 데이터에서 노드의 인접 데이터를 모두 탐색한 뒤 다음 데이터로 이동하는 방법입니다.

그림으로 나타내면 다음과 같습니다.

탐색 속도는 DFS보다 빠르며 최단 거리를 구하는 문제에서 사용할 수 있습니다.

const graph = {
  A: ["B", "C"],
  B: ["A", "D"],
  C: ["A", "E"],
  D: ["B", "F"],
  E: ["C","G"],
  F: ["D","H","I"],
  G: ["E","J","K"],
  H: ["F","L"],
  I: ["F", "M"],
  J: ["G","N"],
  K: ["G","O"],
  L: ["H"],
  M: ["I","P"],
  N: ["J"],
  O: ["K"],
  P: ["M"]
};

const bfs = (graph, start) => {

    const checked = [];
    const willCheck = [];
    
    willCheck.push(start);
    
    while(willCheck.length!==0){
      const node = willCheck.shift(); // 큐(First In First Out)
      if(!checked.includes(node)){
       	 checked.push(node);
      	 willCheck.push(...graph[node]);       
      }
   }
	return checked;
}

console.log(bfs(graph, "A"));
// ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P']

textContent, innerText, innerHTML 간단 비교(javascript)

요소의 텍스트를 다루는 textContent, innerText, innerHTML의 차이점과 유의 사항

요소에 접근해 데이터를 설정하거나 가져올 때 사용하는 프로퍼티인 textContent, innerText, innerHTML에 대해 알아보겠습니다.

<div id=1 onClick=(check(event))>click
    <div id=2>child1</div>
    <div id=3>child2
      <div id=4>grandchild</div>
    </div>
</div>

onClick 이벤트를 통해 div요소의 텍스트에 접근할 때 각각의 프로퍼티를 사용한 결과는 다음과 같습니다.


1. 실행 결과

const check = (event) => {
    console.log(event.target.textContent); 
}
const check = (event) => {
    console.log(event.target.innerText); 
}
const check = (event) => {
    console.log(event.target.innerHTML); 
}

textContent

text/plain으로 파싱하여 모든 요소를 반환합니다. <script>, <style> 요소를 포함해 CSS를 사용해 숨겨진 요소도 함께 반환하며 요소의 원시 텍스트를 사용하므로 성능이 좋습니다.

innerText

text/plain으로 파싱하여 렌더링 후의 요소를 반환합니다. <script>, <style> 요소는 반환하지 않으며 숨겨진 요소도 반환하지 않습니다. 자식 노드를 모두 제거하고 하나의 텍스트로 반환되며 성능은 보통입니다.

innerHTML

text/html로 파싱하여 요소의 html, xml 전체를 반환합니다. html을 다루므로 보안 이슈 중 하나인 XSS(Cross Site Scripting)에 취약합니다. HTML5에서는 innerHTML에 삽입된 <script> 태그는 실행되지 않도록 변경되었지만 <img>등 다른 태그를 통해 접근하면 여전히 취약점이 남습니다. 따라서 innerHTML은 별도로 문제 방지를 위한 설정이 없다면 사용을 권장하지 않습니다.



구현도 중요하지만 상황에 맞고 적절한 방식을 통해 구현한 시스템에 문제가 생기지 않도록 사전에 방지하는 것이 더 중요한 것 같습니다. 적절한 방식을 선택하는 것은 결국 각 기능의 이해를 통해서야 비로소 가능한 부분이므로 필요할 때 정리를 해두면 도움이 될 것 같습니다.

A Simple Explanation of Currying Functions(Javascript)

currying function’s usages, pros and cons

‘Currying’ has the same spelling as Curry that we love.

But ‘currying’ is derived from the name Haskell Brooks Curry who was known as a mathematician and a logician.

Currying is a technique that converting multiple arguments function into a single argument functions sequence.

Like this.

func(a, b, c) -> f(a)(b)(c)

Three arguments function is converted into three functions with single argument each.

f(a) returns value and (b) takes this value as a parameter. (c) also do the same thing. Get’s (b)‘s return value and return.

//non-curried
function plusFunc(a, b, c){
  console.log(a + b + c);
}

plusFunc(1, 2, 3);   // 6

//curried
function plusFunc(a){
    return function(b){
       return function(c){
          console.log(a + b + c);
       }
    }
}

plusFunc(1)(2)(4);  // 7

Then what are the differences between Curried and Non-curried?

non-curried : Function will be immediately executed even though parameters are not passed.
? Function definition : func(a, b, c)
? Function execution : func(a)
? Execution result : func(a, undefined, undefined)

curried : Execution will be suspended if parameters are not fully passed.
? Function definition : func(a, b, c)
? Function execution : func(a)
? Execution result : func(a) waits for b parameter.

So we can use currying as below.

function setAppell(appell){
    return function(name) {
       console.log(appell + name);   
    }
}

const setName = setAppell('Mr.');
setName('Right');  // Mr.Right
setAppell('Mr.')('Baker'); //Mr.Baker

//ES6 화살표 함수
const setAppell = appell => name => console.log(appell + name);

const setName = setAppell('Miss.');
setName('Dior');  // Miss.Dior

If we use currying function, we can also pass event and value together.

const setNumber = (num) => (event) => {
     console.log(event.target.id+':'+num);
}

<div onClick="setNumber(2)(event)" id='myNum'>
  click
</div>

// myNum:2

What is Pros.

? Pros
Reusable
– Reduced amount of code
– Readability

And Cons.

? Cons
Deeply nested functions cause memory and speed issue. So Currying

Mathematical Explanations of Currying



Most of the functions can be implemented without using currying. but you can expect a good effect if you use currying to improve productivity through reusability or readability.

리액트가 타입스크립트로 생성이 안될 때(CRA + typescript not working)

create-react-app <project> –template typescript

리액트+타입스크립트로 새 프로젝트를 생성하고자 create-react-app –template typescript를 실행해도 App.tsx가 아닌 App.js로 생성되는 경우가 있습니다.

cra-template-typescript 패키지가 없어 발생하는 문제일 가능성이 있으므로 해당 패키지를 설치해주고 실행해 봅니다.

npm install cra-template-typescript -g

설치 후 다시 create-react-app <projectName> –template typescript를 실행한 결과입니다.


또 다른 원인 중 하나는 캐쉬에 남아있는 이전 버전으로 설치가 되어 적용이 안될 가능성도 있으므로 npm uninstall -g create-react-app를 통해 삭제 후 재설치를 진행해보는 것도 좋을 것 같습니다.

CSS, 알면 쉬운 display 속성(inline, flex, …others)

inline, block, inline-block, flex, inline-flex, grid, inline-grid, none

display는 요소를 보여주고 숨기거나 위치를 설정하기 위한 옵션으로, display만 잘 알아도 레이아웃의 많은 부분을 해결할 수 있습니다.

이번 포스팅에서 display의 속성인 inline, flex, inline-flex, block, inline-block, grid, inline-grid, none의 구현을 통해 각각의 표시 방식을 알아보도록 하겠습니다.

알아보기 편하도록 배경은 블랙, 요소는 각각 레드, 오렌지, 그린으로 표현하겠습니다.

inline : inline으로 표시(width는 요소 크기)
block : block으로 표시
inline-block : inline + block으로 표시
flex : 자식 요소를 모두 inline-block으로 설정
inline-flex : inline + flex(전체 width는 자식 width의 합)
grid : flex처럼 한 방향이 아닌 가로, 세로로 설정 가능한 레이아웃
inline-grid : inline + grid(전체 width는 자식 width의 합)
none : 표시하지 않음(공간을 차지하지 않음)


줄바꿈 없이 태그를 표시하는 요소를 inline 요소, 태그마다 줄바꿈이 되는 요소를 block 요소라고 합니다.

대표적인 inline 요소는 <span>, <a> 등이 있으며, block 요소는 <div>,<p>,<h1>,<h2> 등이 있습니다.

먼저 아무 속성도 설정하지 않은 div를 확인해 보겠습니다.

.setContainer{
  background-color:black;
}

.setOne{
  background-color: red;
}

.setTwo{
  background-color: orange;
  width:95%;
}

.setThree{
  background-color: green;
  width:90%;
}

<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

div의 default 설정은 width 100%입니다.

기본 설정을 확인하기 위해 setTwo와 setThree에 width를 설정한 결과입니다.

먼저 display의 inline 속성을 확인해보죠.


1. inline

위 속성은 말 그대로 요소를 일렬로 늘어선 방식으로 표시하며 줄바꿈을 하지 않습니다.

각 요소마다 설정하며 width는 자동으로 크기에 맞게 변형됩니다.

.setContainer{
  background-color:black;
  display:inline;
}
.setOne{
  background-color: red;
  display:inline;
}
.setTwo{
  background-color: orange;
  display:inline;
}
.setThree{
  background-color: green;
  display:inline;
}

<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

inline은 위와 같이 문자열처럼 일렬로 늘어선 상태로 표시됩니다.


2. block

block은 inline 요소를 block으로 표시합니다.

block 요소 div 대신 inline 요소 span을 사용하면 다음과 같은데요.

위에서 div에 display:inline을 설정한 것과 같은 모양입니다.

그러므로 span에 display:block을 설정하면 반대로 div를 사용한 것과 같은 결과가 나오는 것을 알 수 있습니다.

.setContainer{
  background-color:black;
}
.setOne{
  background-color: red;
  display:block;
}
.setTwo{
  background-color: orange;
  display:block;
}
.setThree{
  background-color: green;
  display:block;
}

<div class='setContainer'>
  <span class='setOne'>red</span>
  <span class='setTwo'>org</span>
  <span class='setThree'>grn</span>
</div>

block 속성은 inline 요소를 block 요소처럼 표현하는 것을 알 수 있습니다.


3. inline-block

그렇다면 inline-block은 언제 사용할까요?

display:block이 필요하지만 표시는 inline으로 표시를 하고 싶은 상황입니다.

그러면 그게 그냥 span의 default 아닌가라고 생각할 수도 있지만 span에는 width, height 등 속성이 적용되지 않기 때문에 block으로 설정을 해야 합니다.

위의 코드에서 첫 번째 요소에 width:300px, height:200px를 설정하면 다음 그림과 같은 모습이 됩니다.

위 요소를 inline으로 설정하기 위해 inline-block를 사용할 수 있습니다.

.setContainer{
  background-color:black;
}
.setOne{
  background-color: red;
  display:inline-block;
  width:300px;
  height:200px;
}
.setTwo{
  background-color: orange;
  display:inline-block;
}
.setThree{
  background-color: green;
  display:inline-block;
}

<div class='setContainer'>
  <span class='setOne'>red</span>
  <span class='setTwo'>org</span>
  <span class='setThree'>grn</span>
</div>

div를 사용해 위와 같이 나타내려면 어떻게 해야 할까요?

.setContainer{
  background-color:black;
}
.setOne{
  background-color: red;
  display:inline-block;
  width:300px;
  height:200px;
}
.setTwo{
  background-color: orange;
  display:inline;
}
.setThree{
  background-color: green;
display:inline;
}

<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

위와 같이 사용하면 됩니다.

만약 위와 같이 사각형 사이 사이에 빈공간이 들어가는 경우가 있다면 <div> 태그 사이의 띄워쓰기나 줄바꿈을 확인해봐야 합니다.

보기에는 안좋지만 다음과 같이 태그 사이를 모두 붙여쓰면 공백이 발생하는 것을 제거할 수 있습니다.

<div class='setContainer'><div class='setOne'>red</div><div class='setTwo'>org</div><div class='setThree'>grn</div></div>

4. flex

flex는 새로운 속성 중 하나로 부모 요소에서만 설정을 합니다.

display:flex를 설정하면 모든 자식 요소에 display:inline-block을 설정한 것과 같은 효과를 줍니다.

따라서 모든 자식 요소는 display를 설정할 필요 없이 width, height 등의 속성이 사용 가능합니다.

.setContainer{
  background-color:black;
  display:flex;  
}
.setOne{
  background-color: red;
}
.setTwo{
  background-color: orange;
  width:200px;
}
.setThree{
  background-color: green;
}

<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

개별 요소에 모두 display를 설정할 필요 없이 부모 요소에서만 편하게 설정이 가능합니다.

만약 자식 요소를 가운데 정렬하고 싶으면 부모 요소에서 justify-content:center;를 사용하면 됩니다.


5. inline-flex

flex는 이미 inline-block의 기능을 갖고 있는데 그럼 inline-flex의 기능 무엇일까요?

바로 inline 특징 중 하나인 자동 크기 조절입니다.

inline-flex는 자식 요소를 합친 크기 만큼만 크기를 설정하므로 width는 100%가 아닌 자식 크기의 합입니다.

flex의 결과와 비교해보면 알 수 있듯이 부모 요소를 의미하는 블랙이 공간을 차지하고 있지 않습니다.


6. grid, inline-grid

이 grid는 무엇일까요?

그리드는 flex처럼 가로나 세로 한 방향으로만 레이아웃을 설정하는 것이 아니라 가로, 세로 두 방향 모두 설정할 수 있는 속성입니다.

grid 역시 부모 요소에서 설정을 하며 자식 요소를 block으로 표현합니다.

다양한 속성을 통해 레이아웃을 구성하는데 효과적이지만 내용이 많아 다른 포스팅을 통해 좀 더 알아봐야 할 필요성이 있을 것 같습니다.

.setContainer{
  background-color:black;
  display:grid;  
  grid-template-columns: 100px 100px 100px;
}
.setOne{
  background-color: red;
}
.setTwo{
  background-color: orange;
}
.setThree{
  background-color: green;
}

<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

inline-grid 역시 inline-flex 속성과 마찬가지로 width를 자식 요소에 맞게 조절하는 기능을 합니다.


7. none

none은 해당 요소를 표시하지 않으며 공간도 차지하지 않는 방식입니다.

.setContainer{
  background-color:black;
}

.setOne{
  background-color: red;
  display:none;
}

.setTwo{
  background-color: orange;
}

.setThree{
  background-color: green;
}


<div class='setContainer'>
  <div class='setOne'>
    red
  </div>
  <div class='setTwo'>
    org
  </div>
  <div class='setThree'>
    grn
  </div>
</div>

이렇게 없는 놈 취급을 합니다.

이와 반대되는 속성이 visibility로 이는 공간은 차지하되 표시만 하지 않는 속성입니다.

visibility, display 사용 관련 포스트

display:none을 visibility:hidden으로 변경한 결과입니다.

있는데 없는 척을 합니다.

물론 visibility도 공간만 차지할 뿐 할 수 있는 일은 없습니다.



CSS의 기본이지만 모든 기능을 다 이해하고 사용하기까지는 어느 정도의 시간과 경험이 필요한 것 같습니다. 무작정 외우기보다는 사용하면서 답답함이 쌓였을 떄 한번씩 소화제 느낌으로 설명을 삼켜주면 조금 더 와닿는 설명이 되지 않나 싶습니다..🧔

템플릿 리터럴(template literal)과 쉬운 응용(feat.`)

`로 시작해서 `로 끝나는 템플릿 리터럴

템플릿 리터럴(template literal)은 ES6부터 도입된 기능으로 문자열 다루기에 특화된 기능인데요.

` (backtick, grave accent)

템플릿 리터럴은 ` 기호로 시작해 ` 기호로 끝나며, 문자열과 변수를 함께 전달하거나 태그를 편리하게 사용할 수 있습니다.

또한 다음과 같은 방식도 사용도 가능한데요.

const printData = (text) => {
    console.log(text[0]); // 'Hello everyone!'
}

printData`Hello everyone!`;

함수에 템플릿 리터럴을 전달할 수도 있습니다.

이를 태그드 템플릿(tagged template)이라고 하는데요.

호출된 함수는 템플릿 리터널 내 문자열 조각이나 표현식 등을 매개변수로 받습니다.

styled-components에서 사용되는 방식도 태그드 템플릿입니다.


1. 템플릿 리터럴(template literal)

템플릿 리터럴은 시작과 끝에 반드시 `(backtick)을 붙여야 하며, ‘(홑따옴표), “(쌍따옴표)와 반드시 구분해야 합니다.

const name = 'clint Eastwood';
const age = '92';
const city = 'San Francisco';
const occupation = 'director';

// 표현식
console.log('His name is '+name+ '\n' + 'and '+age+'.');

// 템플릿 리터럴
console.log(`He was born in ${city}
and he is a ${occupation}`);

템플릿 리터럴에서 ${ }를 사용하면 블록 내 변수 또는 함수에 접근이 가능하며, \n 등 이스케이프를 사용하지 않고도 입력한대로 출력할 수 있습니다.

템플릿 리터럴은 쉽게 응용이 가능하니 태그드 템플릿에 대해 알아보겠습니다.

2. 태그드 템플릿(tagged template)

const TextBox = styled.div`
  display: inline-block;
  color: gray;
  margin: 0 auto;
`;

const StyledInput = styled.input`
    font-size: 1rem;
    border: none;
    border-bottom: 1px solid gray;
    outline: none;
    width: 100%;
`;

위와 같이 styled-components에서 태그드 템플릿이 밥 먹듯이 사용됩니다.

템플릿 리터럴로 함수를 호출하면 어떻게 사용할까요?

함수를 호출하면 매개변수로 문자열과 변수가 전달됩니다.

const name = 'clint';
const age = '92';
const city = 'LA';

const showString = (text, ...args) => {
    console.log(text);
    console.log(args);
    console.log(text[2]);
    console.log(args[2]);
}

showString`He is ${name} and ${age}. From ${city}`;

전달된 매개변수는 텍스트와 ${ }에 넣은 변수이며, 각각 확인할 수 있습니다.

텍스트와 변수에 접근하려면 인덱스를 사용하면 됩니다.

텍스트의 경우 ${ }이 들어간 부분에서 끊어주므로 ‘He is’, ‘ and ‘, ‘. From ‘, ”이렇게 네 부분으로 나뉘어지며, 순서대로 0, 1, 2, 3의 인덱스를 갖습니다.

태그드 템플릿을 사용하는 이유는 문자열을 원하는 형식으로 재가공하여 사용할 수 있는 장점이 있기 때문입니다.



styled-components를 무턱대고 사용하는 것보다 구조를 알고 사용하면 더 도움이 될 것 같아 태그드 리터럴에 대해 알아보았습니다. 템플릿 리터럴은 이제 너무 유용하고 편리한 기능이므로 꼭 알아두어야 할 기능 중 하나인 것 같습니다.

CSS transition, 작동 원리 이해하기(왜 작동을 안할까?)

transition의 작동원리와 transition 대체할 수 있는 방법

transition은 애니메이션 효과를 주는 CSS입니다.

transition 하나만으로도 투박한 느낌을 지우고 부드러운 느낌을 줄 수 있는데요.

메뉴가 부드럽게 열리고 닫히거나 화면에 fade-in 효과 등을 줄 수 있습니다.

CSS의 대표적인 애니메이션 처리는 transition와 animation이 있는데요.

transition은 변경이 발생하는 순간 작동하고, animation은 transition보다 더 자유롭고 다양하게 사용이 가능한 친구입니다.

그럼 transition을 작성하는 코드부터 확인해 보겠습니다.

1. transition 사용하기

.setBox{
  background-color:pink;
  width:200px;
  height:200px;
  transition:all 1000ms linear 500ms;
}

위와 같은 방식으로 사용하며, 한 줄 표기의 의미는 다음과 같습니다.

transition: property duration timing delay;

property : color, background-color, border, position, all 등의 속성

duration : 완료까지 걸리는 시간. ms(밀리초) 또는 s(초)로 설정

timing : linear(동일), ease(느림->빠름->느림), ease-in(느림->빠름), ease-out(빠름->느림)

delay : 딜레이 시간(ms 또는 s로 설정)

물론 property나 delay 는 생략도 가능합니다.

이를 풀어 쓰면 다음과 같이 작성할 수 있습니다.

transition-property : property
transition-duration : duration
transition-timing-function : timing
transition-delay: delay

transition을 사용해 마우스를 올리면(hover) 박스가 부드럽게 커졌다가 줄어드는 코드를 확인해 보겠습니다.

.setBox{
  background-color:pink;
  width:100px;
  height:50px;
  transition:all 1000ms linear 500ms;
}

.setBox:hover{
  background-color:gold;
  width:200px;
  height:100px;
  transition:all 300ms ease;
}

<div class='setBox'></div>

박스가 커질 때는 .setBox:hover{}의 transition 설정에 따라 300ms, 줄어들 때는 .setBox{}의 transition 설정에 따라 1000ms동안 움직입니다.

그럼 이제는 요소 숨기기&표시하기 기능을 확인해 보겠습니다.

.setBox{
  background-color:gray;
  color:white;
  width:100px;
  height:50px;
  text-align:center;
  line-height:50px;
}
.showMenu{
  visibility:hidden;
  height:150px;
  width:100px;
  background-color:lightgray;
  opacity:0;
  color:black;
  border-radius:5px;
  transition:linear 500ms;
}
.setBox:hover .showMenu{
  visibility:visible;
  transition:linear 500ms;
  opacity:1;
}

<div class='setBox'>MENU
    <div class='showMenu'>
        <div class='menu'>
          메뉴 A
        </div>
        <div class='menu'>
          메뉴 B
        </div>
        <div class='menu'>
          메뉴 C
        </div>
    </div>
</div>

위 코드의 실행 결과는 아래와 같습니다.

마우스를 올리면 숨겨둔 div를 표시하거나 숨기면서 transition이 작동하는 것을 볼 수 있습니다.

위 코드에서 visibility가 아닌 display를 사용하면 결과는 어떨까요?

display를 사용하면 transition이 작동하지 않는 것을 볼 수 있습니다.

이유는 바로 display와 visiblility의 작동 방식에 차이가 있습니다.

transition은 위에서 이야기한 것처럼 변경이 발생하는 순간 작동합니다.

예를 들어 A 모양에서 B 모양으로 변경될 때 작동을 하는데요.

visibility는 공간은 그대로 두고 설정에 따라 요소를 숨기거나 나타내므로 A에서 B로 변경을 적용할 수 있습니다.

다음 그림과 같은 느낌입니다.


2. transition 작동하지 않는 이유

그렇다면 display가 작동하지 않는 이유도 추측할 수 있습니다.

display:none은 요소의 표시 뿐만 아니라 표소가 있는 공간도 비워버리는 설정입니다.

따라서 ‘A모양 -> B모양’으로의 변형이 아니라 ‘없음 -> B모양’ 이 되므로 transition이 작동하지 않는 것입니다.

그러므로 transition은 ‘모양의 변형‘만 기억하면 됩니다.

그렇다면 같은 효과를 내는 animation은 어떻게 사용할까요?

코드만 봐도 이해하기 쉬운 구조이므로 코드로 확인해 보겠습니다.

.setBox:hover .showMenu{
  visibility:visible;
  animation:setMotion 3s;
}
@keyframes setMotion{
  0%{
      opacity:0;
    }
  100%{
      opacity:1;
    }
}


CSS3는 아주 다재다능한 친구라 기존에는 jquery를 사용해 복잡하게 구현할 수 있던 애니메이션 효과들을 이제는 한 행의 코드만으로 해결할 수 있게 되면서 CSS3는 조금만 배워 둬도 아주 유용하게 사용할 수 있는 친구가 되었네요. CSS에 조금 더 관심을 갖고 포스팅을 늘려 가야겠습니다.