일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- react
- 고득점Kit
- 코테연습
- LeetCode
- Doitvue.js입문
- 프로그래밍
- python
- Level1
- 프로그래머스
- 리트코드
- web
- CS
- 리액트
- C++
- 웹프로그래밍
- Level3
- 자바스크립트
- 카카오
- Level2
- 배열
- Medium
- 파이썬
- sql
- javascript
- dp
- typescript
- OS
- 백준
- 동적계획법
- VUE
- Today
- Total
[기술면접] React, 기타 면접 대비 본문
React
Virtual DOM 작동원리
react는 뒤에서 실제 DOM을 모두 복사해서 virtual DOM을 만든다.
만약 리액트를 이용해서 virtual dom의 어떤 노드를 수정한다면 리액트는 새로운 virtual dom(updated virtual dom)을 만들고 이전 virtual dom 트리와 비교한다.
만약 일치하지 않는 노드를 발견한다면 리액트는 실제 dom 트리에서 해당 노드만 업데이트 시켜준다.
Virtual DOM이란
브라우저의 렌더링 엔진은 DOM 트리가 수정될 때마다 새로운 렌더 트리와 레이아웃을 생성하고 repaint 해야하기 때문에 동적 UI의 경우 성능이 저하될 수 있다. 이러한 이슈를 해결하기 위해 나온 것이 Virtual DOM이다.
- 이전 DOM과 가상 DOM에 있는 내용을 비교하여 바뀐 부분만 실제 DOM에 적용한다.
- react에서는 변경된 부분(diff)만을 계산하여 실제 DOM에 적용한다.
결과적으로 브라우저는 불필요한 렌더링 횟수를 줄이고 한번만 렌더링 할 수 있다.
React를 사용하는 이유
동적인 웹페이지를 효율적으로 유지 보수하고 관리하기 위함
웹 어플리케이션에 동적인 변화가 많이 일어난다면 그만큼 DOM 요소들 또한 변화가 이루어져야 한다는 것과 같다. DOM 요소들이 변화한다는 것은 브라우저의 렌더링 과정이 다시 이루어져야한다는 것이므로 매번 렌더링이 일어난다면 성능이 저하된다.
이를 해결하기 위해 여러 프론트엔드 라이브러리가 탄생하였다.
그 중에서 react는 다음과 같은 이점이 있다.
- component 단위 작성
- UI를 컴포넌트 단위로 조립하기 때문에 생산성과 유지 보수를 용이하게 한다.
- JSX 문법을 제공한다.
- JSX는 리액트에서 HTML와 유사한 문법을 사용할 수 있도록 하는 것으로 요소를 제공해주기 때문에 컴포넌트를 쉽게 구성할 수 있다.
- virtual dom
- 유저의 인터랙션이 일어나면 변화가 일어난 dom 트리의 노드만 교체하기 때문에 효율적이다.
클래스형 컴포넌트와 함수형 컴포넌트 차이
이전에는 클래스형 컴포넌트만 상태값을 가질 수 있었으며 생명 주기 함수를 작성할 수 있었다 하지만 이를 대체할 수 있는 훅이라는 기능이 도입되면서 함수형 컴포넌트에서도 상태값과 생명주기를 관리할 수 있게 되었다.
생명주기 메소드
컴포넌트가 브라우저 상에서 나타날 때, 업데이트 될 때, 사라지게 될 때 호출하는 메소드들이다.
컴포넌트 사이클은 크게 마운트 - 업데이트 - 언마운트 로 이뤄진다.
함수형 컴포넌트에서는 useEffect라는 훅을 이용해서 생명주기 메소드들을 대체한다.
useEffect(callBackFunc); //렌더링 될 때마다
useEffect(callBackFunc, []); // componentDidMount : 최초 렌더링시
useEffect(callBackFunc, [state1, state2]); // 최초 렌더링 + dependencies가 변경 되었을 때
useEffect(()=>{ return(() => func()) }); // componentWillUnmount
Hook 이란
훅이란 함수형 컴포넌트에서 생명주기 기능을 연동할 수 있게 해주는 함수이다.
목적
- 상태 관련 로직을 추상화해 독립적인 테스트와 재사용이 가능해 레이어 변화 없이 재사용할 수있다.
- 컴포넌트를 함수 단위로 잘게 쪼갤 수 있다.
사용 규칙
- 최상위에서만 호출해야한다.
- 리액트 함수 컴포넌트에서만 호출해야한다.
이 규칙을 강제하는 플러그인은 eslint-plugin-react-hooks 으로 create react app에 기본적으로 포함되어 있다.
useState
동적으로 바뀌는 값을 관리할 때 사용하며, 상태 유지 값과 그 값을 갱신하는 함수를 반환한다.
useEffect
리액트 컴포넌트가 렌더링될 때마다 특정 작업을 실행할 수 있도록 하는 hook
state를 직접 바꾸지 않고 useState를 사용하는 이유
state는 컴포넌트 렌더링에 영향을 주는 데이터를 가지고 있는 객체이다. state가 변경되면 컴포넌트들은 다시 렌더링된다. useState나 setState를 사용해 값을 변경하는 이유는 render 함수를 호출하기 위해서이다. state 값이 업데이트 되면 render 함수를 호출해 렌더링을 실행해서 변경된 내용으로 화면은 업데이트 해준다.
useMemo와 useCallback
리액트는 값이 변할 때마다 리렌더링된다. 따라서 의도치 않게 리렌더링이 계속 일어나 성능이 저하될 수 있다. 이를 해결하기 위해서 메모제이션 기법을 사용하는데 대표적인 훅으로 useMemo와 useCallback가 있다.
함수 컴포넌트에서 불필요하게 함수와 객체를 업데이트하는 것을 방지해준다.
useMemo
메모제이션된 객체 값을 리턴한다. 함수가 호출 될 때마다 새로 객체를 생성하는 것이 아니라 dependency의 값이 변경되었을 때만 새로 객체를 생성한다.
useCallback
메모제이션된 함수를 리턴한다. dependency의 값이 변경되었을 때만 새로 함수 생성한다.
리액트 렌더링 성능 향상을 위한 방법
컴포넌트의 리렌더링 되는 조건은 다음과 같다.
- 부모에서 전달 받은 props가 변경될 때
- 부모 컴포넌트가 리렌더링될 때
- 자신의 state가 변경될 때
리렌더링을 줄여 성능을 향상 시키는 방법이 있다.
- useMemo 사용하기
- 컴포넌트가 리렌더링될 때마다 함수가 호출되는 것을 방지한다. 종속 변수들이 변하지 않으면 이전에 반환한 참조값을 재사용 할 수 있도록 한다.
- react.memo 컴포넌트 메모제이션
- 컴포넌트의 props가 바뀌지 않았다면, 리렌더링하지 않도록 설정하여 함수형 컴포넌트의 리렌더링 성능을 최적화 해줄 수 있다.
- useCallback 사용하기
- 함수 선언을 메모제이션할 수 있다.
- 자식 컴포넌트의 props로 객체를 넘겨줄 경우 변형하지 말고 넘겨주기
- 새로 생성된 객체를 전달하면 컴포넌트가 리렌더링될 때마다 새로운 객체가 생성되어 전달되며 새로 생성된 객체는 이전 객체와 다른 참조 주소를 가진 객체이기 때문에 자식 컴포넌트는 메모제이션이 되지 않는다.
- 컴포넌트를 매핑할 때 key 값으로 index를 사용하지 않는다.
- 배열 중간 요소가 변경되면 그 뒤에 요소들도 index가 다 변경되기 때문에
- useState의 함수형 업데이트
- useCallback에 depency 배열을 비울 수 있다.
리액트에서 JSX 문법
JSX란 React에서 HTML을 쉽게 사용할 수 있도록 만든 것이다.
HTML 문법으로 태그를 바로 생성할 수 있어서 편하다.
Context API
context는 React 컴포넌트 트리 내에서 데이터를 글로벌하게 공유하기 위해 설계되었다.
react redux의 provider, styled components의 ThemeProvider 등 많은 라이브러리에서 내부적으로 context를 사용하고 있다.
만약 특정 prop을 멀리 있는 컴포넌트에게 전달하기만을 원한다면, Context 보다는 해당 prop을 사용하는 컴포넌트 자체를 전달하는 방식이 종종 더 간단한 해결책이 된다.
Redux
리덕스 쓰는 이유
Props 문법 귀찮을 때
상위 컴포넌트에서 state를 하위 컴포넌트로 전달해주기 위해서는 props를 써야한다. 만약 하위 컴포넌트가 여러개 중첩되어 있을 경우 많은 단계를 거쳐서 props를 내려보내줘야하기 때문에 상당히 귀찮다.
리덕스를 설치하면 store라는 파일에 state를 보관하고 모든 컴포넌트들이 props 쓰지 않고 이를 가져다 쓸 수 있다.
상태 관리가 용이하다.
각 컴포넌트들이 동일한 state를 각각 변경하는 기능을 한다고 했을 때, 버그가 일어나면 각각의 컴포넌트들을 다 찾아봐야 한다. 이때 redux를 사용하면 reducer를 사용해서 각각의 경우에 대해 조건 별로 기능을 구현하여 모아놓을 수 있다.
각각의 컴포넌트들은 직접 state를 수정하는 것이 아니라 조건(action.type)과 함께 store에 state 변경을 요청한다. 이때 요청은 dispatch 함수를 통해 이루어진다.
즉 state를 수정하는 것을 한 곳에서 관리가 가능해지기 때문에 버그 추적 및 수정이 쉬워진다.
redux가 전역적인 상태 관리에 좋긴 하지만 간단한 앱에서는 도리어 코드의 복잡도만 올릴 뿐 생산성에 도움이 되지 않는 경우도 있다.
기타
TypeScript 특징
- 컴파일 언어, 정적 타입 언어
- 런타임에서 타입이 결정되고 오류가 발견되는 자바스크립트와 달리 타입스크립트는 정적 타입의 언어이며 컴파일러 또는 바벨을 통해 자바스크립트 코드로 변환된다.
- 코드 작성 단계에서 타입을 체크해 오류를 확인할 수 있고 미리 타입을 결정하기 때문에 실행 속도가 빠르다는 장점이 있다.
- 코드 작성시 매번 타입을 결정해야 하기 때문에 번거롭고 코드량이 증가하며 컴파일 시간이 오래 걸린다는 단점이 있다.
- 자바스크립트 슈퍼셋
- 자바스크립트 기본 문법에 타입스크립트의 문법을 추가한 언어이다.
- 객체 지향 프로그래밍 지원
- 타입스크립트는 ES6에서 새롭게 사용된 문법을 포함하고 있으며 클래스, 인터페이스, 상속, 모듈 등과 같은 객체 지향 프로그래밍 패턴을 제공한다.
TypeScript를 사용하는 이유
- 높은 수준의 디버깅
- 코드에 목적을 명시하고 목적에 맞지 않는 타입의 변수나 함수들에서 에러를 발생시켜 버그를 사전에 제거한다. 또한 코드 자동 완성이나 실행 전 피드백을 제공하여 작업과 동시에 디버깅이 가능해 생산성을 높일 수 있다.
- 자바스크립트 호환
- 강력한 생태계
- 점진적 전환 가능
- 기존의 자바스크립 프로젝트를 타입스크립트로 전환하는데 부담이 있다면 추가 기능이나 특정 기능에만 타입스크립트를 도입함으로써 프로젝트를 점진적으로 전환할 수 있다.
https://www.samsungsds.com/kr/insights/TypeScript.html
type, interface 공통점과 차이점
interface는 객체나 함수의 타입을 지정할 때 사용하는데 주로 객체에 사용된다.
함수의 경우는 주로 타입을 사용한다.
Interface
인터페이스는 객체의 타입을 지정하기 위해 사용된다.
interface Person {
name: string;
hungry: boolean;
}
const me: Person = {
name: 'Harry',
hungry: false,
}
class Harry implements Person {
name: string;
hungry: boolean;
}
interface Greeting {
(name: string) : string;
}
const myGreeting: Greeting = (name: boolean) => 'Hello!';
인터페이스는 확장될 수도 있다.
interface Harry extends Person {
youtuber: boolean;
}
인터페이스는 선언 병합 decoration merging을 지원한다.
따로 선언해도 하나로 통일해줌
interface Person {
name: string;
hungry: boolean;
}
interfcae Person {
youtuber: boolean;
}
type
//type : 타입을 직접 지정해주고 컴파일 시점에 에러를 잡아낼 수 있다.
type Hungry = boolean;
type Greeting = (name: string) => string;
const harry: Hungry = 'true';
// type alias : default 값을 지정할 수 있다.
type Person = {
name: string;
hungry: boolean;
}
// union, intersection
type Youtuber = {youtuber: boolean};
type Harry = Person | Youtuber;
type lee = Person & Youtuber;
const harry: Harry = {
youtuber: boolean;
}
generics
클래스나 함수, 인터페이스를 다양한 타입으로 재사용할 수 있다. 선언할 때는 타입 파라미터만 적어주고 생성하는 시점에 타입을 결정한다.
매개 변수의 타입을 바꿔서 함수를 재사용하고 싶다면 오버로드를 사용하던지 제네릭을 사용할 수 있다.
function getSize<T>(arr: T[]): number { // 타입 파라미터 T를 명시
return arr.length;
}
// 사용하는 쪽에서 타입을 명시한다.
const arr1 = [1, 2, 3];
getSize<number>(arr1); // 3
const arr2 = ['1', '2', '3'];
getsize<string>(arr2); // 3
인터페이스에서 사용하는 경우
interface Mobile<T> {
name: string;
price: number;
option: T;
}
const m1: Mobile<{color: string; coupon: boolean}> = {
name: "s21",
price: 1000,
option: {
color: "red",
coupon : false,
}
};
const m2: Mobile<string> = {
name: "s20",
price: 900,
option: "option",
}
타입 매개변수의 확장
interface User [
name: string;
age: number;
]
interface Car {
name: string;
color: string;
}
interface Book {
price: number;
}
const user: User = {name: "a", age: 10};
const car: Car = {name: "bmw", color: "red"}
const book: Book = {price: 3000};
function showName<T extends {name: string}>(data: T): string {
return data.name;
}
showName(user);
showName(car);
showName(book); // error
장점
- 코드의 가독성을 올려준다.
- 유지보수, 리팩토링 등이 용이해진다.
- 자바스크립트 사용자가 습득하기 쉽다.
- 타입과 관련된 에러를 컴파일 단계에서 잡아준다.
- OOP를 지원한다.
단점
- 진짜 정적 타이핑이 아니다. 컴파일 후에는 자바스크립트로 변환되기 때문에 런타임에서 여전히 타입 에러 가능성이 있다.
- 타입 선언 및 사용을 위해 코드 작성을 더 해야한다.
필수 문법
let name : string = 'name'//일반 변수
let name : stinrg[] = ['park', 'kim'] // 배열 배열 내부 타입 []
let name_obj : {name: string} = {name: 'kim'} // 오브젝트, ?를 붙여서 옵션으로 지정할 수도 있다.
let name : string | number = 123; // 다양한 타입으로 지정할 때 union type
//type alias를 사용해 타입들을 변수에 담아 사용할 수 있다.
type Name = string | number;
let name : Name = 123;
//함수 타입 지정
function 함수(x: number) : number {
return x * 2
}
// tuple type 배열에 각 순서 별로 타입을 지정
type Member = [number, boolean];
let john: Member = []
// object에 타입 지정해야할 속성이 너무 많으면
type Member = {
[key: string] : string, //글자로 된 모든 object 속성 타입은 : string
}
let john : Member = {name : 'kim'};
// class 타입 지정 가능
class User {
name :string
constructor(name :string) {
this.name = name;
}
}
제이쿼리
제이쿼리 웹사이트에서 자바스크립트를 쉽게 활용할 수 있도록 해주는 오픈 소스 기반의 자바스크립트 라이브러리이다.
장점
- 웹 페이지 상의 엘리먼트 찾기와 조작이 쉽다
- 호환성이 뛰어나다
- 메소드 체이닝 등 짧고 유지관리가 용이한 코드를 작성할 수 있다.
- ajax 함수를 제공해 비동기 통신 작성을 쉽게 지원해준다.
- 정적이고 가벼운 웹 페이지를 신속하게 제작하는데 용이하다
더 이상 사용하지 않는 이유
웹 표준 API 확장
웹 표준이 발전하면서 기본적으로 제공하는 편의 기능도 발달했다. JQuery().ajax() 메소드를 사용해야만 했던 예전과 달리 fetch API를 기본적으로 제공하면서 jquery를 쓰지 않아도 되게 됐다.
웹브라우저 환경의 변화
렌더링 엔진을 탑재한 크롬은 빠른 버전 업그레이드를 위해 웹 표준을 신속하게 반영하였고 그 결과 제이쿼리와 같은 라이브러리를 사용하지 않고도 양질의 웹 애플리케이션 구현이 가능해졌다.
가상 돔(Virtual Dom)을 사용하는 라이브러리의 등장
웹페이지는 브라우저 상에서 돔이라는 표준 형식으로 파싱되어 표현된다. 따라서 사용자 조작에 맞춰 동적으로 변화하는 대화형 웹을 구현하기 위해서는 돔 조작이 필수적이다. 하지만 브라우저에서 돔 조작이 발생할 때마다 배치나 표시에 많은 연산을 발생시키다보니 성능이 낮아지는 문제가 있었다.
이를 해결하기 위해서 자바스크립트 라이브러리 중 하나인 리액트는 가상 돔을 채용하여 대중화시켰고 성능이 뛰어나고 화려한 웹 페이지를 비교적 손 쉽게 제작할 수 있도록 했다.
리액트는 메모리에 가상 돔을 구성하여 실제 돔과의 차이점을 비교하고 변경된 부분을 실제 돔에 적용할 수 있기 때문에 효율적이다.
따라서 돔을 직접 조작하는 제이쿼리의 필요성이 줄어들게 되었다.
참고 :
https://www.samsungsds.com/kr/insights/jQuery.html
'CS > 면접 대비' 카테고리의 다른 글
[기술면접] 기초개발 상식, 웹 면접 대비 (0) | 2022.05.11 |
---|---|
[기술면접] 데이터베이스 면접 대비 (0) | 2022.05.10 |
[기술면접] 프론트엔드 면접 대비 (자바스크립트) (0) | 2022.05.09 |
[기술면접] 운영체제 면접 대비 (0) | 2022.05.07 |
[기술면접] 네트워크 면접 질문 대비 (0) | 2022.05.06 |