함수 컴포넌트, 클래스 컴포넌트 두가지 종류로 사용할 수 있음.
function app(props){
...
<div>
<Tweet></Tweet> //사용자 정의 컴포넌트 Tweet
</div>
...
}
//이 함수를, react 컴포넌트 라고 부른다.
function Tweet(){
return <div>트윗 컴포넌트</div>
}
위 예제의 함수는, 데이터를 가진 하나의 'props(속성을 나타내는 데이터)'객체 인자를 받은후,
react 엘리먼트를 반환한다. 즉, 이 함수는 유효한 react 컴포넌트이다.
그리고 이 컴포넌트는 js함수이기 때문에, '함수 컴포넌트'라고 부른다.
class app extends React.Component{
render(){
return <div>트윗 컴포넌트 이름 : {this.props.name}</div>
}
}
React 엘리먼트들은 두 가지로 나타낼 수 있다.
let el = <div />;
let el = <Tweet id="pioneerJ" />;
JSX문법으로 작성된 엘리먼트는 하나의 엘리먼트로 묶여서 새 객체로 반환된다.
위에서 작성한 Tweet 컴포넌트를 App 컴포넌트안에 담으면
//App.js
import React from 'react'; //react 불러오기
function App() {
return (
<div>
<Tweet />
</div>
);
}
export default App; //App 컴포넌트 내보내기
이제 App.js를 index.js를 만들어서 Tweet 컴포넌트를 내보내려고 한다.
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from "./reportWebVitals";
ReactDOM.render(<App />, document.getElementById('root'));
//브라우저에 있는 실제 DOM내부에 리액트 컴포넌트를 렌더링하겠다는 것을 의미한다.
//그리고 렌더링하여 붙일 리액트 컴포넌트는 id가 root인 dom을
//선택하고 있다.
//-> 즉 리액트 컴포넌트가 렌더링될때에는 , 렌더링된 결과물이 위 div내부에
//다시 렌더링이 되는것이다.
reportWebVitals(); //아직 모름 ㅠㅠ
👉컴포넌트 작성 규칙
- 컴포넌트 이름은 항상 대문자로 시작한다.
: react는 소문자로 시작하는 이름의 컨포넌트를, DOM태그로 처리해버린다.
: 예를 들어 tweet을 여러 번 렌더링하는 App 컴포넌트를 만들 수 있는것이다.
function Tweet(props) {
return <h1>Hello, {this.props.id} !</h1>;
}
function App() {
return (
<div>
<Tweet id='pioneerJ' />
<Tweet id='pioneerK' />
<Tweet id='pioneerL' />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
ex) 중첩구조로 이루어진 comment 컴포넌트를, 몇 가지 컴포넌트를 추출하여 재사용성을 증가시켜보자.
//이 컴포넌트는 author(객체), text(문자열), date(날짜)를 각각 props로 받은 후,
//SNS 사이트의 comment를 나타내는 컴포넌트이다.
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>
);
}
- Avatar 추출하기
function Avatar(props){ //-> <Avatar user = {props.author} />
return (
<img className='Avatar'
src={props.user.avatarUrl}
//**props의 이름은, '사용될 컴포넌트 자체의 관점'에서 짓는것이 좋다고 한다.
alt={props.user.name}
/>
);
}
👉 Avatar는, 자신이 Comment안에서 렌더링 된다는 사실을 알 필요없다.
때문에, Avatar 입장에서 볼 때로 이름을 바꿔줄 수 있다.
'author' 속성이름을, 일반화된 'user'로 변경하여 사용하였다.
Avatar 컴포넌트를 사용자 정의 컴포넌트로 만들어서 다시 Comment컴포넌트 안에 넣어보았다.
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를 추출 함으로써, Comment 컴포넌트가 한층 더 가벼워보이는 것을 볼 수있다.
계속해서 Avatar가 들어있는 UserInfo 부분도 스리슬쩍 빼 보겠다.
- UserInfo 추출하기
function UserInfo(props){ //-> <UserInfo user = {props.author} />
return (
<div className='UserInfo'>
<Avatar user={props.user} />
<div className='UserInfo-name'>
{ props.user.name }
</div>
</div>
);
}
UserInfo 컴포넌트 또한 사용자 정의 컴포넌트로 만들어서 다시 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>
);
}
함수 컴포넌트 이건, 클래스 컴포넌트 이건, 모두 컴포넌트의 자체 props를 수정할 수 없다.
컴포넌트 추출 과정 시, 이 props의 속성이름을 해당 props를 사용하는 관점에서 변경이 가능하다.
모든 React 컴포넌트는, 자신의 props를 다룰 때 반드시 *순수 함수처럼 동작해야 한다.
*순수 함수
다음은 순수 함수와, 순수 함수가 아닌 예제이다.
순수 함수 순수 함수가 아님. function sum(a, b) { function withdraw(account, amount) { return a + b; account.total -= amount; } }
=> 입력값을 바꾸려 하지 않고, 항상 동일한 입력값에 대해 동일한 결과를 반환하기 때문에
순수 함수라고 부른다.=> 그에 반해, 오른쪽 예제는 자신의 입력값을 변경하기 때문에 순수 함수가 아니다.