React Tetris 따라만들면서 배운것들

R

document.hidden

현재 탭이 활성상태인지(보이는지) 체크하는 속성값이다.

document.addEventListener("visibilitychange", function() {
    console.log(document.hidden);
});

위 코드를 console창에 입력하고 해당 브라우저에서 탭을 새로 만들어서 왔다리 갔다리 해보면 log에 true -> false -> true 이런식으로 찍히는걸 볼 수 있다.

parseInt

parsetInt(string, radix)

두번째 인자인 radix는 해당 string을 몇진수로 해석할건지를 의미한다.

parseInt 함수는 특정 radix(진수)값에 따라 문자열 아규먼트 내용의 해석을 하고, 그 영향을 받은 정수 값을 생성합니다. 문자열 내에서 시작되는 부분에 위치한 공백은 무시됩니다. 만약 radix 값이 정의되지 않거나, 0이라면, 이것은 10진수로 여겨집니다. 0x 이나 0X 으로 시작되는 숫자 일 때는 16진수로 여겨집니다.

안쓰면 10진수로 여겨진다.

slice vs splice

slice

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr1 = arr.slice(3, 5); // [4, 5]

원본 배열은 건들지 않는다.

splice

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var arr1 = arr.splice(10, 2, 'a', 'b', 'c');
console.log(arr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "a", "b", "c"]
console.log(arr1); // [11, 12]

arr.splice(10, 2, 'a, 'b', 'c') arr의 10번째 index부터 시작해서 2개의 원소를 빼가 arr1에 넣고, 빈자리에 'a', 'b', 'c'를 넣는다. 오호!

중간에 뭐 끼워넣을때도 편하다

var arr = [1, 2, 3, 4, 5]
arr.splice(2, 0, 0)
console.log(arr) // [1, 2, 0, 3, 4, 5]

Unshift

const array1 = [1, 2, 3];
console.log(array1.unshift(4, 5));
// expected output: 5
console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]

원소를 앞에 추가하는구만!

mapStateToProps

이거 왜 쓰는걸까?

transform.scale

componentWillReceiveProps

컴포넌트 생성후에 첫 렌더링을 마친 후 호출되는 메서드다.
컴포넌트가 처음 마운트 되는 시점에서는 호출되지 않는다.
props를 받아서 state를 변경해야 하는 경우 유용하다.
이 메소드 내부에서 setState를 사용해도 추가적인 렌더링이 발생하지 않는다.

Component.Statics

화살표 함수

Arrow function should not be used in the component render method. Render is called repeatedly, thus arrow function create a new function often and unnecessary. Remember:

Bind creates a new function!

component의 render 함수로 화살표 함수를 쓰면 안된다. 왜냐고? render함수는 여러번 호출되는데 화살표 함수는 호출될때마다 새로 만들어 지니까!

가로세로 비율 일정하게 만들기

가로 : 세로 = 2 : 3으로 비율을 맞추고, 화면이 충분히 크다면 가로는 640px 세로는 960px로 한다. 세로의 길이가 작아서 가로와 세로의 비율이 안맞다면? 가로를 640, 세로를 960으로 고정했는데 화면의 세로길이가 640이라서 화면밖으로 삐져나오게 된다면? 줄이긴 줄여야 하는데 얼마나 줄여야 할까? 가로와 세로에 640/960을 곱해주면 되지 않겠어? 그러면 세로는 640이 될테고, 가로도 960 -> 640을 만든 그 정도(scale)줄어들겠지.

scale 을 통해서 가로와 세로를 줄이면 된다. 얼마만큼씩???

props 펼치기

const {
  active, color, size, top, left, label, position, arrow,
} = this.props;

변수를 객체의 키로 사용

<div
 className={cn({ [style.button]: true, [style[color]]: true, [style[size]]: true })}
style={{ top, left }}
>

addEventListener('eventType', true)

뒤 인자의 true가 뭘까?

무슨의미지?

document.addEventListener('touchstart', (e) => {
  if (e.preventDefault) {
    e.preventDefault();
  }
}, true);

느낌표 두개

if (m.every(n => !!n)) {
  clearLines.push(k);
}

window.btoa

base64로 이루어진 문자열을 decode한다, window.atob는 해당 문자열을 base64로 encode한다.

