React는 사용자 인터페이스를 구축하기 위한 선언적이고 효율적이며 유연한 JavaScript 라이브러리입니다. “컴포넌트”라고 불리는 작고 고립된 코드의 파편을 이용하여 복잡한 UI를 구성하도록 돕습니다.
React는 사용자 인터페이스 개발을 위한 META에서 만든 JavaScript 오픈소스 라이브러리이다. Node 서버에서 렌더링이 가능하며 React Native를 사용하여 모바일 애플리케이션도 개발할 수 있다. 현재 가장 인기가 많은 JavaScript 라이브러리 중 하나이며, 그에 따라 큰 개발자 생태계를 갖고 있다. React는 선언형이며, 컴포넌트 기반이라는 특징을 갖는다.
애플리케이션의 각 상태에 대한 간단한 뷰만 설계하세요. 그럼 React는 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링합니다.
React는 선언형 프로그래밍 방식을 채택하여 동작 방식만 정의해주면 React가 동작 방식에 따라 뷰의 내용을 렌더링한다. 컴포넌트 내에서 선언되고 관리되는 값인 상태에 따라 React가 변경 내역에 따라 어떻게 동작할 지 선언한 내용을 따라 효율적으로 UI에 반영해주는 것이다. 아래는 선언적 프로그래밍 방법을 이용한 React의 Counter 예시 코드이다.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { counts: 0 };
}
countIncrease = () => {
this.setState({ counts: this.state.counts + 1 });
};
render() {
return (
<div>
<h1>Count: {this.state.counts}</h1>
<button onClick={this.countIncrease}>Click me</button>
</div>
);
}
}
Counter
라는 컴포넌트는 상태(state)로 counts
를 가지며 0을 초기값으로 한다. 컴포넌트는 state counts
를 나타내는 부분과 클릭할 때마다 countIncrease
를 호출하는 버튼을 갖는다. 컴포넌트 내에서는 countIncrease
라는 함수가 있으며, 호출될 때마다 컴포넌트의 상태 중 counts
를 1 증가시키는 작업을 수행한다. state가 변경될 때마다 어떤 작업을 수행하는지, counts
의 값이 바뀔 때마다 어디를 변경하는지에 관한 부분은 없지만 버튼을 클릭할 때마다 "Count: " 옆의 숫자가 1씩 증가하는 것을 확인할 수 있다. 상태와 그의 변경만을 선언해주면 React가 컴포넌트에 최신 상태로 반영해주는 것이다.
스스로 상태를 관리하는 캡슐화된 컴포넌트를 만드세요. 그리고 이를 조합해 복잡한 UI를 만들어보세요.
React는 컴포넌트라고 불리는 작고 고립된 코드의 파편을 이용하여 복잡한 UI를 구성하는 방식을 사용한다.
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
위의 코드에서 shopping-list
가 React 컴포넌트 클래스 또는 React 컴포넌트 타입이 되는 것이다.개별 컴포넌트는 'props'라는 매개변수를 받아오고, render
함수를 통해 표시할 뷰 계층 구조를 반환한다. 아래는 위에서 만든 카운터 컴포넌트를 조합해 카운터들을 나타내는 웹 페이지를 만든 예시이다.
Counter
라는 컴포넌트는 상태로 counts
를 가지며, 매개변수 props를 통해 initialValue
와 step
을 받는다. 각 Counter
는 initialValue
의 값을 이용해 counts
를 초기화한다. 그리고 버튼의 클릭 이벤트가 발생할 때마다 props의 step
을 이용해 counts
의 값을 증가시킨다. props는 위의 코드처럼 임의로 지정해줄 수도 있으며, 컴포넌트 간의 통신을 위해 각 컴포넌트의 값을 참조할 수도 있다.
위의 예시에서 버튼을 누를 때마다 step
의 값을 1씩 증가시키는 버튼을 추가한 것이다. 여기서 App
은 state로 배열 [1, 3, 5]
라는 값을 가지며 이 값들을 props로 전달하여 Counter
를 렌더링한다. Counter
컴포넌트는 전달받은 step
프로퍼티를 사용하여 상태 값을 관리하면서 버튼을 클릭할 때마다 상태 값을 업데이트한다. 또한, App
의 최하단에 있는 버튼에는 자신의 state step
의 모든 원소들을 1씩 증가시키는 역할을 갖는다. 버튼을 누를 때마다 step
의 원소들의 값이 증가하고 Counter
컴포넌트는 증가한 값들을 참조하여 렌더링한다. 부모 컴포넌트에서 상태 값을 변경하고 자식 컴포넌트로 전달하여 컴포넌트 간 통신을 하는 것이다.
const element = <h1>Hello, world!</h1>;
React는 .jsx
를 사용한다. JavaScript를 확장한 문법으로 JavaScript 코드 안에 XML과 비슷한 구조를 사용하여 컴포넌트의 뷰를 표현한다. JSX로 작성된 코드는 번들링 과정에서 babel을 통해 JavaScript 코드로 변경된다. React는 jsx의 사용을 필수로 하지는 않지만, JavaScript 코드 안에서 UI 관련 작업을 할 때 가독성이 뛰어나고 React가 더욱 도움이 되는 에러 및 경고 메시지를 표시할 수 있게 해준다.
JSX에서 사용하는 문법 규칙은 다음과 같다.
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
JSX는 {…} 안에 유효한 모든 JavaScript 표현식을 넣을 수 있다. 위의 코드는 name
이라는 변수를 선언하고 {name}
으로 JSX안에 사용하는 예시이다. 이 외에 2 + 2
, user.firstName
, formatName(user)
등도 사용할 수 있다.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
function App(){
return(
<div>
<h1>Title1</h1>
<h2>Title2</h2>
</div>
)
}
컴포넌트에 여러 요소가 있다면 반드시 부모 요소 하나가 감싸는 형태여야 한다.
React는 Virtual DOM 방식을 사용하여 렌더링하는데 컴포넌트 변화를 감지할 때 효율적으로 비교할 수 있도록 컴포넌트 내부는 하나의 DOM 트리로 이루어져야 한다는 규칙이 있기 때문이다.
<div>
, <p>
, <span>
, <a>
등과 같이 짝이 있는 태그의 경우 반드시 닫는 태그가 존재해야 한다.<img/>
, <input/>
, <br/>
같은 단독 태그(self-closing tag)의 경우, 또는 태그가 비어있는 경우에는 />
를 이용해 바로 닫아주어야 한다.JSX 내부의 자바스크립트 표현식 내에서 if
문을 사용할 수 없기 때문에 조건부 연산자(삼항 연산자)를 사용해야 한다.
function App(){
const name = 'react';
return(
<div>
{name === 'react'? (<h1>This is react</h1>) : (<h1>This isn't react</h1>)}
</div>
)
}
undefined
렌더링 하지 않기function Example() {
const value = undefined;
return <div>{value}</div>;
}
위의 예시는 undefined
를 렌더링하게 되므로 React에서 오류가 출력되는 잘못된 코드이다. 만약 어떠한 값이 undefined
일 수도 있을 경우, OR 연산자(||
)를 사용하거나 JSX 내부에서 렌더링하는 방식으로 오류를 방지할 수 있다.
function Example() {
const value = undefined;
return value || "Value is undefined";
}
기존에 HTML에서 스타일을 지정할 때의 background-color
, border-radius
등과 같이 '-'이 포함된 이름들을 JSX에서 사용할 때에는 카멜 표기법으로 작성해야 한다.
function App() {
const style = {
backgroundColor: 'turquoise',
fontSize: '100px',
fontWeight: '700'
}
return (
<div style={style}>테스트</div>
)
}
class
를 지정해 줄 때에는 className
으로function App() {
return (
<div className="myTitle">
<h1>Hello, World!</h1>
</div>
)
}
function MyComponent() {
return (
<div className="myClass">
Hello, world!
</div>
);
}
Virtual DOM (VDOM)은 UI의 이상적인 또는 “가상”적인 표현을 메모리에 저장하고 ReactDOM과 같은 라이브러리에 의해 “실제” DOM과 동기화하는 프로그래밍 개념입니다.
React는 효율적인 렌더링을 위해 Virtual DOM을 사용한다. Virtual DOM이란 실제 DOM 노드 트리를 복제한 JavaScript 객체를 말한다. class, style 등의 속성을 갖고 있으나 DOM API 메서드를 갖지는 않으므로 HTML DOM의 추상화 버전이라고도 할 수 있다. 최초로 브라우저가 DOM 트리를 생성하고 브라우저 화면에 애플리케이션 UI를 렌더링할 때 Virtual DOM은 DOM 트리를 '가벼운 버전'으로 복사한다. 이후 데이터가 변경되거나 DOM 노드에 변화가 생기면 Virtual DOM은 새로운 DOM 트리를 처음부터 다시 생성한다. 그리고 이전 Virtual DOM에 있던 내용과 업데이트 후의 내용을 비교하여 바뀐 부분만 실제 DOM에 적용한다. DOM 노드를 조작하는 과정의 비효율성은 렌더링 과정에서의 비싼 비용으로 인한 것이므로, 메모리 상에서 트리만 변경하는 Virtual DOM은 이러한 작업을 효율적으로 할 수 있게끔 한다.
React는 단방향 데이터 바인딩을 사용하여 컴포넌트 간 데이터 흐름을 관리한다. 뷰와 모델 간의 데이터 변경을 서로 감시하는 양방향 데이터 바인딩의 경우, 그 사이에 의존성이 발생할 수 있으며 데이터가 많아질수록 복잡도가 증가하여 성능 저하를 일으킬 수 있다. React에서는 부모 컴포넌트가 자신의 state를 자식 컴포넌트에게 props로 전달함으로써 데이터의 흐름을 단순하게 유지한다.
또한, 자식 컴포넌트는 부모 컴포넌트가 function인지 class인지 알 필요도 없으며 상태의 존재 여부도 모를 수 있다. state가 소유하고 설정한 컴포넌트 이외에는 어떠한 컴포넌트에도 접근할 수 없는 캡슐화가 이뤄진 것이다.
일반적으로 이를 “하향식(top-down)” 또는 “단방향식” 데이터 흐름이라고 한다. 모든 state는 항상 특정한 컴포넌트가 소유하고 있으며 그 state로부터 파생된 UI 또는 데이터는 오직 트리구조에서 자신의 “아래”에 있는 컴포넌트에만 영향을 미치는 것이다.
앞서 만든 App에서 props를 전달하여 Counter 컴포넌트를 작성하는 것이 그 예시라고 할 수 있다. 각 Counter
컴포넌트는 App
에서 받은 props를 사용하여 자신만의 컴포넌트를 설정하고 독립적으로 업데이트한다.
React
mdn web docs) React
YUNSEONG.log) 리액트와 선언형 프로그래밍(Declarative Programming)
naon) 리액트 상태값(state)이란?
DeKu) React란
개발여행의 블로그) [React 기초] JSX란? / JSX 문법
gyumin_2.log) React.js - JSX란?(정의, 장점, 문법, 특징 등)
ChanBLOG) [React] React 에서 사용하는 JSX 문법
우아한테크) [10분 테코톡] 돔하디의 Virtual DOM
우아한테크) [10분 테코톡] 🥁 지그의 Virtual DOM