출처: React 공식 홈페이지
State and Lifecycle – React (reactjs.org)
1. 3번째 게시물의 element 예제에서 Clock 컴포넌트를 분리한 것
**전
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
**후
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick(){
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
2. props 없이도 스스로 동작하게 만들기.
- <Clock date={new Date()} /> 를 <Clock /> 로
> state가 필요하다.
> state가 변하면 다시 렌더링한다.
(1) Clock을 클래스로 변환
class Clock extends React.Component{
render(){
return(
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
(2) constructor 생성 후 state 추가
>> props를 기본 constructor에 전달하는 방법 유의 : super(props) 는 항상 필수적이다.
class Clock extends React.Component{
constructor(props){
super(props);
this.state = {date: new Date()};
}
render(){
return(
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
3. props을 삭제
**전
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
**후
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
4. 매초 스스로 업데이트 하도록 만들기 - setInterval를 대체
마운팅 메서드 : Clock이 처음 DOM에 렌더링 될 때마다 실행
언마운팅 메서드 : Clock에 의해 생성된 DOM이 삭제될 때 실행
>> 마운팅, 언마운팅 메서드 같이 생성, 삭제 와 관련된 함수를 '생명주기 메서드'라고 부른다.
class Clock extends React.Component{
constructor(props){
super(props);
this.state = {date: new Date()};
}
componentDidMount(){
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount(){
clearInterval(this.timerID);
}
tick(){
this.setState({
date: new Date()
});
}
render(){
return(
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
**공식 설명
- <Clock />가 ReactDOM.render()로 전달되었을 때 React는 Clock 컴포넌트의 constructor를 호출합니다. Clock이 현재 시각을 표시해야 하기 때문에 현재 시각이 포함된 객체로 this.state를 초기화합니다. 나중에 이 state를 업데이트할 것입니다.
- React는 Clock 컴포넌트의 render() 메서드를 호출합니다. 이를 통해 React는 화면에 표시되어야 할 내용을 알게 됩니다. 그 다음 React는 Clock의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트합니다.
- Clock 출력값이 DOM에 삽입되면, React는 componentDidMount() 생명주기 메서드를 호출합니다. 그 안에서 Clock 컴포넌트는 매초 컴포넌트의 tick() 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청합니다.
- 매초 브라우저가 tick() 메서드를 호출합니다. 그 안에서 Clock 컴포넌트는 setState()에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행합니다. setState() 호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render() 메서드를 다시 호출합니다. 이 때 render() 메서드 안의 this.state.date가 달라지고 렌더링 출력값은 업데이트된 시각을 포함합니다. React는 이에 따라 DOM을 업데이트합니다.
- Clock 컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount() 생명주기 메서드를 호출합니다.
** 내설명
<Clock/> → constructor 호출 → // render() → DOM 생성 → 마운트 메서드 실행 → tick() 메서드 실행 → state 변화 → render() → 반복..
5. State 올바르게 사용하기
(1) State 직접 수정 금지
잘못된 예 - 컴포넌트를 다시 렌더링 하지 않음.
this.state.comment = 'Hello';
바른 예 - 컴포넌트 수정.
this.setState({comment: 'Hello'});
(2) props와 state는 비동기 적이므로 state와 props 값이 서로 의존관계이면 안된다.
> 굉장히 빠르게 반복될 경우, state 와 props 사이에 업데이트 속도 차이가 생길 수 있다.
> 매개변수로 받아 해결한다.
잘못된 예)
this.setState({
counter: this.state.counter + this.props.increment,
});
바른 예)
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
혹은
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
(3) State 업데이트는 병합됩니다. 즉, 독립적으로 업데이트할 수 있다.
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
this.setState({comments})는 this.state.posts에 영향을 주지 않는다.
그저 this.state.comments만 업데이트 한다.
(4) 데이터는 아래로 흐른다.
> 컴포넌트는 자신의 state를 자식 컴포넌트에 props로 전달할 수 있다.
<FormattedDate date={this.state.date} />
function FormattedDate(props) {
return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}
(5)
모든 state는 오직 자신의 '아래'에 있는 컴포넌트에만 영향을 미친다.
물론 state 컴포넌트 안에 state가 없는 컴포넌트를 포함할 수 도 있고, 그반대도 가능하다.
***완성코드***
** 완성
class Clock extends React.Component{
constructor(props){
super(props);
this.state = {date: new Date()};
}
componentDidMount(){
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount(){
clearInterval(this.timerID);
}
tick(){
this.setState({
date: new Date()
});
}
render(){
return(
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
)
}
}
function App() {
return (
<div>
<Clock />
<Clock />
<Clock />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
'Front-End > React' 카테고리의 다른 글
[React] 7. 조건부 렌더링 (0) | 2021.02.01 |
---|---|
[React] 6. 이벤트 처리하기 (0) | 2021.02.01 |
[React] 4. Component와 Props (0) | 2021.02.01 |
[React] 3. Element (0) | 2021.02.01 |
[React] 2. JSX (0) | 2021.02.01 |
댓글