[React] props와 state

리액트의 class 컴포넌트에서 다루는 데이터는 두개로 나뉜다. 

props와 state이다.

모든 언어에서는 재활용성과 중복의 제거를 중요시한다고 배웠다. 

이러한 재활용성과 중복의 제거를 토대로 코드의 재활용성을 높이기위해서 사용된것이 props이다. 


props

작성된 컴포넌트에 props를 통해 부모컴포넌트에서 자식컴포넌트로 값을 전달하면 내가 원하는 값이 자식 컴포넌트에서 작성한 템플릿에 값을 넣어 반환한다.

props는 html코드에서 attribute(속성)과 비슷한 형태로 작성되고 이렇게 작성된 props로 전달되는 값을 자식 컴포넌트에서 {this.props.속성명}으로 부모컴포넌트에서 전달한 props 값을 전달 받아 출력한다.

아래의 예제를 보면 

App.js 는 부모컴포넌트
Introduce.js 는 자식 컴포넌트

App.js

import React, { Component } from 'react';
import Introduce from './Introduce';

export default class App extends Component {
render() {
return (
<div>
<Introduce name='리액트' age='100' /><br />
<Introduce name='자바스크립트' age='200' gender='중성' /><br />
<Introduce name='CSS' age='300' gender='남자' /><br />
<Introduce name='컴포넌트' age='400' gender='여자' /><br />
</div >
)
}
}


Introduce.js

import React, { Component } from 'react'

export default class Introduce extends Component {
static defaultProps = {
gender: '미작성'
}
render() {
return (
<div>
<div>반갑습니다!</div>
<div>제 이름은 <b>{this.props.name}</b> 입니다.</div>
<div>제 나이는 <b>{this.props.age}</b> 입니다.</div>
<div>제 성별은 <b>{this.props.gender}</b> 입니다.</div>
</div>
)
}
}

// Introduce.defaultProps = {
// gender: '미작성'
// }

상위 컴포넌트인 App.js 에서 하위 컴포넌트 Introduce.js로 값을 전달하여 자기가 원하는 값대로 결과값을 출력할 수 있다.


위 코드에 대한 결과는  아래와 같이 출력된다.



하나의 컴포넌트를가지고 4개의 다른 값을가진 컴포넌트를 출력할 수 있다. (코드 재활용성 증가)


그리고 props로 값을 전달받아 출력된 내역을 확인해보면 

첫번째줄 부모컴포넌트에 props의 값으로 name에 '리액트'를 전달하고 다른 컴포넌트들과 다르게 gender의 props값을 전달하지 않았다.

props로 값을 전달하지 않았을때 아무것도 출력되지 않으므로 기본값을 설정해서 아무것도 작성하지 않았을때는 위처럼 '미작성' 이라는 기본값이 출력되도록 할 수 있다. 


props로 값을 전달받는 자식컴포넌트 Introduce에 기본값 설정1 또는 설정2 중 하나를 작성하면 props로 아무것도 전달되지 않았을때 해당 값으로 대체된다.

기본값 설정1
static defaultProps = {
gender: '미작성'
}

기본값 설정2
Introduce.defaultProps = {
gender: '미작성'
}


위에서는 static defaultProps를 사용했고 코드 아래에 주석처리된부분처럼 작성해도 동일하게 동작한다.



요약하면 props는 부모 컴포넌트가 자식 컴포넌트에게 전달하는 값이다.

props를 활용하면 코드의 재활용성이 높아진다. 

자식 컴포넌트는 props를 받기만하며 props를 직접 수정할 수 없다. 즉 자식컴포넌트는 값을 받기만 가능하다.

그 이유는 자식 컴포넌트에서 props를 변경하면 부모컴포넌트의 데이터도 변경을 해주어야하므로 부모컴포넌트가 뜻하지 않게 데이터의 변경이 발생될 수 있다.

