React (2) props와 state
JSX
React에서 우리가 쓰는 문법은 Javascript가 아님.
비슷하긴 한데, HTML 태그를 따옴표에 넣지 않고 그대로 쓰고, 여튼 차이가 좀 있다.
페이스북에서 작업을 좀 더 편하게 하기 위해 만든 JSX라는 언어.
Component 만들기
class Subject extends Component {
render() {
return (
<header>
<h1>WEB</h1>
world wide web!
</header>
);
}
}
Subject라는 새로운 component, 즉 사용자 정의 태그를 만든 것.
class 방식으로 만들고, component 클래스를 상속받음.
render라는 메소드 안에 component를 정의해주면 됨.
function으로 만드는 방법도 있음.
여튼, 이제 다른 곳에서 <Subject></Subject>
라는 형태로 사용할 수가 있게 된 것.
class App extends Component {
render() {
return (
<div className="App">
<Subject></Subject>
</div>
);
}
}
요런 식으로.
React component의 주요 용도는 정리정돈이라고 볼 수 있음.
복잡도를 낮추고, Component의 이름에만 집중할 수 있게 됨.
Tag와 attribute
attribute는 태그가 가지는 속성을 의미.
a 태그로 치면 주소를 나타내는 href같은 것들이 바로 attribute.
Component와 props
우리가 그냥 <Subject>
라고만 component를 만들어놓으면, 걔는 항상 똑같은 일만 해야 함.
근데 우리가 component에다가 attribute처럼 여러 가지 속성을 집어넣을 수 있으면,
그것을 통해 여러 가지 일을 하는 component를 만들 수가 있게 된다.
재사용성이 높아진다는 뜻.
거의 유사한 개념이고, 용어만 다르다.
tag의 attribute / component의 props.
상위 component(여기선 App)에서 하위 component(Subject)로 전달해주는 속성값이라고 정의하기도 한다.
class Subject extends Component {
render() {
return (
<header>
<h1>{this.props.title}</h1>
{this.props.sub}
// 요렇게 일종의 템플릿을 만들어 놓으면, 이제 상위 component인 App에서 props를 입력함으로써 Subject component를 완성시키는 것.
</header>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Subject title="WEB" sub="world wide web!"></Subject>
<Subject title="React" sub="For UI"></Subject>
<Navigation></Navigation>
<Content></Content>
// Navigation와 Content도 별도의 component로 만들어놨다는 가정.
</div>
);
}
}
여기서 보면, 동일한 Subject component의 props로 다른 입력값을 주고 있다.
그러면 화면에는 서로 다른 결과가 출력됨.
state
state라는 개념은 props랑 같이 봐야 한다.
state와 props는 둘 다, component가 좀 더 다양한 일을 하게 만들기 위해 필요함.
props는 component의 동작을 바꿀 수 있게, component의 사용자에게 제공하는 일종의 UI.
(component의 사용자가 입력하는 정보).
state는 component의 사용자가 알 필요가 없는 내부 동작에 필요한 정보.
props가 좀 더 사용자 입장의 데이터라면, state는 좀 더 구현하는 사람 입장의 데이터.
component를 사용하기 위해 필요한 ‘외부’의 props와
그 props에 따라서 component를 실제로 구현하는 데에 필요한 ‘내부’의 state가
철저히 분리되어 있어야 한다.
쉽게 말하면, state는 component 내부적으로만 사용될 데이터들을 전부 몰아넣는 곳.
Constructor
component가 실행될 때, render 메소드보다 먼저 실행되면서
그 component의 데이터를 초기화시켜주는 코드를 집어넣는 메소드가 바로 constructor.
class App extends Component {
constructor(props) {
super(props); // component 내의 this.props를 정의
this.state = {
subject:{title:'WEB', sub:'World Wide Web!'}
}
// state를 초기화
}
render() {
return (
<div className="App">
<Subject title = {this.state.subject.title} sub = {this.state.subject.sub}></Subject>
<Navigation></Navigation>
<Content></Content>
</div>
);
}
}
전과 똑같은 기능을 하는 코드이지만
component의 데이터들을 state에서 가져왔다는 차이점.
state와 props
class Navigation extends Component {
render() {
var lists = [];
var data = this.props.data;
var i = 0;
while(i < data.length) {
lists.push(<li><a href={"/"+data[i].id}>{data[i].title}</a></li>);
i = i + 1;
}
return (
<nav>
<ul>
{lists}
</ul>
</nav>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
subject:{title:'WEB', sub:'World Wide Web!'},
contents: [
{id:1, title:'HTML', desc:'HTML is for information'},
{id:2, title:'CSS', desc:'CSS is for design'},
{id:3, title:'Javascript', desc:'Javascript is for interactive'}
]
}
}
render() {
return (
<div className="App">
<Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject>
<Subject title="React" sub="For UI"></Subject>
<Navigation data={this.state.contents}></Navigation>
<Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
</div>
);
}
}
위의 코드에서 보면, 부모인 App의 입장에서는 state라는 내부 정보를 가지고 있고
그것을 자식에게 전달할 때는 props를 통해서 전달한다.
App의 입장에서는 Navigation이라는 component가
내부적으로 어떻게 돌아가는지 전혀 알 필요가 없다.
그냥, data라는 props로 어떤 데이터를 전달하면 되는지만 생각하면 됨.
참고로, 저 Navigation component의 lists는 다음과 같은 구성.
<li><a href="1.html">HTML</a></li>
<li><a href="1.html">CSS</a></li>
<li><a href="1.html">Javascript</a></li>
key
위의 코드를 실행시키면 "Each child in a list should have a unique 'key' props"
라는 에러가 뜬다.
각 리스트의 항목끼리 식별될 수 있는 유니크한 속성이 필요하다는 것.
key = {data[i].id}
이런식으로 유일한 값을 가지는 props를 li 태그에다가 추가해주면 됨.
state 주의할 점.
state에 props를 복사하면 안 된다. 흔히 발생하는 실수 중 하나란다.
constructor(props) {
super(props);
this.state = { color : props.color };
}
이렇게 하지 말라는 것.
그냥 this.props.color로 직접 사용해야 함.