๐Ÿ“œ reactjs ๊ณต์‹ ๋ฌธ์„œ ์ฝ๊ธฐ - Main Concepts 5

BOHYEON SEOยท2020๋…„ 7์›” 2์ผ
0
post-thumbnail

5. State and Lifecycle

์ด์ „์˜ ticking 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);

์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์ด๋‹ค. (์™„์ „ํ•œ ์บก์Šํ™” + ์žฌ์‚ฌ์šฉ์„ฑ)

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

์ด๋ฅผ ์œ„ํ•ด์„œ state๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

Adding Local State to a Class

Class ํ˜•์œผ๋กœ ์ „ํ™˜ํ•œ ํ›„, state๋ฅผ ์ถ”๊ฐ€ํ•ด์คฌ๋‹ค.

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>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Adding Lifecycle Methods to a Class

2๊ฐ€์ง€ ์ƒํ™ฉ์— ํƒ€์ด๋จธ๋ฅผ ์กฐ์ž‘ํ•ด์ค„ ๊ฒƒ์ด๋‹ค.

  1. DOM์— ์ฒ˜์Œ์œผ๋กœ ๋ Œ๋”๋ง ๋์„ ๋•Œ (mounting)

  2. DOM์—์„œ ์‚ญ์ œ๋์„ ๋•Œ (unmounting)

componentDidMount

componentDidMount๋Š” component์˜ output์ด DOM์— ๋ Œ๋”๋œ ํ›„์— ์‹คํ–‰๋œ๋‹ค.

class Clock extends React.Component {
  
  ... 
  
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  ...
  
}

componentWillUnmount

class Clock extends React.Component {
  
  ... 
  
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  ...
  
}

componentDidMount, componentWillUnmount์™€ ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋“ค์„ "lifecycle methods"๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

this.props๋‚˜ this.state๋Š” ์ด๋ฏธ React์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ this.timerID ๋“ฑ data flow์— ์ฐธ์—ฌํ•˜์ง€ ์•Š๋Š” ์ •๋ณด๊ฐ™์€ ๊ฒƒ๋“ค์€ ์œ„ ์ฝ”๋“œ์—์„œ์ฒ˜๋Ÿผ ์ž์œ ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค.

์ „์ฒด ์ฝ”๋“œ ๋ฐ ์š”์•ฝ

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๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. this.state์— ํ˜„์žฌ ์‹œ๊ฐ„์„ ๋‹ด์•„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

  2. ๊ทธ ํ›„์— React๋Š” Clock component์˜ render() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด(๋ฐ˜ํ™˜๊ฐ’์„ ํ†ตํ•ด) React๋Š” ์–ด๋–ค ๊ฒƒ๋“ค์„ ํ™”๋ฉด์— ๋ Œ๋”ํ•ด์•ผํ•˜๋Š”์ง€ ์•Œ๊ฒŒ ๋œ๋‹ค.

  3. Clock ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ Œ๋”๋ง ๋˜๋ฉด (DOM์— ์ถ”๊ฐ€๋˜๋ฉด), React๋Š” componentDidMount() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ๋ฉ”์†Œ๋“œ์— ์ž‘์„ฑ๋œ๋Œ€๋กœ browser๊ฐ€ timer๋ฅผ set upํ•˜๋„๋ก ํ•˜๊ณ , ๋งค์ดˆ๋งˆ๋‹ค tick() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

  4. ๋งค์ดˆ๋งˆ๋‹ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ tick() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. tick() ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์—์„œ setState() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, React๋Š” setState() ๋ฉ”์†Œ๋“œ ๋•์— state๊ฐ€ ๋ฐ”๋€ ๊ฒƒ์„ ์•Œ์•„ ์ฐจ๋ฆฐ๋‹ค. ๊ทธ๋Ÿผ ๋‹ค์‹œ render() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํ™”๋ฉด์— ๋ Œ๋”ํ•ด์•ผ ํ•˜๋Š” ๋‚ด์šฉ๋“ค์„ ์•Œ์•„๋‚ธ๋‹ค. ๋ฐ”๋€ ๋‚ด์šฉ์ด ์žˆ์œผ๋ฏ€๋กœ React๋Š” DOM์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

  5. Clock component๊ฐ€ DOM์—์„œ ์‚ฌ๋ผ์ง€๋ฉด, componentWillUnmount() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํƒ€์ด๋จธ๋ฅผ ๋ฉˆ์ถ”๊ฒŒํ•œ๋‹ค.

Using State Correctly

setState() ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์„ธ๊ฐ€์ง€

Do Not Modify State Directly

// Wrong
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});

State Updates May Be Asynchronous

this.props์™€ this.state๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค.

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

setState์˜ ๋‘๋ฒˆ์งธ ์‚ฌ์šฉ๋ฒ•์œผ๋กœ ๋ฌธ์ œ ์ƒํ™ฉ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ state, ๋‘๋ฒˆ์งธ ์ธ์ž๋กœ props๊ฐ€ ๋„˜์–ด์˜จ๋‹ค.

// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

State Updates are Merged

setState()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด state object๋ฅผ mergeํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

componentDidMount() {
  fetchPosts().then(response => {
    this.setState({
      posts: response.posts
    });
  });

  fetchComments().then(response => {
    this.setState({
      comments: response.comments
    });
  });
}

The Data Flows Down

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋“ , ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“  ํŠน์ • ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ statefulํ•œ์ง€ statelessํ•œ์ง€๋Š” ์•Œ์ˆ˜ ์—†๋‹ค. ์ด๋Ÿฐ ์ด์œ ๋กœ state๋Š” ์บก์Šํ™” ๋ผ์žˆ๊ณ  localํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ์—์„œ FormattedDate ์ปดํฌ๋„ŒํŠธ๋Š” props๋ฅผ ํ†ตํ•ด date๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ๊ฒƒ์ด์ง€๋งŒ Clock์˜ state์—์„œ ์ „๋‹ฌ๋ฐ›์€๊ฑด์ง€๋Š” ์ „ํ˜€ ๋ชจ๋ฅธ๋‹ค.

<FormattedDate date={this.state.date} />

์ด๋Ÿฐ ๋ฐฉ์‹์„ "top-down" ํ˜น "unidirectional" ๋ฐ์ดํ„ฐ ํ๋ฆ„์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ํŠน์ • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์†Œ์œ ํ•œ ์–ด๋–ค state๋“  "below"์— ์กด์žฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—๋งŒ ์˜ํ–ฅ์„ ๋ผ์น  ์ˆ˜ ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋“ค๋กœ ๊ตฌ์„ฑ๋œ ํŠธ๋ฆฌ๊ฐ€ ์žˆ๊ณ  ์ด๋ฅผ props์˜ ํญํฌ๋ผ๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ฉด, ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ state๋“ค์„ ํ•˜๋‚˜์˜ ๋˜ ๋‹ค๋ฅธ ์ˆ˜์›์ง€๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋  ๊ฒƒ์ด๋‹ค. state๋Š” ์•„๋ž˜๋กœ ํ๋ฅธ๋‹ค.

๋ฆฌ์•กํŠธ ์•ฑ์—์„œ, ์ปดํฌ๋„ŒํŠธ๊ฐ€ statefulํ•œ์ง€ statelessํ•œ์ง€๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ์„œ ๋ณ€ํ™”ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ๊ฒฐ์ •๋˜๊ณ  ๊ตฌํ˜„๋˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

profile
FE Developer @Medistream

0๊ฐœ์˜ ๋Œ“๊ธ€