React는 메모리에 Virtual DOM(가상돔)을 생성하고 이를 활용하여 이벤트가 발생할 때 마다 실제 DOM과 상태를 비교하여 변경이 필요한 최소한의 변경 사항만 실제 DOM에 반영하여 렌더링되기 때문에 렌더링 효율성이 좋다. 이러한 특징으로 유저와 상호작용하는 동적인 웹페이지 개발 시 자주 채택된다.
2. Data Flow
Data Flow(데이터 방향)는 한 방향으로 흐르는 단방향이다. 데이터흐름이 양방향인 경우 어플리케이션의 규모가 커질 수록 데이터의 흐름을 추적하기 힘들고 복잡해지는 경우가 발생한다. 이와 달리 단방향으로 개발된 어플리케이션은 데이터를 추적하기 수월하고 변화에 대한 예측이 가능하여 디버깅이 쉬운 장점이 있다.
3. JSX를 활용한 컴포넌트 개발
React를 사용할 때 필수적인 요소는 아니지만 보편적으로 필수적 요소처럼 사용되고 있다. 개인적인 견해로 JSX를 활용하였을 때 가장 큰 장점으로는 "개발의 생산성의 증대"라고 생각한다. JS코드내에서 즉시 UI구현 작업이 가능하고 가독성 또한 좋아지기 때문이다.
4. Props & State
Props는부모 컴포넌트에서 자식 컴포넌트로 전달해 주는 데이터를 의미하며 readonly 타입의 데이터이다. props는 변경이 불가능한 불변데이터이고 props를 전달해 준 최상위 부모 컴포넌트에서만 props를 변경할 수 있다.
State는컴포넌트 내부에서 선언하여 값을 변경할 수 있어 동적인 데이터를 다룰 때 주로 사용된다. 사용자와 상호작용을 통해 데이터를 동적으로 변경할 때 사용되며 각각의 state는 독립적인 데이터이다.
5. Hooks
React가 함수형 컴포넌트를 표준으로 제공하면서 생긴 개념으로, React state와 Life cycle을 연동할 수 있게 해주는 함수를 뜻한다. 대표적으로 useState, useEffect, useCallback, useMemo 등이 있다.
마치며...
지금 껏 개발에 대한 포스팅을 해오며 돌이켜 생각해보면 react훅을 제외하면 나의 주력인 react에 관한 포스팅이 단 하나도 없다는 것이 조금 놀라웠다. 기술에 대한 이론적 역량을 보완하기 위해 react의 개념을 복기하며 포스팅하였고 알고 있더라도 포스팅을 하고 안하고의 차이는 꽤 크니 앞으로 꾸준히 노력하며 포스팅해야겠다.
// 기본적으로 활용하는 방식
let arr = ["Ze", "Riong"];
let [firstName, surname] = arr;
console.log(firstName); // Ze
console.log(surname); // Riong
// 필요하지 않은 데이터는 , 를 사용해서 건너뛰기가 가능하다.
let array = ["A", "B", "C", "D", "E"];
let [a, , c, ,e] = array;
console.log(a) // "A"
console.log(c) // "C"
console.log(e) // "E"
// 할당 연산자 우측에 배열 뿐 아니라 모든 이터러블(반복 가능한 객체)이 올 수 있다.
let [a, b, c] = "all";
let [on, tw, th] = new Set([1, 2, 3]);
console.log(a, b, c) // a l l
console.log(on, tw, th) // 1 2 3
이렇게 구조 분해 할당에 대해 이해했다면 대충 감이 올 수도 있다.
아래 예제 코드를 통해 어떻게 변수 값을 교환할 수 있는지 알아보자.
구조 분해 할당을 활용한 변수 값 교환
변수는 이터러블 구조가 아닌데 어떻게 구조 분해 할당을 활용할까?
답은 간단하다. 변수를 배열에 넣어 이터러블하게 만들고 재할당하는 방식이다.
백문이 불여일견!
let str = "string";
let num = 230;
console.log(str) // "string";
console.log(num) // 230;
// 배열 내부에 변수를 넣어 이터러블 구조를 만들고 swap
[str, num] = [num, str];
console.log(str) // 230;
console.log(num) // "string";
마치며...
운이 좋게 서류합격을 하고 기술 면접을 보았는데 두 변수의 값을 서로 할당해주기 위한 방법을 서술해보라는 질문이 있었다. 나는 올드한 방식으로 새로운 변수를 선언하고 값을 할당하는 방식으로 설명하였고 면접이 끝나고 찾아보니 구조분해할당을 활용하는 트렌드한 방법이 존재했었다... 분명 당시의 질문 의도는 이러한 방식을 활용한 변수 값 교환에 대해서 설명하길 바랐을 것이다. 앞으로도 좀 더 다양한 방식에 대한 자료를 찾고 이해하기 위해 노력해야겠다.
클라이언트가 요청할 때마다 필요한 정보를 보내주기 때문에 세션 정보를 보관할 필요가 없어 서비스의 자유도가 높아지고 유연한 아키텍처 적용이 가능하다.
HTTP 메서드를 사용한다.(GET, POST, PUT, DELETE 등)
서비스 내의 자원은 연관된 자원들과 연결되어 표현되어야한다.
REST는 HTTP메서드를 통해 자원을 처리하도록 설계된 아키텍처이다.
REST의 구성 요소
자원(Resource)
모든 자원은 서버에 존재하며 고유 ID를 가지고 있으며,
자원의 위치를 식별하는 URI(Uniform Resource Identifier)를 통해
자원에 접근할 수 있다.
메서드(Method)
GET: 리소스를 조회
POST: 리소스를 생성
PUT: 리소스를 전체 수정
PATCH: 리소스를 일부 수정
DELETE: 리소스를 삭제
메시지(Message)
HTTP header, body, 응답 상태 코드 등으로 구성되어 있다.
header: body에 어떤 형식으로 데이터가 담겼는지 표시
body: 자원에 대한 정보를 JSON, XML 등으로 전달
응답 상태 코드는 200 ~ 500 사이의 숫자로 클라이언트의
요청에 대한 상태를 나타낸다.
REST의 특징
1. Server-Client 구조
클라이언트는 자원을 요청하고 서버는 자원을 가지고 있으며
API를 제공하여 비즈니스 로직처리 및 저장을 책임진다.
2. Stateless(무상태)
HTTP는 무상태이며 REST는 HTTP를 기본으로 하기 때문에 무상태이다.
클라이언트의 상태(State)를 서버에 저장하지 않는 것을 무상태라고 표현하고
서버에서 클라이언트의 요청을 완전히 별개의 것으로 인식하고 처리한다.
따라서 이전의 요청이 다음의 요청에 연관되지 않고 처리 방식에 일관성을
부여하고 부담이 줄어든다.
3. Cacheable(캐시 처리 가능) HTTP의 캐싱 기능을 적용할 수 있어 대량의 요청을 효율적으로 처리할 수 있다.
캐시를 활용하여 응답 시간이 빨라지고 성능, 서버의 자원 이용률을 향상할 수 있다.
4. Layered System(계층화) 클라이언트는 REST API 서버만 호출하며 REST 서버는 다중 계층 구성이 가능하다.
API 서버는 순수 비즈니스 로직을 수행하고 이의 앞단에서 보안, 로드 밸런싱, 암호화,
사용자 인증 등을 활용해 구조에 유연성을 줄 수 있다.
5. Code-On-Demand 서버로부터 스크립트를 받아서 클라이언트에서 실행한다.
(필수 요건 아님)
6. Uniform Interface(인터페이스 일관성) URI를 통해 자원 조작을 통일되고 한정적인 인터페이스로 수행한다.
HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하며 특정
언어나 기술에 종속되지 않는다.
REST API의 장단점
장점
독립적인 언어와 플랫폼
REST API 메시지를 통해 의도를 쉽게 파악 가능
REST가 지원하는 프레임워크나 언어 등 없이 구현 가능
HTTP로 기존 웹 인프라를 사용 가능
서버와 클라이언트의 역할을 명확하게 분리
다양한 서비스 디자인에서 생길 수 있는 문제 최소화
단점
표준이 존재하지 않음(보안, 정책 등)
HTTP프로토콜만 사용 가능
마치며...
얼마 전 회사에 서류합격을 통지받고 면접을 볼 수 있는 기회가 있었다. 지금껏 개발을 해왔지만 정작 이론에 대한 부분은 약하다는 것을 느끼게 되었고 면접결과 역시 좋지 못했다. 한번에 잘 되리라 생각하진 않았지만 생각했던 것 보다 모르는 이론이 너무나도 많았던 것 같다... 기술면접에서 REST API의 특징을 말하는 부분에서 시원하게 답변하지 못했고 이 포스팅을 시작으로 이론공부도 꾸준히 해야겠다!
캐럿브라우징을 포스팅하게 된 이유는 개발을 하는 과정에서 live-server로 띄운 웹페이지의 텍스트영역에 지속적으로 커서가 생기는 현상에 당황스러웠고 처음에는 코드의 문제로 버그가 발생하는 줄 알고 몇분간 삽질을 한 경험이있었다. 이 후 키보드가 잘못 눌렸을 때 문제가 발생했고 해당 브라우저에서 띄운 모든 페이지가 커서를 띄우는 것을 확인 후 캐럿 브라우징에 대해 알게되었다... 혹시 캐럿브라우징 기능이 필요할 수도 있고 같은 실수를 했을 때 당황하지 않고 대처하기 위해 포스팅했고 앞으로도 경험해야 할 문제들도 발단부터 검증하면 분명 해결할 수 있을 것이라는 믿음이 더 강해졌다.
코드를 축소하여 최적화하고 사용하지 않는 코드를 제거하여 빌드하는 방식으로 성능을 최적화할 수 있다.
CSS가 아닌 SASS 혹은 stylus, Typescript 사용 시 컴파일 과정에서 필요 플러그인을 추가하고 번들러를 실행해준다.
종속성 문제의 해결
Webpack의 단점
일부 패키지들을 loader를 통해 매번 추가해주어야 하며 추가하고자 하는 자원의 타입에 따라 추가해 주어야 하는 loader가 다를 수 있기 때문에 러닝커브가 다소 있는 편이다.
Install
# 웹팩, 개발자 서버 인스톨
npm i -D webpack webpack-dev-server
# 필요한 플러그인 및 로더 설치 (css, sass, static copy plugin, env 등)
npm i -D html-webpack-plugin dotenv-webpack css-loader copy-webpack-plugin cross-env source-map-loader sass-loader clean-webpack-plugin
웹팩(개발자 서버 포함)과 필요한 로더와 플러그인을 설치한다.
webpack.config.js 분리
html / css / vanillaJS 구성으로 웹팩 적용하였으며 config 작성할 때 common, dev, prod로
나누어 빌드환경에 맞춰 별도로 관리해주었다.
webpack.common.js
공통으로 적용 될 config를 작성한다.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const DotEnv = require('dotenv-webpack');
module.exports = {
entry: {
main: path.resolve(__dirname, '../src/script.js'),
},
output: {
path: path.resolve(__dirname, '../public'),
filename: '[name].min.js'
},
// target: ['web', 'es5'], // es5 환경 작업 시 사용
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
enforce: 'pre',
use: ['source-map-loader'],
},
{
test: /\.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(glb|gltf)$/,
use: ['file-loader']
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/index.html'),
filename: 'index.html',
minify: true,
}),
// origin 그대로 복사할 파일을 지정
new CopyWebpackPlugin({
// 빌드 시 public 폴더에 자동 생성(patterns 경로에 해당 파일이 없으면 에러발생)
patterns: [
{ from: path.resolve(__dirname, '../static') },
{ from: path.resolve(__dirname, '../src/style.css') },
]
}),
// dotenv-webpack패키지를 통한 환경변수(env) 사용
new DotEnv({ path: '.env' }),
]
};
다수의 Mesh, Light, Group, Object3D, Camera로 이루어진 트리 구조이다.
배경색, 안개, 다수의 오브젝트, 빛, 질감 등을 표현하는 화면이다.
Scene은 최상위 노드이기 때문에 객체의 위치와 방향이 부모(Scene)기준이다.
Camera
Camera는 다른 구성 객체와는 달리 Scene 그래프에 포함되지 않으며
Scene객체를 촬영하여 어떻게 보여줄 것인가를 결정하는 역할을 한다.
Light
여러 종류의 광원을 말하며 이는 즉 조명을 뜻한다.
AmbientLight, SpotLight, DirectionalLight 등 다양한 광원을 활용하여
Scene에 존재하는 다양한 3D요소들을 3D 공간 공간에서 볼 수 있다.
Geometry
3D요소의 모양을 정의할 수 있으며 내장객체 또는 파일을 통해 형상을 만들 수 있다.
Material
질감을 뜻하며 표면의 색상, 투명도, 질감을 나타낼 수 있다.
Mesh(Object3D)
Mesh는 특정 Material의 속성을 가진 Geometry를 그리는 객체이다.
Mesh는 3D공간 상의 위치와 특정 기준 축 회전 등을 결정할 수 있으며
Material과 Geometry는 재사용이 가능하여 여러 Mesh가 특정
Material, Geometry를 동시 참조 가능한 특징이 있다.
마치며...
오늘은 Three.js의 기본 구성과 개념에 대한 포스팅만을 진행했지만 현재 Three.js를 사용한 프로젝트가 완성에 가까워졌고 완성된이후에Three.js에 대한 추가 포스팅을 진행할 예정이다. 언제나 개발을 통해 기능을 구현하는 것도 중요하지만 가장 중요한 것은 사용한 기술에 대한 개념, 원리를 명확히 이해하고 있는 것이라 생각하고 있고 나에게는 하나의 원칙이기도 하다. 앞으로도근거 있는기술의 사용과 검증 가능한 코드를 지속하기 위해 더 나은 노력할 것이다.
Import Git Repository에서 git계정을 연결하여 저장소의 프로젝트들을 가져온다.
Import를 눌러 deploy(publishing)를 진행한다.
위와 같이 프로젝트 이름을 설정하고 프레임워크를 동일하게 설정해준다.
유의사항
프로젝트를 진행할때 특정 API-key를 사용해서 통신을 해야하는 경우가 아주 많다.
그러한 API-key는 분명 유출시 위험성이 있기 때문에 .env파일에 환경변수로 사용했을 것이고
Github에도 업로드 되지 않게 했을 것이다.vercel에서 파일을 배포할때 Github의 레포지토리를
기준으로 배포하기 때문에 vercel은 환경변수를 알 수 있는 방법이 없다. 그렇기 때문에 반드시
Environment Variables 텝을 눌러 개발환경과 동일한 변수명과 동일한 API-key를 넣어주어야 한다.
만약 API-key와 같은 환경변수의 값이 입력되지 않는다면 배포가 성공해도 status 500 에러가 발생한다.
환경변수를 모두 Add를 눌러 추가하고 마지막으로 Deploy를 눌러주면 배포가 완료된다.
마치며...
유의사항이라고 큼직하게 환경변수 적용에 대해 적어 두었지만 사실 너무나 당연한 것이다. 나는 환경변수에 대해서 떠올리지 못했고 500에러를 마주하며 좌절했었다. 너무 당연하게 개발환경에서 많은 시간을 투자해서 개발을 하다보니 익숙하지 않은 환경에서 무언가를 시도한다는 것은 그런 당연한 것을 쉽게 망각하기도 하는 것 같다. 역시 경험은 성장에서 빼놓을 수 없는 중요한 요소인 것을 다시금 깨닫는 시간이었다.