React의 컴포넌트는 앱을 구성하는 화면을 별개의 모듈로 나눈 단위로 Javascript와 JSX로 구성된 모듈을 반환하여 화면을 구축한다.
React 앱을 구현하는데 있어 가장 기본적인 단위, 컴포넌트다. 컴포넌트의 핵심은 기능의 모듈화와 재사용성에 있다. 기능을 모듈화하여 관리포인트를 통일화하여 유지보수성을 증대시킬 수 있고, 모듈 형태이기 때문에 필요한 곳에 레고처럼 끼워넣어 사용할 수 있다. 이것이 React 앱을 구현하는 가장 기본적인 방법이다.
CRA를 통해 React app을 만들면 App.jsx가 있다. App.jsx도 App이라는 컴포넌트를 return하는 형태로 되어있다. App은 모든 Component의 부모 컴포넌트다.
import React, { Component } from "react";
class Banner extends Component {
render() {
return <div>{this.props.name}</div>;
}
}
export default Banner;
import React from "react";
const Banner = (props) => {
return <div>{props.name}</div>;
}
export default Banner;
💥 주의 : 컴포넌트의 이름은 항상 대문자로 시작한다.
React는 소문자로 시작하는 컴포넌트를 DOM 태그로 처리한다. 한마디로 소문자로 선언해서 사용하면 HTML 태그로 인식해 의도한대로 동작하지 않는다는 얘기다.
React에서는 위 2가지 선언방식을 지원했으나, 현재 공식문서에서는 함수형 Component와 hook을 결합한 형태를 권장한다. 권장하는 이유는 다음과 같다.
👽 React Hook??
React16.8 부터 Hook이란 개념이 도입되었다. Hook을 이용해 함수형 컴포넌트도 state관리와(useState) 라이프사이클API(useEffect)를 심플하게 사용할 수 있게 됐다. 그 덕분에 가독성이 떨어지는 클래스형 함수를 굳이 사용할 필요가 없게 됐다.
React hook에 대해서는 차후 포스팅에서 자세히 다루겠다.
함수형 컴포넌트의 사용을 권장하는 이유 중 props에 따른 랜더링 결과 보장 내용에 대해 설명한다. 이것은 React의 Flux패턴을 도입한 것과 유사한 이유다. 가령 다음과 같은 컴포넌트가 있다고 가정해보자.
class ProfilePage extends React.Component {
showMessage = () => {
alert(`${this.props.user}를 팔로우 했습니다`);
}
handleClick = () => {
setTimeout(this.showMessage, 5000);
}
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}
사용자 A와 B가 있다고 가정해보자. A를 팔로우하고 5초 이내로 B의 프로필을 클릭했을 때 'B를 팔로우 했습니다' 라는 메세지를 얻게된다. 이유는 this는 mutable(변경가능)하기 때문이다. A를 클릭후 B 프로필로 이동하는 경우, A에 대한 요청이 진행되고 있는 상황에서 클래스 컴포넌트가 다시 렌더링된다. 하지만 함수의 진행에 있어 이전 A를 바라봐야 하지만 결과는 B로 할당하게 된다. showMessage 함수가 새로운 this.props의 user를 읽는 것이다. 이러한 현상 때문에 예기치 못한 결과(결국 production에서는 버그임)가 발생할 수 있다.
const ProfilePage = (props) => {
showMessage = () => {
alert(`${props.user}를 팔로우 했습니다`);
}
handleClick = () => {
setTimeout(showMessage, 5000);
}
return (
<button onClick={handleClick}>Follow</button>
)
}
반면 함수형 컴포넌트의 경우 props는 immutable(불변)의 특성을 띄고 있기 때문에, 다시 랜더링되더라도 요청했던 시점의 user를 바라본다.
이제 Component를 선언하고 App.jsx에 활용해보자. LoginComponent를 만들고 App에서 활용한다 가정했을때 다음처럼 사용하면 된다.
/* 이것들이 react에서 제공하는 hook이다. 추후 하나씩 다룬다. */
import React, { useState, useEffect, Suspense, useRef } from 'react';
/**
* 로그인 Component
*/
const LoginComponent = (props) => {
return <div>로그인페이지</div>;
};
export default LoginComponent;
import React, { Suspense } from 'react';
import LoginComponent from './component/Layout';
const App = (props) => (
<Suspense>
<LoginComponent {...props} />
</Suspense>
);
export default App;
다음 코드처럼 Component를 선언하고 해당 기능을 App.jsx에서 import하여 사용한다. react의 모든 화면은 다음과 같은 구조로 작성된다.
목적에 따라 프리젠테이션(presentational) 컴포넌트와 컨테이너(container) 컴포넌트로 분류할 수 있다.
오늘은 React를 구성하는 가장 작은 단위, 컴포넌트에 대해 알아봤다. React 개발에 있어 가장 기초적인 부분인 만큼 개념 확립이 필수적이다. 다음 포스팅에선 React의 통곡의 벽, state, props에 대해 풀어보겠다.
오늘 저녁은 소갈비찜이다. 🥕
참고 : https://ko.reactjs.org/docs/components-and-props.html
https://onlyfor-me-blog.tistory.com/460
https://ko.reactjs.org/docs/react-component.html#render
https://born-dev.tistory.com/27