이벤트와 상태 변화가 많아질수록 DOM 업데이트 규칙이 복잡해지고 관리가 어려워지며 유지보수가 힘들어짐
리액트의 독창적 접근과 Virutal DOM
상태 변화시에 DOM 업데이트 규칙을 정하는 것이 아니라, 아예 다 날려버리고 처음부터 모든걸 새로 만들어서 보여준다면 어떨까? 라는 아이디어에 시작했다. 하지만, 전체를 새로 렌더링하면 성능이 문제갈 될 수 있다.
Virutal DOM을 도입하여 해당 문제를 해결.
실제 DOM 대신 메모리에 존재하는 가상 DOM을 사용하며 상태 변환 시, Virtual DOM에 새 UI를 렌더링하고 실제 DOM과 비교하여 변경된 부분만 업데이트 (선택적 수정이 가능)
이를 통해 성능 문제를 해결하면서도 간단한 개발 환경을 제공.
작업환경 준비
Node.js : Webpack과 Babel 같은 도구를 실행하기 위한 자바스크립트 런타임.(Webpack: 여러 파일로 나뉜 컴포넌트를 하나의 파일로 묶는 역할을 수행. Babel: JSX와 최신 자바스크립트 문법을 브라우저가 이해할 수 있도록 변환하는 역할)
Yarn (선택): npm보다 빠르고 효율적인 패키지 매니저.
Git Bash (윈도우 전용): 터미널 환경 제공
npx create-react-app begin-react 다음 명령어를 실행하는 과정에서 제대로 수행되지 않는다면 node.js 설치 후, Windows 환경 변수에 npm 경로가 등록되지 않아서 npx를 사용할 수 없기 때문에 발생한다. 이를 해결하기 위해서는 환경 변수에 들어가서 C:\Program Files\nodejs\를 직접 추가해 줘야 한다.
React Component
컴포넌트 생성 : Hello.js 파일에 리액트 컴포넌트를 작성
import React from 'react'; function Hello() { return
안녕하세요
; } export default Hello;
컴포넌트 사용 : App.js에서 Hello 컴포넌트를 불러와 사용, 여러번 사용할 수 있으면 재사용성이 높다.
import React from 'react'; import Hello from './Hello'; function App() { return (
); } export default App;
리액트 컴포넌트 렌더링 : 리액트에서 작성한 컴포넌트가 브라우저 화면에 나타나는 것은 ReactDOM.render 가 해당 컴포넌트를 DOM에 "그려주는" 과정 덕분입니다.
import React from 'react'; import Hello from './Hello'; function App() { return (
); } export default App;
JSX
JSX는 리액트에서 생김새를 정의할 때, 사용하는 문법이다. JS문법을 따른다. JSX가 JS로 제대호 변환이 되려면 지켜주어야 하는 몇가지 규칙이 있다.
꼭 닫혀야 하는 태그 : 태그 열었으면 반드시 태그를 닫아줘야 한다. HTML에서는 input, br 태그를 사용할 때 닫지 않고 사용하기도 한다. 하지만 리액트에서는 그렇게 하면 안된다.
태그는 반드시 감싸져야 함 : JSX의 모든 태그는 하나의 부모 태그로 감싸야 한다.
JSX안에 자바 스크립트 값 사용하기 : JSX 내부에 자바스크립트 변수를 보여줘야 할 때에는 {}으로 감싸써 보여준다. import './App.css'; import React from 'react'; import Hello from './Hello'; function App() { const name = "react"; return (
{name}
); } export default App;
Style과 className : JSX에서 태그에 style과 CSS class를 설정하는 방법은 HTML에서 설정하는 방법과 다르다. 인라인 스타일은 객체 형태로 작성해야 하며, background-color 처럼 -로 구분되는 이름들은 backgroundColor처럼 camelCase 형태로 네이밍 해주어야 한다.
주석 작성 : JSX 내부의 주석은 {/* 이런 형태로 /} 작성합니다.
props를 통해 컴포넌트에게 값 전달
props : props는 properties의 줄임말로서 우리가 어떤 값을 컴포넌트에게 전달해줘야 할 때, props를 사용한다. 간단하게 부모 컴포넌트(APP)에서 자식 컴포넌트(Hello)로 값을 전달할 때 사용한다.
props사용법 : 자식 컴포넌트(Hello)에서 props를 파라미터로 받아 값을 사용한다.
function Hello(props) { return
안녕하세요 {props.name}
; }
여러 개의 props 및 비구조화 할당 : props에 여러 값을 전달할 수 있으며, 비구조화 할당으로 코드를 간결하게 작성 가능하다.
App.js (부모 컴포넌트)
function Hello({ color, name }) { return <div style={{ color }}>안녕하세요 {name}
; }
Hello.js (자식 컴포넌트)
function Hello(props) { return <div style={{ color: props.color }}>안녕하세요 {props.name}
}
Hello.js (비구조화 할당) : 함수의 인자값을 하나하나 직접 정의 해준다고 보면 된다. 코드는 더 간결해진다.
function Hello({ color, name }) { return <div style={{ color }}>안녕하세요 {name}
}
defaultProps로 기본값 설정 : 만약 부모 컴포넌트에서 별도의 컴포을 props에 할당하지 않는 경우 자식 컴포넌트에서 기본값을 지정하여 할당 할 수도 있다.
Hello.js
import React from 'react'; function Hello({ color, name }) { return <div style={{ color }}>안녕하세요 {name}
조건부 렌더링 : 조건부 렌더링이란, 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미한다. 다음 코드는 isSpecial이라는 props를 설정하여 해당 값이 true인지 false인지에 따라서 별표를 화면에 출력하는지를 결정한다. true는 js값으로 이를 사용하기 위해서는 부모 컴포넌트에서 {}값을 감싸줘야 한다. 또한, 삼항연산자를 통해서 조건문을 구현할 수 있다. ```JSX import React from 'react';
onChange라는 이벤트를 사용하여 이벤트 객체 e를 파라미터로 받아와서 사용할 수 있다. 이 객체의 e.target은 이벤트가 발생한 DOM인 inputDOM을 가리킨다. 이 DOM의 값은 e.target.value를 통해서 확인할 수 있다.
여러개의 input 상태 관리하기
input이 여러개일때는 단순히 useState를 여러번 사용하고 onChange도 여러개 만들어서 구현할 수 있습니다. 하지만 이러한 방법보다 좋은 방법이 있다.input에 name을 설정하고 이벤트가 발생했을 때 이 값을 참조하는 것이다. 그리고 useState에서는 문자열이 아니라 객체 형태의 상태를 관리해주어야 한다.
import React, { useState } from 'react';
function InputSample() {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
리액트 상태에서는 객체를 수정할 때 직접 수정하면 안된다. 그 대신에 새로운 객체를 만들어서 새로운 객체에 변화를 주고, 이를 사용해야 한다.
이러한 작업을, "불변성을 지킨다" 라고 부릅니다. 불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리렌더링이 진행됩니다. 만약에 inputs[name] = value 이런식으로 기존 상태를 직접 수정하게 되면, 값을 바꿔도 리렌더링이 되지 않습니다.