리액트에서의 state
는 컴포넌트 내부에서 바뀔 수 있는 값이다.
전에 살펴보았던 props
는 부모 요소에서 설정하기 때문에 읽기 전용만 되었는데, state는 이 친구와 다른 성질을 가지고 있다고 말할 수 있다. :)
전달받은 값을 state
를 이용하여 어떻게 바꿀 수 있을까?
constructor(props) {
super(props); //state의 초기값 설정하기
this.state = {
number : 0
};
}
먼저 state
의 초기값을 지정해보자. 우리는 이를 위해서 사용해야 하는 것이 바로 constructor
라는 컴포넌트의 생성자 메서드이다. (그냥 암기하삼) constructor
을 작성할 때에는 반드시 super(props)
를 호출해 주어야 한다.
super
함수가 호출되면, 현재 클래스형 컴포넌트가 상속받고 있는 리액트의 Component 클래스가 지닌 생성자 함수를 호출해 준다. 그리고 this.state
에 초기값을 설정해 주어용.
render() {
const {number} = this.state;
return (
<div>
<h1>number</h1>
<button onClick = {() => { this.setState({number : number + 1 }); }}
//this.setState를 사용하여 state에 새로운 값을 집어넣습니다.
</div>
);
}
위와 같이 사용 가능하다.
여러가지 state
를 사용한다면 여러가지 state
그냥 골라서 쓰면 된다.
그럼 아래와 같이 작성 가능합니당
state = {
number : 0,
fixedNumber : 0
};
이렇게 써도 된다. 메서드를 복잡하게 안써도 된다!
위에서 작성하였던 코드는 setState
에 함수를 전달하였다.
우리가 this.setState
를 사용하여 state 값을 업데이트하면 상태가 비동기적으로 업데이트됩니다.
아래 코드 예시를 볼까용
onClick = {() => {
this.setState({number : number + 1 });
this.setState({number : this.state.number + 1 });
}
코드를 위와 같이 작성하게 되면, this.setState
를 두 번 사용하는데도, 1밖에 숫자가 더해지지 않는다. 그 이유는 , this.setState
를 사용한다고 해서 state의 값이 바로 바뀌지 않기 때문입니다!
그래서 옛날에 콘솔창에 찍어볼 때 고생 많이 했지.. 왜 한번에 바뀌지 않느냐며..ㅠㅠ
이를 해결하기 위해서는 this.setState
를 사용할 때, 객체 대신에 함수를 인자로 넣어주는 것이다.
this.setState((prevState, props) => {
return {
//업뎃하고 싶은 내용
}
})
여기서 prevState
는 기존 상태이고, props
는 현재 지내고 있는 props
를 가리킵니다. 만약 props
가 필요하지 않는다면 생략해도 된다.
this.setState((prevState => {
return {
number : prevState.number + 1
};
});
이렇게 preState
를 사용하여 작성해도 되고,
this.setState((prevState => ({
return {
number : prevState.number + 1
};
}));
이렇게 객체를 바로 반환해도 된다!
setState
함수의 두번째 파라미터로 콜백함수를 받을 수 있다.
onClick = {() => {
this.setState({number : number + 1 }, () => {console.log('방금 setState 수행완료함'); console.log(this.state);});
}}
배열 비구조화 할당이 무엇일까?
배열 안에 있는 값을 쉽게 추출할 수 있도록 해 주는 문법
const array = [1, 2];
const one = array[0];
const two = array[1];
이에 대하여 배열 비구조화 할당을 이용해보자.
const array = [1,2];
const [one, two] = array;
훨씬 간단하게 사용 가능하다. 객체랑 비교해서 다시 복습하고 잘 써먹을 수 있도록 하자
import React, { 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
함수의 인자에는 상태의 초기값을 넣어줍니다.
어기서 이 초기값은 꼭 객체가 아니여도 된다. (클래스형은 무조건 객체여야 했음). 수일수도 있고, 문자열일 수도, 객체일수도, 배열일수도 있다.
useState
함수를 호출하면 배열이 반환된다. 첫번째 원소는 현재 상태이고, 두번째 원소는 상태를 바꾸어주는 함수이다. 이 함수를 새터함수(Setter)라고 한다. 배열 비구조화 할당을 통하여 이름을 자유롭게 정해준 것이다.
이것은 한 컴포넌트에서 여러번 사용하여도 괜찮다!! 막써라잉
state의 값을 바꾸고 싶다고 아래와 같이 쓴 경험이 많다.
this.state.number = this.state.number + 1;
this.state.array = this.array.push(2);
this.state.object.value = 5;
const [object, setObject] = useState({a : 1, b: 1});
object.b = 2;
값을 업데이트 할 때에는 꼭 배열이나 객체 사본을 만들고, 그 사본에 값을 업데이트해주세요 그리고 그 사본의 상태를 새터 함수를 통하여 업데이트해주세요
아래 예시를 통하여 확인해봅시다~
const object = { a : 1, b : 2, c : 3 };
const nextObject = { ...object, b : 2 }; //사본을 만들고, b 값만 덮어쓰기!
const array = [
{id : 1, value : true },
{id : 2, value : true },
{id : 3, value : false},
];
let nextArray = array.concat({id : 4}); //새 항목 추가!
nextArray.filter(item => item.id !==2); //id가 2인 항목 제거
nextArray.map(item => (item.id === 1 ? {...item, value : false } : item)); //id 1인거 false
글 잘 읽고가요!