props 부모 컴포넌트에서 설정된 값이며, 직접적인 변경이 불가능합니다. ( 불변성 ) Immutable Data 즉, 변하지 않는 데이터입니다.
State 컴포넌트 내부에서 관리되는 값을 의미하며, 변경이 가능하고 변경에 따른 리렌더링이 이루어집니다.
생성자함수
import React, { Component } from "react";
import fergment from "react";
class Counter extends Component {
constructor(props) {
super(props); //클래스형 컴포넌트 생성자에서는 반드시 호출해야합니다.
console.log(this.props); // super(props) 사용이유에 대해 알아보세요
this.state = { // 상태관리를 할 변수들을 객체 형태로 선언합니다.
number: 0,
name : "" //등등
};
}
render() {
const { number, name } = this.state; // 비구조화 할당 문법
console.log(this.props); // super(props) 사용이유에 대해 알아보세요
console.log(this) // Counter{...} this 는 현재 컴포넌트를 가리킵니다. [[prototype]]는 Componenet 입니다.
return (
<fergment>
<div>{number}</div>
<div>
<button
onClick={() => {
this.setState({ number: number + 1 }); // state의 값변경 ( 리렌더링 )
}}
>
increase
</button>
</div>
</fergment>
);
}
}
export default Counter;
생성자 함수를 정의하지 않고 아래와같이 간략하게 사용할 수 있습니다.
import React, { Component } from "react";
import fergment from "react";
class Counter extends Component {
state = { // 상태관리를 할 변수들을 객체 형태로 선언합니다.
number: 0,
name : "" //등등
};
render() {
const { number, name } = this.state; // 비구조화 할당 문법
return (
<fergment>
...code
</fergment>
);
}
}
export default Counter;
setState를 통하여 상태를 업데이트할 때에는 비동기적으로 업데이트 됩니다.
class Counter extends Component {
state = { //state 설정
number: 0,
random: 0,
};
render() {
const { number, random } = this.state; // 변수할당
return (
<fergment>
<div>{number}</div>
<div>
<button
onClick={() => {
this.setState({ number: number + 1 });
this.setState({ number: this.state.number + 1 });
}}
>
increase
</button>
</div>
</fergment>
);
}
}
위와같이 한번의 이벤트핸들러 안에서 2번의 상태를 업데이트하면 어떻게 될까요? 상식적으론 2씩 증가해야하지만 그렇지 않습니다.
setState가 비동기인 이유는 무엇일까요?
setState가 동기적으로 작동한다면 state의 변경에따라 페이지 리렌더링의 수가 상당히 증가할 것입니다. 성능이슈가 발생되겠죠?
위와같은 이유로 setState는 상태를 한번에 종합해서 리렌더링하기위해 비동기로 작업한것입니다.
state 객체의 같은 키값을 가진 경우에는 가장 마지막 실행된 값으로 덮어지게 됩니다.
this.setState({ number: this.state.number + 1 });
이부분이 되겠죠?
해결책
setState의 인자로 함수를 전달하면 됩니다.
<button
onClick={() => {
this.setState((prevState) => {
return {
number: prevState.number + 1,
};
});
this.setState((prevState) => {
return {
number: prevState.number + 1,
};
});
}}
>
increase
</button>
setState 로 값을 설정한 후에 실행되는 callback 함수는 두번째 인자로 넣어주면 됩니다.
<div>
<button
onClick={() => {
this.setState({ number: number + 1 }, () => {
alert("변경후의값은:" + number + "입니다");
});
}}
>
increase
</button>
</div>
</button>
16.8 이전 버전에서 함수형 컴포넌트는 상태관리를 할 수 없었습니다. 이후로 Hooks가 도입되면서 함수형 컴포넌트의 단점들이 사라졌는습니다. 오늘은 useState Hook에 대해 포스팅하겠습니다.
const SayMessege = () => {
const [messege, setMessege] = useState("");
//구조분해 할당 기억나시나요? useState() 함수의 인자는 1번째 배열에 저장되고 2번째 배열은 1번째 배열에 값을 적용해주는 함수가 들어있습니다.
const Hi = () => {
setMessege("어서오세요");
};
const Bey = () => {
setMessege("안녕히가세요");
};
return (
<div>
<div>{messege}</div>
<button onClick={Hi}>입장</button>
<button onClick={Bey}>퇴장</button>
</div>
);
};
export default SayMessege;
주의사항 클래스형, 함수형 모두 상태관리를 위해서는 setter 를 사용하여 값을 변경하여야합니다.
참조타입 데이터의 상태관리는 방법이 다릅니다. 이전에 자바스크립트의 메모리 할당방식에대해 이야기한적이 있습니다.
리액트는 상태를 관리하는 변수의 값이 변했을 때 화면을 리렌더링 합니다. 즉, 데이터가 저장된 메모리 주소가 바뀌었을 때 리렌더링 한다는 말입니다.
참조타입 데이터는 저장된 메모리의 주소를 변경하려면 어떻게해야했었나요? 리액트에서 참조타입 데이터를 리렌더링하려면 완전히 새로운 객체를 만들어주어야 합니다.
const Animals = () => {
const [animals, setAnimal] = useState({name:"",age:""});
setAnimals({...animals,race:""})
}