import React from 'react';
class State extends React.Component {
constructor() {
super();
this.state = {
color: 'red'
};
}
render() {
return (
<div>
<h1>Class Component | State</h1>
</div>
);
}
}
export default State;
render 함수가 필요하고 화면에 나타내고 싶은 JSX 요소가 return문 안에 들어있습니다.render 함수 위에 constructor 함수를 보도록 하겠습니다.constructor 함수를 작성하여 설정합니다.constructor 함수는 컴포넌트 선언문(class State extends Component)과 render 함수 사이에 작성합니다.constructor에서 super(props) 를 호출 한 이유는, 컴포넌트를 만들게 되면서, Component를 상속했으며, 이렇게 constructor를 작성하게 되면 기존의 클래스 생성자를 덮어쓰게 됩니다. 그렇기에, 리액트 컴포넌트가 지니고있던 생성자를 super 를 통하여 미리 실행하고, 그 다음에 우리가 할 작업 (state 설정) 을 해주는 것 입니다
import React, { Component } from 'react';
class Counter extends Component {
state = { //객체형으로 정의
number: 0
}
class fields 문법을 사용해서 이렇게 간단히 쓰는 방법도 있습니다.
👉메소드 작성
handleIncrease = () => {
this.setState({
number: this.state.number + 1
});
}
handleDecrease = () => {
this.setState({
number: this.state.number - 1
});
}
👉setState
state 에 있는 값을 바꾸기 위해서는, this.setState 를 무조건 거쳐야합니다.
리액트에서는, 이 함수가 호출되면 컴포넌트가 리렌더링 되도록 설계되어있습니다.
setState는, 객체로 전달되는 값만 업데이트를 해줍니다.
지금은 state 에 number값 밖에 없지만 만약에 다음과 같이 다른 값이 있다고 가정해봅시다.
state = {
number: 0,
foo: 'bar'
}
그러면, this.setState({ number: 1 }); 을 하게 된다면, foo 는 그대로 남고, number 값만 업데이트 됩니다.
setState 는 객체의 깊숙한곳 까지 확인하지 못합니다. 예를들어서, state 가 다음과 같이 설정되어있다고 가정한다면요,
state = {
number: 0,
foo: {
bar: 0,
foobar: 1
}
}
아래와 같이 한다고 해서 foobar 값이 업데이트 되지 않습니다.
this.setState({
foo: {
foobar: 2
}
})
이렇게 하게된다면 그냥 기존의 foo 객체가 바뀌어버립니다.
{
number: 0,
foo: {
foobar: 2
}
}
그 대신에 위와 같은 상황에서는 이렇게 해주어야합니다:
this.setState({
number: 0,
foo: {
...this.state.foo,
foobar: 2
}
});
... 은 자바스크립트의 전개연산자 입니다. 기존의 객체안에 있는 내용을 해당 위치에다가 풀어준다는 의미죠. 그 다음에, 우리가 설정하고 싶은 값을 또 넣어주면 해당 값을 덮어쓰게 됩니다.
👉setState에 객체 대신 함수를 전달하기
setState 를 사용하여 값을 업데이트하게 될 때, 기존의 값을 참고하여 값을 업데이트를 하게 될 때, 조금 더 나은 문법으로 할 수 있습니다
기존에 작성했던 코드는 이랬죠?
this.setState({
number: this.state.number + 1
});.
굳이 또 this.state 를 조회해야 하는데요, 이렇게 하면 조금 더 멋진 문법으로 작성 할 수 있습니다.
this.setState(
(state) => ({
number: state.number
})
);
setState 에 updater 함수를 만들어서 전달해 주었습니다. 여기서 조금 더 나아가면 이렇게 작성 할 수 있습니다.
this.setState(
({ number }) => ({
number: number + 1
})
);
==
const { number } = this.state;
this.setState({
number: number + 1
})
기존함수 또한 간단히 해볼수있습니다.
handleIncrease = () => {
const { number } = this.state;
this.setState({
number: number + 1
});
}
handleDecrease = () => {
this.setState(
({ number }) => ({
number: number - 1
})
);
}
👉이벤트 설정
render 함수에서 이벤트 설정을 한 부분을 확인해봅시다.
render() {
return (
<div>
<h1>카운터</h1>
<div>값: {this.state.number}</div>
<button onClick={this.handleIncrease}>+</button>
<button onClick={this.handleDecrease}>-</button>
</div>
);
}
버튼이 클릭되면 우리가 준비한 함수가 각각 호출되도록 설정해주었습니다.
<button onclick="alert('hello');">Click Me</button>
html 에서는 onclick 속성에 클릭되면 실행 할 자바스크립트를 문자열 형태로 넣어줍니다. 반면 우리가 작성한 코드를 다시 봐보세요.
<button onClick={this.handleIncrease}>+</button>
⚡여기서 정말로 주의해 주어야 하는데, 리액트에서 이벤트 함수를 설정할때 html 과 다음과 같은 사항이 다르다.
- 이벤트이름을 설정 할 때 camelCase로 설정해주어야 한다.
- 이벤트에 전달해주는 값은 함수 여야 한다. 만약에 onClick={this.handleIncrease()} 이런식으로 하게 된다면, 렌더링을 할 때 마다 해당 함수가 호출이된다. 그렇게 되면 렌더링 -> 함수 호출 -> setState -> 렌더링 -> 함수 호출 -> 무한반복.. 이렇게 되버린다!