props 와 state
패트와 매트도 아닌 props와 state
리액트를 사용하면서 반드시 개념정리가 확실히 되어야 한다
props
단어 뜻 그대로 속성값이다 바로 컴포넌트의 속성값
HTML로 이야기하면 attribute가 바로 props다
우리는 props를 통해 부모 컴포넌트로부터 자식 컴포넌트에게 state의 상태 값, 혹은
event handler를 넘겨 줄 수 있다!
아래의 코드를 확인하자
class App extends Component {
render() {
return (
<div className="App">
<Subject title="React" sub="For UI"></Subject>
<TOC></TOC>
<Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
</div>
)
}
}
위 코드와 같이 Subject와 Content의 컴포넌트에 title과 sub, desc라는 props를 할당 해 준 것이다.
그러면 이 해당 자식컴포넌트는 안에서 어떻게 받아야 할까 ?
class Subject extends Component {
render() {
return (
<header>
<h1>{this.props.title}</h1>
{this.props.sub}
</header>
);
}
}
=========================================
class Content extends Component {
render(){
return (
<article>
<h2>{this.props.title}</h2>
{this.props.desc}
</article>
);
}
}
이런식으로 부모 컴포넌트로부터 전달 받은 데이터를 이렇게 받아오며
props를 통한 event handler 전달 또한 가능하다
아래의 코드를 확인하자
import React from 'react';
import Child from '../pages/Children/Children';
class Parent extends React.Component {
constructor() {
super();
this.state = {
color: 'red'
};
}
handleColor = () => {
this.setState({
color: 'blue'
})
}
render() {
return (
<div>
<h1>Parent Component</h1>
<Child titleColor={this.state.color} changeColor={this.handleColor}/>
</div>
);
}
}
export default State;
부모에서 정한 handleColor함수를 props의 changeColor 값으로 전달 해 주고 있다
그러면 자식에서는 아래와 같이 받는다
import React from 'react';
class Child extends React.Component {
render() {
// console.log(this.props);
return (
<div>
<h1 style={{color : this.props.titleColor}}>Child Component</h1>
<button onClick={this.props.changeColor}>Click</button>
</div>
);
}
}
export default State;
Child 컴포넌트 내부에 button태그로 onclick 이벤트가 발생되고 그 이벤트 발생시
props 객체의 changeColor가 실행되며 부모로부터 전달받은 handleColor 함수가 실행된다
그 함수는 setState 함수를 호출하여 state의 color 값을 blue로 변경 시킨다.
그러면 state가 바뀌었기 때문에 render 함수가 다시 재 실행된다
state
state란 컴포넌트 내부에서 가지고있는 컴포넌트의 상태 값이다
즉 사용자는 이 state값이 어떻게 설정되어 있는지 알 수가 없으며 철저히 숨겨져 있는다
또한 state를 설정 하려면 constructor 함수를 작성하여 설정해야 한다
아래의 코드를 확인해보자
class App extends Component {
constructor(props){
super(props);
this.state = {
subject:{title:'WEB', sub:'World Wide Web!'}
}
}
render() {
return (
<div className="App">
<Subject title={this.state.subject.title} sub={this.state.subject.sub}></Subject>
<Subject title="React" sub="For UI"></Subject>
<TOC></TOC>
<Content title="HTML" desc="HTML is HyperText Markup Language."></Content>
</div>
)
}
}
위 코드를 보면 상위 App이라는 클래스에 constructor 함수를 작성하였고 그 안에
state로 App이라는 컴포넌트가 가지고 있는 자신의 상태값을 설정했다
또한 constructor는 처음 초기화를 시켜주기 때문에 render함수 이전에 설정이 되어야 하며
만약 state의 값을 바꿔주면 render 함수가 다시 호출된다
(왜냐하면? 초기화를 했으니 그것에 맞게 다시 호출을 하는 것이다!!)
App컴포넌트가 state값을 하위 Subject 컴포넌트에게 props의 값으로 전달을 하였다.
누가 전선이 튀어나와 있는 핸드폰을 좋아할 수 있을까?
그것과 마찬가지로 state는 철저히 내부에 숨겨져서 사용자가 모르게 해야한다
요번에는 state가 복수일때는 어떻게 할까?
아래의 코드 확인 !
class App extends Component {
constructor(props){
super(props);
this.state = {
contents:[
{id:1, title:'HTML', desc:'HTML is HyperText ...'},
{id:2, title:'CSS', desc:'CSS is for design ...'},
{id:3, title:'JavaScript', desc:'JavaScript is for interactive ...'}
]
}
}
render() {
return (
<div className="App">
<TOC data={this.state.contents}></TOC>
</div>
)
}
}
위와 같이 부모인 App 클래스에서 contents라는 배열이 담긴 state를 만든 다음 자식에게
props를 통해서 전달을 해준다 그 뒤 자식은 아래와 같이 받는다.
class TOC extends Component {
render() {
let lists = [];
let data = this.props.data;
let i = 0;
while(i < data.length){
lists.push(<li><a href={"/content/"+data[i].id}>{data[i].title}</a></li>);
i = i + 1 ;
}
return (
<nav>
<ul>
{lists}
</ul>
</nav>
);
}
}
TOC라는 자식 컴포넌트에 lists라는 빈 배열을 생성한 뒤 data라는 변수에 this.props.data를 담고
그 길이만큼 반복해서 lists 배열에 엘리먼트를 생성하여 넣어준다
주의해야할게 여기서 여러개의 엘리먼트를 자동으로 생산하고 있는데
정상적으로 페이지는 동작 할지언정 console창에는
Warning: Each child in a list should have a unique "key" prop. 라는 에러가 뜨고 있다
key라고 하는 props를 가지고 있어야 된다는 뜻이다
해결 방법은 지속적으로 생산하고있는 li태그안에
<li key={data[i].id}>
이렇게 우리가 확인하려고 넣은 것이 아닌 리액트에게 설명 하기 위해 넣는 key값을 넣어 줘야 한다