(React 공식문서의 main concepts 번역 글입니다.)
함께보면 이해가 쏙쏙
https://youtu.be/MhjaBokqfVw
Components는 props를 argument로 받아
element를 리턴하는 function이다.
(여기서 props는 element가 보여줄 data이다)
compoents를 활용하여 element를 독립적으로 만들 수 있다.
이는 element의 재사용성을 높여준다.(마치 super class 처럼)
일반적으로 component를 선언할 때 이름은 대문자로 시작한다.
선언 방법은 functional component와 class component 2가지가 있다.
component는 아래처럼 function으로 만들 수 있다.
function Welcome(props) {
return <h1>Hello, David</h1>;
}
react component가 되려면 아래 2가지 기준을 만족해야 한다.
위에 function Welcome은 2가지 조건을 만족하기 때문에 component이다.
또한 ES6의 class keyword를 사용해서 component를 만들 수도 있다.
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
function과 class 두가지 방법은
동일하게 react component를 만들 수 있다.
두가지 방법 사이 유일한 차이점은 state 관리 기능이었다.
(과거에는 class만 state 관리 가능)
하지만 react hooks가 등장하면서
functional component에서도 state 관리가 가능 해졌다.
이전에 react element는 단순히 HTML tag로 만들어졌다.
const element = <div />;
그러나 component를 활용해서 아래처럼 element를 만들게 되었다.
const element = <Welcome name="david" />;
react가 이러한 component를 실행할 때,
JSX attribute(예를 들어, 위 코드에서 name
)을
single object ({name: "david"}
)의 형태로
component에게 전달한다.
이 object가 바로 props이다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
위 코드를 실행하면 아래의 과정을 거친다.
<h1>Hello, david</h1>
라는 element를 return한다.component는 다른 component를 조합하여 구성할 수 있다.
그 결과 component는 거꾸로 추출할 수도 있다.
(부모 component에게 소속된 자식 component를 만들 수 있으므로)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="David" />
<Welcome name="Paul" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
위 코드에서 처럼 App component
를 구성할 때
그 안에서 많은 Welcome component
들을 조합하여 구성할 수 있다.
처음부터 react로 app을 만드는 경우
최상위 component인 App component부터 가장 먼저 만들게 된다.
하지만 기존 앱을 react로 바꿀때는 더 작은 component부터 만들기도 한다.
component는 핵심 component를 추출할수록 간단해진다.
(이때 추출한 component가 리턴한 object는
OOP에서 super class와 비슷하다.)
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar" src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
위 Comment component
는 재사용하기 어렵다.
너무 많은 component들을 special하게 갖고 있기 때문이다.
component를 추출할 때 그 기준은 재사용성이 높은 코드인가? 이다.
(추출한 component는 재사용성이 높아서 코드의 중복을 제거함)
가장 먼저, 하이라이팅된 Avatar component
를 추출하자.
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
원래 Avatar component의 props 이름은 author였다.
하지만 이름을 user로 바꾸었다.
그 결과, author 뿐만 아니라 다른 직업도 Avatar component를 활용할 수 있게 되었다.
component의 props 이름은 해당 재사용성을 높이는 방향으로 짓자.
(역할을 구체적이고 명확하게 고려해서 짓지 말자 ❌)
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} /> <div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
위와 같이 Avatar component의 props이름이 user가 되었고,
comment component는 조금 간단해졌다.
다음은 UserInfo component를 추출해보자.
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
UserInfo 또한 comment component 외에
다른 component에서 재사용 가능하므로
추출해서 중복된 코드를 제거한다.
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>
);
}
최종적으로 comment component는 위와 같이 간단해졌다.
재사용할 수 있는 component들을 추출했기 때문이다.
component 추출은 마치 generalization과 비슷하다. 공유되는 특성을 추출하는 것과 비슷하게 중복되는 로직을 추출하기 때문이다.
function 또는 class로 component를 만든 경우,
절대 주어진 props를 수정할 수 없다.
아래 function을 보자.
function sum(a, b) {
return a + b;
}
sum function은 pure하다.
왜냐하면 argument로 주어진 a,b값을 수정하지 않기 때문이다.
그 결과, 언제나 동일한 값을 return한다.
반대로 아래 function은 pure하지 않다.
function withdraw(account, amount) {
account.total -= amount;
}
왜냐하면 위 function은 argument로 주어진 account의 값을 바꾸기 때문이다.
React에서는 절대적인 규칙이 한가지 있다.
모든 component는 props 값을 수정하지 않는 pure function이다.
물론 UI는 동적이어서 나타내는 값이 변한다.
이와 관련된 state라는 개념을 다음 블로깅에서 만나보자.
state는 component가 React의 절대적인 규칙을 지키면서
동시에 event, server와의 통신 등 상호작용을 통해
UI가 나타내는 값이 변할 수 있도록 해준다.