props와 유사하지만, 비공개이며 컴포넌트에 의해 제어됨.
함수에서 클래스로 변환하기
- React.Component를 상속받는 class 생성
class Clock extends React.Component
- render() 라는 메서드를 선언해, 그 안에 함수를 작성
render() { return ( ~~ ) }
- 함수형에서 사용했던 props를 this.props로 변경
render() 메서드 안에 있는 this.props.data
를 this.state.date
로 변경
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
class 내부에 state를 초기화하는 constructor를 추가
constructor (props){
super(props);
this.state = {date: new Date()};
}
컴포넌트 인스턴스가 생성되어 DOM이 렌더링 될 때마다 특정 함수를 실행시키는 것.
마운팅시 다음 함수를 순서대로 호출
메서드를 바인딩하지 않거나 state를 사용하지 않는다면 해당 컴포넌트는 생성자를 구현하지 않아도 됨.
React 컴포넌트의 생성자는 해당 컴포넌트가 마운트되기 전에 호출됨. 생성자에 제일 먼저 super(props)를 호출해야 this.props가 생성자 내에 정의될 수 있음.
생성자의 목적
coustructor() 내부에서는 setState() 호출 불가능
생성자는 this.state를 직접 할당할 수 있는 유일한 곳
state에 props 복사 금지
this.state = { color : props.color} ❎
-> props의 갱신을 의도적으로 무시해야할 때만 사용
this.state = this.props.color ✅
이 메서드 호출시 this.props와 this.state의 값을 활용해 반드시 다음의 값 중 하나를 반환해야함.
항상 순수함수로 작동해야함. (인풋값에 따른 리턴값이 항상 일정)
react 엘리먼트
보통 JSX를 사용하여 생성
<div></div>
배열과 Fragment
render()를 통해 여러개의 react엘리먼트를 반환
fragment를 배열로 매핑하는 경우, fragments에 key가 있다면 명시적으로 선언해야함.
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// React는 `key`가 없으면 key warning을 발생합니다.
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</React.Fragment>
))}
</dl>
);
}
클래스의 render()메소드가 호출되면 DOM을 업데이트함.
출력값이 DOM에 삽입되면 그 때 componentDidMount(){}
호출됨.
외부에서 데이터를 불러올 때 사용되기도 함. (데이터 구독)
-> 이런 경우 componentWillUnmount() 에서 구독 해제 작업 필요
모달이나 툴팁과 같이 렌더링 전에 DOM노드의 크기나 위치를 먼저 측정해야하는 경우, 함수 안에 즉시 setState()를 설정하기도 함.
props 또는 state가 변경되면 갱신.
추가적인 렌더링 없이 props의 변화에 따라 state를 안전하게 업데이트해주는 방법
잘 사용되지 않음
현재 state가 변할 때마다 다시 렌더링을 수행
기본값은 true이며, false 반환시 아래의 함수들이 호출되지 않음.
코드 업데이트 직후 호출되며, 최초 렌더링에선 호출되지 않음.
이전과 현재의 props를 비교하여 네트워크 요청을 보내는 작업에 유용
(만약 props가 변하지 않았다면 요청 보내지 않기)
조건문으로 감싸지 않는다면 무한 반복이 발생함.
부모에게서 전달받은 props를 state에 넣어 저장하는 것보다 props자체를 사용하는 것이 좋음.
DOM이 삭제될 때마다 특정 함수 실행
componentWillUnmount(){}
렌더링한 컴포넌트가 DOM으로부터 삭제되는 순간 componentWillUnMount(){}
호출
이 컴포넌트는 다시 렌더링 하지 않으므로 setState()를 호출하면 안됨. -> 값이 저장되지 않음
위 상황에서 오류가 발생시 호출되는 함수들
기존에 사용되었지만 사용 권장되지 않음 (2018)
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
직접적으로 this.state.greeting = 'hello'
로 지정하게 되면 코드는 컴포넌트를 다시 렌더링하지 않아 DOM이 변경사항에 대해 업데이트 되지 않는다. 그래서 this.setState({greeting : 'Hello'})를 이용해 값을 지정해주어야 함.
React자체에서 setState()호출를 성능을 위해 한번에 처리하는 경우가 있음.
그렇기 때문에 setState안에 직접적으로 this.state, this.props 등을 입력하는 경우, 값이 업데이트되지 않아 예상했던 값과 다르게 나오는 경우가 있음.
이럴때를 대비하기 위해
this.setState((state, props) => ({
greeting : state.greeting + props.shaking})
이런식으로 사용 가능함.
setState()를 호출할 때, 제공된 객체를 현재 state로 병합
state에는 여러가지 변수들을 넣어 한번에 선언이 가능한데, 별도의 호출을 통해 독립적으로 업데이트할 수도 있음.
컴포넌트는 서로에 대한 정보를 갖고 있지않아, state로 컴포넌트간 연결을 시켜줌
state가 소유하고 설정한 컴포넌트 이외에는 어떤 컴포넌트도 접근할 수 없기 때문에, state는 로컬 또는 캡슐화라고 불리기도 함
컴포넌트는 자신의 state를 자식의 props로 전달 할 수 있으며, 자식은 props로 받기때문에 이게 부모의 state인지 props인지 알지 못함. 이를 하향식(top-down) 데이터 흐름이라고 함. 모든 데이터의 흐름은 아래로 내려가기 때문에 각자의 자식에만 영향을 미칠 수 있음.
React앱에서 컴포넌트의 state가 존재하는지 여부는 후에 수정될 수 있기 때문에, state가 없는 class의 자식으로state가 있는 클래스가 나올 수 있고 그 반대의 경우도 가능할 수 있음.