만약 props로 받은 데이터를 자식 컴포넌트에서 수정해야 한다면 자식 컴포넌트 내부에 state를 선언하여 값을 수정해야한다. 그래야지 부모컴포넌트에 영향을 미치지 않는다.




state

화면상에서 변경이 일어나는 모든 부분의 데이터를 state에 작성한다. 주의사항으로는 수동으로 변경시키는 값들만 state값으로 작성해야 한다.

state는 Component 내부에 존재하는 동적인 값 즉, 변경이 가능한 데이터를 가지는 객체이다. 

state의 값을 변경할 때에는 setState를 사용하여야 값을 변경할 수 있다. setState메소드가 호출되어야만 컴포넌트가 리렌더링되어 업데이트된 값을 화면에 보여준다. 

매 순간 setState를 호출할 때 마다 react는 새로운 state값과 함께 render함수를 호출한다.

setState를 사용하지 않고 직접적으로 object인 state의 값을 변경시키면 컴포넌트의 html요소들의 값이 업데이트 되지않고 그대로 화면에 출력하게되어 화면에서 원하는 값을 확인할 수 없다.

React의 state값은 setState 객체로 전달되는 값만 업데이트를 해준다.

setState는 비동기로 동작한다.

state를 사용하기위해서는 클래스형 컴포넌트를 사용하여야 하며 클래스형 컴포넌트를 class field라고도 한다.

렌더링될 때 데이터 흐름에 사용되는 값들만 state에 포함시키고 그렇지 않은데이터는 정적인 데이터로 관리하는 것이 좋다.

렌더링이나 데이터 흐름과 관련없는 모든 데이터들을 state에 넣으면 state가 변경될때마다 Component 리렌더링이 발생되는데 이때 괴장히 무거워질 수 있다.(느려질 수 있다)


setState 사용 방법

App.js
import React, { Component } from 'react';
import Counter from './Counter';

export default class App extends Component {
render() {
return (
<div>
<Counter />
</div >
)
}
}


Counter.js
import React, { Component } from 'react'

export default class Counter extends Component {

state = {
count: 0
}

handleIncrease = () => {
this.setState((prevState, props) => ({
count: prevState.count + 1
}))
}

handleDecrease = () => {
this.setState({
count: this.state.count - 1
})
}

render() {
return (
<div>
<h1>카운터</h1>
<div>값: {this.state.count}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
)
}
}



State의 값을 this.state.count로 증감 시켜도 되지만 setState 에 콜백 함수를 사용하면 첫번째 인자로 이전의 state값을 가져와 값을 증감 시킬 수 있으며 두번째 인자로 props 값을 받을 수 있다.


추가적으로 리액트에서는 text값도 setState를 사용하여야지만 값을 입력 받을 수 있다.


하지만 리액트에서 input의 value속성에 props값으로 null를 주면 setState없이도 사용자의 입력값을 받을 수 있다.

ex)
<input value={null} />


추가적으로 render함수 안에서는 setState를 사용하면 무한루프가 발생하기 때문에 setState는 render 함수 내부에 작성하지 않도록 한다.


이벤트 설정

1. 리액트에서 이벤트 함수를 설정할 때 camleCase로 작성해주어야 한다. ex) onClick, onMouseDown, onChange

2. 이벤트에 전달해주는 값은 함수여야 한다. 
주의할점이있는데 함수를 전달할때 함수실행으로 값을 전달하면 안된다! 

예를들어 숫자를 추가해주는 add 함수가 있다고 가정하고 onClick 이벤트가 발생했을 때 add 함수를 실행시켜주는 이벤트를 설정하고 싶다면 onClick={add} 와 같이 함수를 전달해줘야한다. 

이렇게 전달하지않고 즉시 실행하도록 함수를 onClick={add()} 와 같이 전달하게 될 경우 onClick이벤트가 발생하지 않아도 함수가 즉시 실행되어 원하는데로 동작하지 못한다.


댓글