📌 타입스크립트란?
JavaScript는 동적 타입만을 제공하여 예측하기 어려운 타입변환으로 디버깅이 어려워지는 문제점이 있어 이를 해결하고자 TypeScript가 탄생하였다.
TypeScript는 정적 타입 시스템을 사용하여 코드가 실행되기 전에 코드에 대하여 예측해준다.
계속 읽기JavaScript는 동적 타입만을 제공하여 예측하기 어려운 타입변환으로 디버깅이 어려워지는 문제점이 있어 이를 해결하고자 TypeScript가 탄생하였다.
TypeScript는 정적 타입 시스템을 사용하여 코드가 실행되기 전에 코드에 대하여 예측해준다.
계속 읽기1 | import styled from "styled-components"; |
Link 컴포넌트 안에다가 styled-component를 생성하고 as props를 전달해주었다.
위와 같이 할 경우, as props에 img 태그가 들어오게 된다면
이를 해결하기 위해 조건부 렌더링을 해주었다.
1 | import styled from "styled-components"; |
문제의 원인은 npm 명령어로 webpack server만 실행시켰는데, webpack config.js
파일에 static
속성값을 [build]
로 주었기 때문에 정적 이미지 파일을 불러오기 위해서는 build
폴더에서 assets
을 찾는다.
그러므로 npm run build
명령어로 build 폴더를 생성한 후 그 안에다가 img를 넣어주고 경로를 설정해주어 해결하였다.
1 | <Link |
aria-label
속성 있을 때, 조건부로 css 추가 이 속성을 삭제한 이유는 span 태그를 사용하여 Link 컴포넌트를 구현하였을 때, role="link"
로 해주었기 때문에 aria-label
속성을 굳이 해주지 않아도 되므로 삭제하였다.
로또 게임 기능을 구현해야 한다. 로또 게임은 아래와 같은 규칙으로 진행된다.
1 | - 로또 번호의 숫자 범위는 1~45까지이다. |
1 | 14000 |
1 | 1,2,3,4,5,6 |
1 | 7 |
1 | 8개를 구매했습니다. |
1 | 3개 일치 (5,000원) - 1개 |
1 | 총 수익률은 62.5%입니다. |
1 | [ERROR] 로또 번호는 1부터 45 사이의 숫자여야 합니다. |
1 | 구입금액을 입력해 주세요. |
1 | const app = new App(); |
1 | const numbers = MissionUtils.Random.pickUniqueNumbersInRange(1, 45, 6); |
1 | class Lotto { |
score 객체에 3등 4등 5등 의 키 값은 숫자로만 주었는데, bonus 등수는 문자열로 주어서 출력시 5등 4등 3등 2등 1등 Bonus등수가 출력되어서 이를 해결하기 위해 score의 key 값을 문자열로 변경하였다.
lotto 배열의 요소도 [1, 2, 3, 4, 5, 6] 이런 형태의 배열인데, print 결과물이 “[1, 2, 3, 4, 5, 6]” 이렇게 나와야 하므로 이에 대한 처리를 해주었다.
1 | this.Lotto.forEach((lotto) => MissionUtils.Console.print(`${lotto}`)); |
1 | this.Lotto.forEach((lotto) => MissionUtils.Console.print(`[${lotto}]`)); |
1 | this.Lotto.forEach((lotto) => |
Number.prototype.toLocaleString()
메서드를 사용하면 천단위에 ,를 찍은 문자열로 변환한다.1 | class Lotto { |
1 | // 내 코드 |
1 | class Lotto { |
1 | class Lotto { |
1 | // 리팩터링 전 |
2주차때 클래스구조와 테스트에 대해서 조금은 익숙해져서 3주차 미션을 받았을 때 구조가 비슷하여 조금 마음이 놓였다.
jest expect
함수와 matcher
함수를 찾아보면서 단위 테스트 기능에 대해 공부해볼 수 있는 기회여서 좋았다.리액트 컴포넌트에 전달되는 Prop(속성)의 Type(타입)을 검사하는 방법에 대해 알아보자.
1 | EmotionCard.propTypes = { |
위와 같이 직접 custom propTypes를 통해 prop를 검사할 수 있지만 리액트 팀에서 제공하는 propTypes 패키지를 사용하면 편리하고 안정적으로 prop 검사를 할 수 있다.
1 | npm i -D prop-types |
1 | import PropTypes from "prop-types"; |
1 | import { objectOf, number } from "prop-types"; |
propTypes.objectOf
는 객체의 속성 값이 모두 동일한 타입을 설명할 경우 사용한다.1 | import { shape, arrayOf, string } from "prop-types"; |
propTypes.shape
는 객체의 각 속성별 타입을 설명할 때 사용한다.arrayOf
를 사용하였다.객체의 속성이 정확히 동일하게 일치해야한다면
propTypes.exact() 를 사용한다.
propTypes는 null 타입 체크를 할 수 없어 oneOf를 사용한다.
1 | import { oneOf, oneOfType, shape, string } from "prop-types"; |
PropTypes.oneOf([’grow’, ‘learn’, ‘connect’])
이 중 하나만 파라미터로 들어올 수 있다.함수에 기본값을 주듯이 props에 기본값을 주는 것을
1 | import React from 'react'; |
애플리케이션의 비동기 처리는 빈번하게 발생하므로 비동기 요청의 응답을 기다리는 동안 사용자에게 로딩을 표시해줘야한다. 재사용이 가능한 컴포넌트로 로딩 컴포넌트를 만들어보자.
접근성을 고려하였을 때,
1 | // public/index.html |
aria-live="assertive"
속성을 주어 다른 것보다 우선적으로 스크린 리더가 읽도록 설정해준다.1 | // Spinner.js |
role="alert"
속성을 주어 스크린 리더가 읽고 있는 것을 중지하고 로딩중을 읽도록 설정하였다.포털을 사용하면 애플리케이션 영역을 벗어나 특정 위치에 컴포넌트를 렌더링할 수 있다. 즉, 지금껏 root 컨테이너에만 렌더링을 해왔다면 포털을 사용하여
포털을 통해 렌더링된 컴포넌트는 DOM 트리 위치와 상관없이 React 컴포넌트 트리에 포함되기 때문이다.
1 | ReactDOM.createPortal(child, container); |
1 | render() { |
시각적으로 자식을 튀어나오도록 보여야하는 다이얼로그, 호버카드, 툴팁에 사용된다. 이 때,
키보드 포커스 관리와 접근성을 고려해줘야한다.
aria-modal=true
이여야한다.aria-label
, aria-labelledby
로 설정한다.1 | export class DemoDialog extends React.Component { |
root 요소가 아닌 곳에 자식 컴포넌트를 그려주기 위해서 public 폴더의 index.html에 다음과 같이 div 요소를 추가해줘야한다.
1 | // public/index.html |
1 | // Dialog.jsx |
createPortal()
에 렌더링할 자식 컴포넌트와 자식 컴포넌트를 렌더링할 컨테이너를 전달하였다.Dialog.footer
자식 요소에게 onClose를 props로 전달하였다.1 | export class Dialog extends React.Component { |
e.preventDefault()
로 기본동작을 막을 수 있다.htmlElement.style.overflowY = "hidden"
로 모달 컴포넌트가 띄워져있을 때, 다른 요소는 스크롤이 비활성화시켜주었다.어떤 컴포넌트들은 어떤 자식 요소가 들어올지 예상할 수 없는 경우가 있다. 이럴 경우 children prop을 사용하여 자식 요소를 출력에 그대로 전달하는 것이 좋다.
합성(composition)을 사용하여
1 | Dialog.Header = function DialogHeader({ children }) { |
리액트 앱은 대부분 리액트에 의해 컨트롤되지만 예외인 상황이 있다. 리액트는 virtualDOM을 가지고 동작하기 때문에 RealDOM 요소에 접근하거나 조작해야할 경우 이는 리액트가 할 수 없는 일이다.
이러한 일을
사이드 이펙트를 처리하기 위해서는 다음과 같은 React API를 사용하여야한다.
컴포넌트 생성 시점에 이벤트를 구독한 경우, 컴포넌트 제거 시점에 구독한 이벤트를 취소해야한다.
1 | export class TiltCard extends React.Component { |
교차 출처 리소스 공유(Cross-Origin Resource Sharing)는 추가 HTTP Header를 사용하여 한 출처에서 실행 중인 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록
웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때, 교차 출처 HTTP 요청을 실행한다.
ex) https://domain-a.com
의 프론트 엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json
을 요청하는 경우 보안 상의 이유로
CORS 표준은 웹 브라우저에서 허용된 출처를 서버에서 새로운 HTTP Header에 추가함으로써 동작한다.
HTTP 요청 메서드가 GET, POST 일 때 사용한다.
다른 출처끼리 요청을 보낼 때, 요청에 Origin이라는 Header를 추가한다.
1 | https://loco9939.com:5000 |
요청 받은 서버는 응답 Header에 지정된 ACAO(Access Control Allow Origin) 정보를 실어서 보낸다.
브라우저가 ACAO 정보가 담긴 응답과 요청의 Origin을 비교하여 동일하면 허락한다.
브라우저가 사전요청을 먼저 보낸 후 서버의 응답을 보고 안전한지 확인한 후 본 요청을 보내는 방식이다. 본 요청은 Simple Request 방식과 동일하다.
1 | var http = require("http"); |
Access-Control-Allow-origin 헤더 값으로 * 을 사용하면 모든 Origin에서 오는 요청을 허용한다는 의미이므로 당장은 편할 수 있겠지만, 바꿔서 생각하면 정체도 모르는 이상한 출처에서 오는 요청까지 모두 허용하기 때문에 보안은 더 허술해진다. 그러니 가급적이면 귀찮더라도 다음과 같이 출처를 직접 명시해주도록 하자.
디자인 패턴은 애플리케이션내에서 각자 역할에 맞는 코드끼리 분리하여 유지보수성을 높이고 탄탄한 구조를 가진 애플리케이션을 설계할 수 있다.
디자인 패턴은 소프트웨어 개발의 문제를 해결하는 확실한 접근 방식을 제공한다.
일반적으로 필요에 따라 조정가능하며 즉시 사용가능한 솔루션을 반영한다.
이외의 사소한 문제를 예방할 수 있고 반복을 피하여 파일 크기를 줄일 수 있으며, 개발자간의 소통을 원할하게 하는 장점이 있다.
Model + View + Controller를 합친 용어이다.
1 | 참고 - MVC에서 View가 업데이트 되는 방법 |
polling이란?
하나의 장치가 충돌 회피 또는 동기화를 목적으로 다른 장치의 상태를 주기적으로 검사하여 일정 조건을 만족할 때, 송수신 자료를 처리하는 방식
Model + View + Presenter를 합친 용어이다.
Model + View + View Model을 합친 용어이다.
Command패턴이란?
요청을 객체 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 사용할 수 있도록 메서드명, 매개변수 등 요청에 필요한 정보를 저장,로깅, 취소하는 패턴이다.
참고
페이스북이 전통적인 MVC 디자인 패턴이 복잡한 애플리케이션에서 적합하지 않다고 판단하여 새로운 디자인 패턴을 소개한 것이 바로
애플리케이션 규모가 커짐에 따라
사용자와 상호작용하는 여러 View가 연결된 여러 Model을 업데이트하고 Model 또한 연결된 View를 업데이트하는 매우 복잡한 상황이 발생하기에 데이터 흐름을 예측하기란 매우 어려워진다.
사실 위 그림은 전통적인 MVC 패턴이고 Apple의 MVC 패턴은 사진처럼 Model과 View의 양방향 데이터 흐름이 발생하지 않는다.
문제는 양방향 데이터 흐름이다.
Flux 패턴은 앱의 단방향 데이터 흐름을 촉진하는 시스템 아키텍처를 말한다.
사용자의 요청을 정의한 객체를 말한다.
디스패처는 중앙 데이터 흐름 관리한다. 스토어에 등록된 액션 타입마다 콜백되는 함수가 존재한다.
스토어는 상태(Model)를 관리하는 저장소이며 상태를 변경할 수 있는 콜백을 가진다. 각 액션을 처리하는 콜백함수는 디스패처에 등록된다.
뷰는 사용자와 상호작용하는 컴포넌트이다. 스토어에서 상태가 변경되었다는 알림이 오면 뷰는 리렌더링이 발생한다.
author.bio
author.job