async and promise

matrix = await $matrix.clearLines(matrix, clearLines);
clearLines = (matrix: Tetris.MatrixState, lines: number[]) => {
    let newMatrix = deepcopy(matrix);
    return new Promise<Tetris.MatrixState>(async (resolve, reject) => {
      await this.animateLines(lines);
      lines.forEach(n => {
        newMatrix.splice(n, 1);
        newMatrix.unshift(Array(10).fill(blockColors.GRAY));
      });
      resolve(newMatrix);
    });
  }
  animateLines = (lines: number[]) => {
    return new Promise<void>(async (resolve) => {
      await this.changeLineColor(lines, 2, 0);
      await this.changeLineColor(lines, 0, 150);
      await this.changeLineColor(lines, 2, 150);
      await this.changeLineColor(lines, 0, 150);
      resolve();
    });
  }
changeLineColor = (lines: number[], color: number, sec: number) => {
    console.log("changeLineColor is called");
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        this.render(this.setLine(lines, color));
        resolve();
      }, sec);
    });
  }

resolve를 해줘야 await 이후로 작동을 계속 진행하는구나.

Coding Style

promise callback function 앞에 async 붙이는거 지양해야한다.

clearLines = (matrix: Tetris.MatrixState, lines: number[]) => {
    const newMatrix = deepcopy(matrix);
    
    // async (resolve, reject ... 이렇게 callback function에 async 붙여서 쓰면 작동은 하는데
    // ESLint에서 하지 말라고 강력히 경고한다
    return new Promise<Tetris.MatrixState>(async (resolve, reject) => {
      /**
       * 지울 라인의 색을 변화시킨 다음에 라인을 삭제한다
       */
      await this.animateLines(newMatrix, lines);
      lines.forEach(n => {
        newMatrix.splice(n, 1);
        newMatrix.unshift(Array(10).fill(blockColors.GRAY));
      });
      
      /**
       * resolve를 해야 await clearLines(...)를 쓰는 쪽에서 라인이 지워진 newMatrix를 받을 수 있게된다
       */
      resolve(newMatrix);
    });
}

Webpack하고 ESLint하고 같이 쓸 수 있다잉

F8을 누르니까 error message가 잘 뜬다

ESLint쓰는데 마우스 갖다대도 에러메세지가 안보였는데 F8누르니까 에러메세지가 보인다

declare module vs export namespace ?

dependency cycle 문제 해결

A모듈은 B를 import했고, B모듈은 A를 import 했다.

나같은 경우에는 지금

import { blockColors, yxRotateOrigin } from '../const';
import { Tetris } from '../types';
import Matrix from './Matrix';
class Block implements Tetris.BlockOption {
  type: Tetris.BlockType;
  shape: Tetris.Shape;

Block.ts파일에서 Tetris를 import했고, types.d.ts파일 안에서는

import Block from './Components/Block';
import Matrix from './Components/Matrix';
import Next from './Components/Next';

Block을 import했다. 그래서 서로가 서로를 import 한 상황이다.

그래서 나는 그냥 types.d.ts파일을 types.ts파일로 바꾸고, 안에서 아무것도 import하지 않기로 했다. interface나 잔뜩 만들어서 Block을 커버칠거다.

아악 사용하지 않은 변수라고?

아악,,,Interface 정의하고 있는데 이거 뭔 소리냐?

그래서 찾아보니까 이렇게 하래

overrides: [
    {
      files: ['*.ts', '*.tsx'],
      rules: {
        '@typescript-eslint/no-unused-vars': [2, { args: 'none' }]
      }
    }
]

Typescript에 in operation이 있구나

type keyType = 'a' | 'b' | 'c';
type keyTimer = { [kk: keyType]: string }

이렇게 하면 다음과 같은 에러가 뜬다.

An index signature parameter type cannot be a union type. Consider using a mapped object type instead.(1337)

찾아보니 in operation이 있었다!

type keyType = 'a' | 'b' | 'c';
type keyTimer = { [kk in keyType]: string }

너무좋고~

타입스크립트 2차원 배열 선언 및 초기화

const $blocs: Array<[Node]> = [[]] // 이건 에러뜸
const $blocks: Node[][] = [[]]; // 이건 가능!

오호라~

Add Comment