React
React는 컴포넌트 단위로 어플리케이션을 설계할 수 있도록 하는 자바스크립트 라이브러리이다. 튜토리얼은 공식 홈페이지에 잘 설명되어있으니 꼭 읽어보도록 하자.
1. JSX와 앨리먼트 랜더링
JSX는 자바스크립트를 확장한 문법이다. JSX로 작성한 스크립트는 해석할 수 있도록 자바스크립트 컴파일러 라이브러리 바벨이 변환하게 된다. JSX를 사용하면 아래와 같이 엘리먼트(element)를 생성하여 변수에 할당하거나 반환을 할 수 있다. 시각적으로는 HTML의 구조를 따르면서도, 자바스크립트의 언어체계 방식으로 작업할 수 있다.
const name = "Josh"
const element = <h1>Hello, {name}!</h1> // 엘리먼트를 생성하였다. 후술할 컴포넌트의 구성요소이다.
ReactDOM.render(
element,
document.getElementById("root")
)
React DOM은 랜더링을 할 때마다 지금 랜더링해야할 엘리먼트와 이전 엘리먼트를 비교한다. 그리고, 변경해야할 부분만 선택적으로 변경하여 DOM을 업데이트한다.
2. Componenet
UI를 구성하는 엘리먼트들을 기능에 따라 재사용 가능한 여러 부품으로 나누어보자. 각 기능을 담당하는 부품을 컴포넌트라고 할 수 있다. React에서는 컴포넌트를 함수와 클래스 방식으로 선언하여 생성할 수 있다. 컴포넌트는 엘리먼트와 마찬가지로 React DOM으로 랜더링할 수 있다.
// 1. 함수 컴포넌트
function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
// 2. 클래스 컴포넌트
class Welcome extends React.Componenet {
constructor(props) {
super(props);
}
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
// 3.
ReactDOM.render(
<Welcome
name="sara"
/>,
document.getElementById("root")
)
2. 1. 속성(Props)과 상태(State)
React에는 데이터를 담아두는 두가지 모델이 있다. Props와 State는 JS 객체이며, 후술할 랜더 업데이트 이벤트를 유발한다. Props는 컴포넌트의 구성(configuration)으로, 원칙적으로 immutable하다. State는 컴포넌트가 마운트될 때 초기값을 가지며, 이벤트에 따라 값이 변하는 mutable한 객체이다.
Props | State | |
---|---|---|
부모 컴포넌트로부터 해당 데이터의 초기값을 가질 수 있는가 | O | O |
부모 컴포넌트가 해당 데이터를 변경할 수 있는 수 있는가 | O | X |
컴포넌트 내부에서 초기값을 설정할 수 있는 데이터인가 | O | O |
컴포넌트 내부에서 변경할 수 있는 데이터인가 | X | O |
자식 컴포넌트의 해당 데이터의 초기값을 설정할 수 있는가 | O | O |
자식 컴포넌트의 해당 데이터를 변경할 수 있는가 | O | X |
위 표에서 알 수 있듯이 State는 해당 데이터를 가진 컴포넌트만 접근할 수 있다. 부모와 자식 컴포넌트는 어떤 상태인지 알 수 없으며, 알 필요도 없다. State를 캡슐화라고 부르기도 하는 이유이다.
한편, Props는 부모 immutable한 데이터라고 하였으나, State를 활용하면 마치 Props를 변경하는 것처럼 구현할 수 있다. 컴포넌트 자신의 State를 자식 컴포넌트의 Props에 전달하면 된다. 이러한 데이터 흐름을 하향식(Top-down)이라고 한다. 대부분의 공대 출신들에게는 익숙한 단어가 아닐까 싶다… 쓸데없는 소리지만 건축에는 탑다운 공법이라는 터파기 및 골조 시공방식이 있다.
<FormattedDate date={this.state.date} />
State를 수정할 때에는 직접 수정해서는 안된다. 해당 컴포넌트를 다시 렌더링하는 작업이 실행되지 않기 때문. this.setState() 메서드를 사용해야한다.
또한 React는 성능을 위해 여러 setState() 호출을 단일 업데이트로 한 번에 처리하기도 한다. 즉, this.props와 this.state가 비동기적으로 업데이트 될 수도 있다는 것. 따라서, 예제의 첫 번째와 같이 적으면 오류가 발생할 수 있다.
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => {
counter: state.counter + props.incremenet
}));
2. 2. State 끌어올리기
어떤 컴포넌트의 데이터에 대한 변경사항을 여러 컴포넌트에 반영해야 할 수도 있다. State는 해당 컴포넌트에서만 접근할 수 있다고 하였다. 따라서, 우리는 부모와 자식 컴포넌트로 나눌 필요가 있다.
부모 컴포넌트가 데이터의 State를 관리하며, 이벤트 핸들러를 자식 컴포넌트의 Props로 전달한다. 자식 컴포넌트에서 이벤트가 발생하면, Props의 이벤트 핸들러 함수를 통해서 부모 컴포넌트에 갱신해야 할 데이터를 넘겨줄 수 있다.
중요하게 생각할 부분은 계층 구조를 어떻게 나눌 것인가이다. 리액트는 하향식 데이터 흐름을 지향하며, State는 해당 컴포넌트에서만 접근할 수 있다. 따라서 설계단계에서 데이터 간 상호관계를 명확히 하여 계층구조를 설계해야 한다.
2. 3. 생명주기(Life Cycle)
아래 그림을 참고하여 예제의 버튼을 입력했을 때 콘솔에 어떤 내용이 뜨는지 확인해보자.
- constructor: 클래스 생성자. 컴포넌트가 생성될때 호출된다.
- componenetDidMount: 컴포넌트가 DOM에 랜더링 된 직후 실행된다.
- componenetDidUpdate: 갱신이 일어난 직후에 호출된다. 최초 랜더링에서는 호출되지 않는다.
- componenetWillUnmount: 컴포넌트가 마운트가 해제되어 제거되기 직전에 호출된다. 해당 컴포넌트는 이후에 다시 렌더링되지 않는다.
3. Create React App
React를 기반으로 한 프로젝트를 시작하는 제일 쉬운 방법이다. 이 방법을 사용하면 필요한 설정은 다 해주지만, Babel과 Webpack이 무엇이며 어떤 역할을 하는지는 알아두도록 하자.
npx create-react-app my-app
Leave a comment