본문 바로가기
Front-End/React

[React] 5. State와 생명주기

by hongdor 2021. 2. 1.
728x90

출처: 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')
);

 

**공식 설명

  1. <Clock />가 ReactDOM.render()로 전달되었을 때 React는 Clock 컴포넌트의 constructor를 호출합니다. Clock이 현재 시각을 표시해야 하기 때문에 현재 시각이 포함된 객체로 this.state를 초기화합니다. 나중에 이 state를 업데이트할 것입니다.
  2. React는 Clock 컴포넌트의 render() 메서드를 호출합니다. 이를 통해 React는 화면에 표시되어야 할 내용을 알게 됩니다. 그 다음 React는 Clock의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트합니다.
  3. Clock 출력값이 DOM에 삽입되면, React는 componentDidMount() 생명주기 메서드를 호출합니다. 그 안에서 Clock 컴포넌트는 매초 컴포넌트의 tick() 메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청합니다.
  4. 매초 브라우저가 tick() 메서드를 호출합니다. 그 안에서 Clock 컴포넌트는 setState()에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행합니다. setState() 호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render() 메서드를 다시 호출합니다. 이 때 render() 메서드 안의 this.state.date가 달라지고 렌더링 출력값은 업데이트된 시각을 포함합니다. React는 이에 따라 DOM을 업데이트합니다.
  5. 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')
);
728x90

'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

댓글