Component (컴포넌트)
- 재사용 가능한 각각의 독립된 모듈
- 재사용 가능한 UI 구성 단위
동일 코드가 반복되는 부분을 하나의 component로 만들어 같은 디자인의 input이 필요한 곳마다 재사용할 수가 있으며, 컴포넌트를 하나만 만들고 여기저기서 재사용하면, 디자인이 바꼈을 때 css 한줄만 수정하면 바뀐 디자인이 모두 반영될 것이다
컴포넌트는 독립적으로, 재사용 가능한 코드로 관리할 수 있다. 하나의 컴포넌트에 필요한 html, css, js(모듈)를 모두 합쳐서 만들 수 있다
컴포넌트는 함수랑 비슷하다. 함수도 기능이 독립적이고 한 번 선언해 두면 필요할 때 마다 호출하면서 재사용하기 때문이다.
React 컴포넌트에서는 input을 props라고 말하고 return은 화면에 보여져야할 React요소가 return된다
장점
- 코드 재활용성 증가
- 코드 유지보수 용이
- 해당 페이지가 어떻게 구성되어 있는지 파악 용이
- 컴포넌트는 또 다른 컴포넌트를 포함 (부모 컴포넌트 - 자식 컴포넌트)
component 만들기
React에서는 컴포넌트를 class나 함수로 만들 수 있다
class component
- 초기에 많이 사용되던 컴포넌트 형태
- 함수형에 비해 문법과 사용법이 복잡함
- 하지만 클래스형으로 작성되어있는 기존 코드들도 많이 남아있기 때문에 읽고 해석할 수 있어야함
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
class로 컴포넌트를 만들려면 React.Component 를 extends해서 생성한다. 컴포넌트를 생성할 때 render() 메서드는 무조건 정의해야 하고, return 도 해주어야 한다 render() 메서드는 무조건 정의해야한다는 말은, 컴포넌트를 만들 때 필요한 메서드가 원래 더 있다.
function component
- 클래스형 컴포넌트에 비해 간단하고 단순
- 초창기에는 state를 관리하지 못한다는 단점으로 인해 잘 사용되지 않았음
- React 16.8 버전에서 hooks란 기능이 추가되면서 state를 관리할 수 있게 되어서 그 뒤로 자주 사용된다
- 실제 현업에서 가장 많이 사용되고 있다
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Component 사용
컴포넌트는 함수 이름 or class 이름으로 사용할 수 있다. 태그처럼 <Welcome /> 으로 작성한다
// 1. Welcome 컴포넌트 정의
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// 2. App 컴포넌트 정의
function App() {
return (
<div>
<Welcome name="wecoder" />
<Welcome name="John" />
<Welcome name="Sara" />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
- Welcome 컴포넌트 : Welcome 컴포넌트를 사용한 측(부모)에서 name이라는 property를 부여 props.name의 값을 사용한다
- App 컴포넌트를 보면 div로 감싸져있고, <Welcome/> 컴포넌트를 세번 사용했다. name이라는 property를 부여했다
- ReactDom.render 함수로 react 요소를 그려준다. root라는 id를 찾아 <App /> 컴포넌트를 그려준다
더 작은 Component로 분리하기
아래 예시는 Comment라는 컴포넌트이다. 컴포넌트는 재사용 가능한 코드 단위라고 했다.
.avatar 요소를 컴포넌트로 만들겠다. avatar 컴포넌트는 분명 댓글창 이외에도 사용자 정보 등 여기저기 많이 쓰일 것 같다.
function Comment(props) {
return (
<div className="comment">
<div className="user-info">
<img className="avatar"src={props.author.avatarUrl}alt={props.author.name}/>
<div className="user-info-name">
{props.author.name}
</div>
</div>
<div className="comment-text">
{props.text}
</div>
<div className="comment-date">
{formatDate(props.date)}
</div>
</div>);
}
.avatar 부분을 그대로 떼와서 Avatar라는 이름으로 컴포넌트를 만들어줬다. Comment 컴포넌트에서는 props.author로 접근해서 avatarUrl과 name을 가져왔는데, Avatar 컴포넌트에서는 좀 더 직관적으로 사용할 수 있도록 user라는 이름으로 받아왔다
props.user에서 avatarUrl, name 값을 가져오도록 해야겠다. <Avatar />를 사용하는 측에서 user라는 attribute를 추가해야겠다
function Avatar(props) {
return (
<img className="avatar"src={props.user.avatarUrl}alt={props.user.name}/>);
}
Avatar 컴포넌트에서 user의 avatarUrl과 name이 필요하므로, Comment 컴포넌트에서 props.author 정보를 user라는 attribute로 넘겨주었다props.author의 avatarUrl, name 값이 user를 통해 전달되었다.
function Comment(props) {
return (
<div className="comment">
<div className="user-info">
<Avatar user={props.author} />
<div className="user-info-name">
{props.author.name}
</div>
</div>
<div className="comment-text">
{props.text}
</div>
<div className="comment-date">
{formatDate(props.date)}
</div>
</div>);
}
한 번 더 분리를 해보면, 이제는 .user-info 부분을 컴포넌트로 만들었다. 재사용할 가능성이 조금이라도 있다면 컴포넌트로 만들어주는 것이 좋다. .user-info 부분을 그대로 떼어다가 UserInfo라는 컴포넌트로 만들었다
function UserInfo(props) {
return (
<div className="user-info">
<Avatar user={props.user} />
<div className="user-info-name">
{props.user.name}
</div>
</div>);
}
그러면 Comment 컴포넌트는 아래처럼 확 간결해진다!
function Comment(props) {
return (
<div className="comment">
<UserInfo user={props.author} />
<div className="comment-text">
{props.text}
</div>
<div className="comment-date">
{formatDate(props.date)}
</div>
</div>);
}