
리액트에서 state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미합니다.
props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 설정하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있습니다. props를 바꾸려면 props를 바꾸려면 부모 컴포넌트에서 바꾸어 주어야 합니다.
App 에서 props를 바꾸어야 값이 변경되는 것이고, MyComponent에서는 전달 받은 name 값을 직접 바꿀 수 없습니다.
리액트에는 두가지 종류의 state가 있으며,
import { Component } from "react";
class Counter extends Component{
constructor(props){
super(props);
this.state = {
number:0
};
}
render(){
const{ number } = this.state;
return(
<div>
<h1>{number}</h1>
<button
onClick={() => {
this.setState({ number: number + 1});
}}>+1
</button>
</div>
)
}
}
export default Counter;
컴포넌트에 state를 설정할 때는 다음과 같이 constructor 메서드를 작성하여 설정합니다.
constructor(props){
super(props);
//초기값 셋팅
this.state = {
number:0
};
}
클래스형 컴포넌트에서 constructor를 작성할 때는 반드시 super(props)를 호출해 주어야 합니다.
이 함수가 호출되면 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해 줍니다.
그다음에는 this.state 값에 초기값을 설정해 주었습니다. 컴포넌트의 state는 객체 형식이어야 합니다.
render() 함수에서 현재 state를 조회할 때는 this.state를 조회하면 됩니다.
state 객체 안에는 여러 값이 있을 수 있습니다. Counter 컴포넌트를 수정해 봅시다.
import { Component } from "react";
class Counter extends Component{
constructor(props){
super(props);
this.state = {
number:0,
//새로운 변수 생성
fixedNumber: 0
};
}
render(){
//추가
const{ number, fixedNumber } = this.state;
return(
<div>
<h1>{number}</h1>
//연결
<h1>바뀌지 않는값: {fixedNumber}</h1>
<button
onClick={() => {
this.setState({ number: number + 1});
}}>+1
</button>
</div>
);
}
}
export default Counter;
fixedNumber 값을 새롭게 만들어서 넣어보았습니다.
앞으로 포깃값을 지정하기 위해 constructor 메서드를 선언해 주었는데요, 다른 방식으로도 가능하기에 수정해 봅시다.
import { Component } from "react";
class Counter extends Component{
state = {
number: 0,
fixedNumber: 0
}
render(){
const{ number, fixedNumber } = this.state;
return(
<div>
<h1>{number}</h1>
<h1>바뀌지 않는값: {fixedNumber}</h1>
<button
onClick={() => {
this.setState({ number: number + 1});
}}>+1
</button>
</div>
);
}
}
export default Counter;
위에랑 비교하였을때 확연히 쉽죠 ?
setStatef를 사용하여 state 값을 업데이트 할 때는 상태가 비동기적으로 업데이트 됩니다.
예를 들어 onClick 함수 내에서 this.setState를 두번 호출하면 어떻게 될까요?
onClick={() ⇒ { this.setState({ number: number+1}); this.setState({ number: this.state.number +1 }); }
위와 작성 할 경우 number의 값이 두번 1씩 증가해야 하지만, 1씩 밖에 증가하지 않습니다.
이를 해결하기 위해서는 객체 대신 함수 인자로 넣어 주는 것입니다.
this.setState((prevState , props) ⇒ { return {number: prevState.number + 1} })
prevState 는 기존 상태이고, props 는 현재 지니고 있는 props를 가르킵니다. props는 생략이 가능합니다.
위에는 아래처럼도 생략이 가능합니다.
this.setState(prevState ⇒ ({ number: prevState.number + 1 }));
setState를 사용하여 값을 업데이트 하고 난 다음에 특정 작업을 하고 싶을 때는 setState의 두 번째 파라미터로 콜백 함수를 등록하여 처리할 수 있습니다.
import { Component } from "react";
class Counter extends Component{
state = {
number: 0,
fixedNumber: 0
}
render(){
const{ number, fixedNumber } = this.state;
return(
<div>
<h1>{number}</h1>
<h1>바뀌지 않는값: {fixedNumber}</h1>
<button
onClick={() => { //() 콜백함수
this.setState({ number: number + 1},()=>{
console.log("콜백함수 실행")
});
}}>+1
</button>
</div>
);
}
}
export default Counter;
useState를 사용하기 전에는 배열 비구조화 할당 문법을 알아야 합니다.
배열 비구조화 할당 문법이란
const array = [1,2];
const one = array[0];
const two = array[1];
이것을 const [one, two] = array; 이런식으로 바꾸어 주는 겁니다.
이제 새로운 Say.js 컴포넌트를 만들어 입력해 보겠습니다.
import { useState } from "react";
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('안녕하세요!');
const onClickLeave = () => setMessage('안녕히 가세요!');
return(
<diV>
<button onClick={onClickEnter}>입장</button>
<button onClick={onClickLeave}>퇴장</button>
<h1>{message}</h1>
</diV>
);
};
export default Say;
useState 함수의 인자에는 상태의 초기값을 넣어 줍니다.
클래스형 컴포넌트에서의 state 초기값은 객체 형태를 넣어 주어야 한다고 배웠는데요.
useState에서는 반드시 객체가 아니어도 상관없습니다.
배열의 첫 번째 원소는 현재 상태이고, message
두 번째 원소는 상태를 바꾸어 주는 함수 입니다. 이를 세터(Setter)함수라고 부릅니다. setMessage
이는 다르게 text, setText로 바꾸어도 상관이 없습니다.
useState 한 컴포넌트 여러번 사용해도 상관없습니다.
import { useState } from "react";
const Say = () => {
const [message, setMessage] = useState('');
const onClickEnter = () => setMessage('안녕하세요!');
const onClickLeave = () => setMessage('안녕히 가세요!');
const [color, setColor] = useState('black');
return(
<diV>
<button onClick={onClickEnter}>입장</button>
<button onClick={onClickLeave}>퇴장</button>
<h1 style={{ color }} >{message}</h1>
<button style={{ color: 'red' }} onClick={()=> setColor('red')}>빨간색</button>
<button style={{ color: 'blue' }} onClick={()=> setColor('blue')}>파란색</button>
<button style={{ color: 'green' }} onClick={()=> setColor('green')}>초록색</button>
</diV>
);
};
export default Say;
color, setColor를 만들어서 넣어주자 !