์ฃผ์˜ํ•˜์„ธ์š”!

์ปดํฌ๋„ŒํŠธ๋ฅผ class ๋Œ€์‹  ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.

Component๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ class๋กœ ์ •์˜๋œ React ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋ณธ class์ž…๋‹ˆ๋‹ค. React์—์„œ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ณ„์† ์ง€์›ํ•˜์ง€๋งŒ, ์ƒˆ ์ฝ”๋“œ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

๋ ˆํผ๋Ÿฐ์Šค

Component

React ์ปดํฌ๋„ŒํŠธ๋ฅผ class๋กœ ์ •์˜ํ•˜๋ ค๋ฉด, ๋‚ด์žฅ Component class๋ฅผ ํ™•์žฅํ•˜๊ณ  render ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜์„ธ์š”.

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

render ๋ฉ”์„œ๋“œ๋งŒ ํ•„์ˆ˜๊ณ  ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋Š” ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.


context

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ context๋Š” this.context๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. static contextType(modern) ๋˜๋Š” static contextTypes(deprecated)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋–ค context๋ฅผ ๋ฐ›๊ธธ ์›ํ•˜๋Š”์ง€ ์ง€์ •ํ•ด์•ผ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ context๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ this.context๋ฅผ ์ฝ๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


props

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๋Š” props๋Š” this.props๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

<Greeting name="Taylor" />

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ this.props๋ฅผ ์ฝ๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ props๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


refs

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API๋Š” React์˜ ํ–ฅํ›„ ์ฃผ์š” ๋ฒ„์ „์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  createRef๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ legacy string refs์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


state

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ state๋Š” this.state๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. state ํ•„๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ฐ์ฒด์—ฌ์•ผํ•ฉ๋‹ˆ๋‹ค. state๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์ง€ ๋งˆ์„ธ์š”. state๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ƒˆ state๋กœ setState๋ฅผ ํ˜ธ์ถœํ•˜์„ธ์š”.

class Counter extends Component {
state = {
age: 42,
};

handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};

render() {
return (
<>
<button onClick={this.handleAgeChange}>
Increment age
</button>
<p>You are {this.state.age}.</p>
</>
);
}
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ state๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useState๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


constructor(props)

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ(ํ™”๋ฉด์— ์ถ”๊ฐ€๋จ)๋˜๊ธฐ ์ „์— constructor๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ constructor๋Š” React์—์„œ ๋‘ ๊ฐ€์ง€ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. state๋ฅผ ์„ ์–ธํ•˜๊ณ  class ๋ฉ”์„œ๋“œ๋ฅผ class ์ธ์Šคํ„ด์Šค์— ๋ฐ”์ธ๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
// ...
}

์ตœ์‹  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด constructor๋Š” ๊ฑฐ์˜ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์™€ Babel๊ณผ ๊ฐ™์€ ๋„๊ตฌ์—์„œ ๋ชจ๋‘ ์ง€์›๋˜๋Š” ๊ณต์šฉ class ํ•„๋“œ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Counter extends Component {
state = { counter: 0 };

handleClick = () => {
// ...
}

constructor๋Š” ๋ถ€์ˆ˜ ํšจ๊ณผ ๋˜๋Š” ๊ตฌ๋…์„ ํฌํ•จํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • props: ์ปดํฌ๋„ŒํŠธ์˜ ์ดˆ๊ธฐ props.

๋ฐ˜ํ™˜๊ฐ’

constructor๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • constructor์—์„œ ๋ถ€์ˆ˜ ํšจ๊ณผ ๋˜๋Š” ๊ตฌ๋…์„ ์‹คํ–‰ํ•˜์ง€ ๋งˆ์„ธ์š”. ๋Œ€์‹  componentDidMount๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • constructor ๋‚ด๋ถ€์—์„œ๋Š” ๋‹ค๋ฅธ ๋ช…๋ น์–ด๋ณด๋‹ค super(props)๋ฅผ ๋จผ์ € ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ฉด, constructor๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ this.props๋Š” undefined๊ฐ€ ๋˜์–ด ํ˜ผ๋ž€์Šค๋Ÿฝ๊ณ  ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • constructor๋Š” this.state๋ฅผ ์ง์ ‘ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์œ„์น˜์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋“  ๋ฉ”์„œ๋“œ์—์„œ๋Š” this.setState()๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. constructor์—์„œ setState๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

  • ์„œ๋ฒ„ ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•  ๋•Œ, constructor๋Š” ์„œ๋ฒ„์—์„œ ์—ญ์‹œ ์‹คํ–‰๋˜๊ณ , ๋’ค์ด์–ด render ๋ฉ”์„œ๋“œ๋„ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ componentDidMount ๋˜๋Š” componentWillUnmount์™€ ๊ฐ™์€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋Š” ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • Strict ๋ชจ๋“œ๊ฐ€ ์„ค์ •๋˜๋ฉด React๋Š” ๊ฐœ๋ฐœ ์ค‘์ธ constructor๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•œ ๋‹ค์Œ ์ธ์Šคํ„ด์Šค ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด constructor ์™ธ๋ถ€๋กœ ์˜ฎ๊ฒจ์ ธ์•ผ ํ•˜๋Š” ์šฐ๋ฐœ์ ์ธ ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์— constructor์™€ ์ •ํ™•ํžˆ ๋™๋“ฑํ•œ ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์— state๋ฅผ ์„ ์–ธํ•˜๋ ค๋ฉด useState๋ฅผ ํ˜ธ์ถœํ•˜์„ธ์š”. ์ดˆ๊ธฐ state๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ํ•จ์ˆ˜๋ฅผ useState์— ์ „๋‹ฌํ•˜์„ธ์š”.


componentDidCatch(error, info)

componentDidCatch๋ฅผ ์ •์˜ํ•˜๋ฉด, ์ผ๋ถ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ(๋จผ ์ž์‹์„ ํฌํ•จ)๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๋•Œ React๊ฐ€ ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์šด์˜ ์ค‘์ธ ์—๋Ÿฌ ๋ณด๊ณ  ์„œ๋น„์Šค์— ์—๋Ÿฌ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ, ์—๋Ÿฌ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” static getDerivedStateFromError์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ error boundary๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • error: ๋ฐœ์ƒํ•œ ์—๋Ÿฌ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ, ๋ณดํ†ต์€ ์—๋Ÿฌ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋˜์ง€๋งŒ JavaScript์—์„œ ๋ฌธ์ž์—ด ๋˜๋Š” null์„ ํฌํ•จํ•œ ์–ด๋–ค ๊ฐ’์ด๋“  throwํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • info: ์—๋Ÿฌ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์˜ componentStack ํ•„๋“œ๋Š” ๋ชจ๋“  ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ์ด๋ฆ„๊ณผ ์ถœ์ฒ˜ ์œ„์น˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—๋Ÿฌ๋ฅผ throwํ•œ ์ปดํฌ๋„ŒํŠธ์˜ stack trace์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜์—์„œ, ์ปดํฌ๋„ŒํŠธ์˜ ์ด๋ฆ„์€ ์ตœ์†Œํ™”๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ์—๋Ÿฌ ๋ณด๊ณ ๋ฅผ ์„ค์ •ํ•˜๋ฉด ์ผ๋ฐ˜ JavaScript ์—๋Ÿฌ ์Šคํƒ๊ณผ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์†Œ์Šค๋งต์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์Šคํƒ์„ ๋””์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

componentDidCatch๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ๊ณผ๊ฑฐ์—๋Š” UI๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๋Œ€์ฒด ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด setState๋ฅผ componentDidCatch ์•ˆ์—์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” static getDerivedStateFromError๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • React์˜ ํ”„๋กœ๋•์…˜๊ณผ ๊ฐœ๋ฐœ ๋นŒ๋“œ๋Š” componentDidCatch๊ฐ€ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด ์•ฝ๊ฐ„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์—์„œ๋Š”, ์—๋Ÿฌ๋Š” window๊นŒ์ง€ ๋ฒ„๋ธ”๋ง๋  ๊ฒƒ์ด๋ฉฐ, ์ด๋Š” window.onerror ๋˜๋Š” window.addEventListener('error', callback)๊ฐ€ componentDidCatch์— ์˜ํ•ด ํƒ์ง€๋œ ์—๋Ÿฌ๋ฅผ ๊ฐ€๋กœ์ฑˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ํ”„๋กœ๋•์…˜์—์„œ, ์—๋Ÿฌ๋Š” ๋ฒ„๋ธ”๋ง๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ฉฐ, ์ด๋Š” ์–ด๋–ค ์ƒ์œ„์˜ ์—๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ componentDidCatch์— ์˜ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ํƒ์ง€๋˜์ง€ ์•Š์€ ์—๋Ÿฌ๋งŒ์„ ์ˆ˜์‹ ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์— componentDidCatch์™€ ์ง์ ‘์ ์œผ๋กœ ๋™๋“ฑํ•œ ๊ฒƒ์€ ์•„์ง ์—†์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ์„ ํ”ผํ•˜๋ ค๋ฉด, ์œ„์™€ ๊ฐ™์ด ErrorBoundary ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•˜๋‚˜ ์ž‘์„ฑํ•˜์—ฌ ์•ฑ ์ „์ฒด์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, ๊ทธ๊ฒƒ์„ ํ•ด์ฃผ๋Š” react-error-boundary package๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


componentDidMount()

componentDidMount ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ™”๋ฉด์— ์ถ”๊ฐ€ (๋งˆ์šดํŠธ) ๋  ๋•Œ React๊ฐ€ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜, ๊ตฌ๋…์„ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, DOM ๋…ธ๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

componentDidMount๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฒ„๊ทธ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, componentDidMount๊ฐ€ ์ผ๋ถ€ state๋‚˜ props๋ฅผ ์ฝ๋Š” ๊ฒฝ์šฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด componentDidUpdate๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  componentDidMount๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋˜ ์ž‘์—…์„ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด componentWillUnmount๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

componentDidMount๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

componentDidMount๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • Strict ๋ชจ๋“œ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด ๊ฐœ๋ฐœ ์ค‘์ธ React๊ฐ€ componentDidMount๋ฅผ ํ˜ธ์ถœํ•œ ๋‹ค์Œ componentWillUnmount๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  componentDidMount๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด componentWillUnmount๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ๊ฑฐ๋‚˜ ๋กœ์ง์ด componentDidMount๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ์™„์ „ํžˆ โ€œ๋ฏธ๋Ÿฌ๋งโ€ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • componentDidMount์—์„œ setState๋ฅผ ์ฆ‰์‹œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ€๋Šฅํ•˜๋ฉด ํ”ผํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ถ”๊ฐ€ ๋ Œ๋”๋ง์„ ์ผ์œผํ‚ค์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ „์— ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ render๊ฐ€ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜๋”๋ผ๋„ ์‚ฌ์šฉ์ž๋Š” ์ค‘๊ฐ„ state๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ์ข…์ข… ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฏ€๋กœ ์ฃผ์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ constructor์—์„œ ์ดˆ๊ธฐ state๋ฅผ ๋Œ€์‹  ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋‹ฌ์ด๋‚˜ ํˆดํŒ๊ณผ ๊ฐ™์ด ํฌ๊ธฐ๋‚˜ ์œ„์น˜์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— DOM ๋…ธ๋“œ๋ฅผ ์ธก์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ componentDidMount, componentDidUpdate ๋ฐ componentWillUnmount๋ฅผ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ํ•จ๊ป˜ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useEffect๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋“œ๋ฌผ์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ € ํŽ˜์ธํŠธ ์ „์— ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” useLayoutEffect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


componentDidUpdate(prevProps, prevState, snapshot?)

componentDidUpdate ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ props ๋˜๋Š” state๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง๋œ ์งํ›„ React๊ฐ€ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์ดˆ๊ธฐ ๋ Œ๋”๋ง์— ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—…๋ฐ์ดํŠธ ํ›„ DOM์„ ์กฐ์ž‘ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ˜„์žฌ props๋ฅผ ์ด์ „ props์™€ ๋น„๊ตํ•˜๋Š” ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์žฅ์†Œ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: props๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ์ผ๋ฐ˜์ ์œผ๋กœ componentDidMount ๋ฐ componentWillUnmount์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • prevProps: ์—…๋ฐ์ดํŠธ ์ด์ „์˜ props. prevProps์™€ this.props๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • prevState: ์—…๋ฐ์ดํŠธ ์ „ state. prevState๋ฅผ this.state์™€ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • snapshot: getSnapshotBeforeUpdate๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒฝ์šฐ, snapshot์—๋Š” ํ•ด๋‹น ๋ฉ”์„œ๋“œ์—์„œ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด undefined๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

componentDidUpdate๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • shouldComponentUpdate๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉด componentDidUpdate๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ  false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • componentDidUpdate ๋‚ด๋ถ€์˜ ๋กœ์ง์€ ์ผ๋ฐ˜์ ์œผ๋กœ this.props๋ฅผ prevProps์™€ ๋น„๊ตํ•˜๊ณ  this.state๋ฅผ prevState์™€ ๋น„๊ตํ•˜๋Š” ์กฐ๊ฑด์œผ๋กœ ๋ž˜ํ•‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ฌดํ•œ ๋ฃจํ”„๊ฐ€ ์ƒ์„ฑ๋  ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • componentDidUpdate์—์„œ setState๋ฅผ ์ฆ‰์‹œ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๊ฐ€๋Šฅํ•˜๋ฉด ํ”ผํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ๋ Œ๋”๋ง์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ „์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ด ๊ฒฝ์šฐ render๊ฐ€ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜๋”๋ผ๋„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ค‘๊ฐ„ state๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ์ข…์ข… ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€๋งŒ ๋“œ๋ฌผ๊ฒŒ ๋ชจ๋‹ฌ์ด๋‚˜ ํˆดํŒ์ฒ˜๋Ÿผ ํฌ๊ธฐ๋‚˜ ์œ„์น˜์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— DOM ๋…ธ๋“œ๋ฅผ ์ธก์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ componentDidMount, componentDidUpdate ๋ฐ componentWillUnmount๋ฅผ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ํ•จ๊ป˜ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useEffect๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋“œ๋ฌผ์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ € ํŽ˜์ธํŠธ ์ „์— ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” useLayoutEffect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


componentWillMount()

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API์˜ ์ด๋ฆ„์ด componentWillMount์—์„œ UNSAFE_componentWillMount๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์ด๋ฆ„์€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ๋Š” ์ƒˆ๋กœ์šด ์ด๋ฆ„๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด rename-unsafe-lifecycles codemod๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”.


componentWillReceiveProps(nextProps)

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API์˜ ์ด๋ฆ„์ด componentWillReceiveProps์—์„œ UNSAFE_componentWillReceiveProps๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์ด๋ฆ„์€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ๋Š” ์ƒˆ๋กœ์šด ์ด๋ฆ„๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด rename-unsafe-lifecycles codemod๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”.


componentWillUpdate(nextProps, nextState)

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API์˜ ์ด๋ฆ„์ด componentWillUpdate์—์„œ UNSAFE_componentWillUpdate๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ „ ์ด๋ฆ„์€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ๋Š” ์ƒˆ๋กœ์šด ์ด๋ฆ„๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด rename-unsafe-lifecycles codemod๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”.


componentWillUnmount()

componentWillUnmount ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉด React๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์—์„œ ์ œ๊ฑฐ (๋งˆ์šดํŠธ ํ•ด์ œ) ๋˜๊ธฐ ์ „์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ๋ฅผ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋…์„ ์ œ๊ฑฐํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

componentWillUnmount ๋‚ด๋ถ€์˜ ๋กœ์ง์€ componentDidMount ๋‚ด๋ถ€์˜ ๋กœ์ง์„ โ€œ๋ฏธ๋Ÿฌ๋งโ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด componentDidMount๊ฐ€ ๊ตฌ๋…์„ ์„ค์ •ํ•˜๋ฉด componentWillUnmount๋Š” ํ•ด๋‹น ๊ตฌ๋…์„ ์ •๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. componentWillUnmount์˜ ์ •๋ฆฌ ๋กœ์ง์ด ์ผ๋ถ€ props๋‚˜ state๋ฅผ ์ฝ๋Š” ๊ฒฝ์šฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ด์ „ props๋‚˜ state์— ํ•ด๋‹นํ•˜๋Š” ๋ฆฌ์†Œ์Šค(์˜ˆ: ๊ตฌ๋…)๋ฅผ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด componentDidUpdate๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};

componentDidMount() {
this.setupConnection();
}

componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}

componentWillUnmount() {
this.destroyConnection();
}

// ...
}

๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

componentWillUnmount๋Š” ์–ด๋–ค ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

componentWillUnmount๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • Strict ๋ชจ๋“œ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด ๊ฐœ๋ฐœ ์‹œ React๋Š” componentDidMount๋ฅผ ํ˜ธ์ถœํ•œ ๋‹ค์Œ ์ฆ‰์‹œ componentWillUnmount๋ฅผ ํ˜ธ์ถœํ•œ ๋‹ค์Œ componentDidMount๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด componentWillUnmount๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ ธ๊ฑฐ๋‚˜ ๊ทธ ๋กœ์ง์ด componentDidMount์˜ ๋™์ž‘์„ ์™„์ „ํžˆ โ€œ๋ฏธ๋Ÿฌ๋งโ€ํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ componentDidMount, componentDidUpdate ๋ฐ componentWillUnmount๋ฅผ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ํ•จ๊ป˜ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useEffect๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋“œ๋ฌผ์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ € ํŽ˜์ธํŠธ ์ „์— ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” useLayoutEffect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


forceUpdate(callback?)

์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ•์ œ๋กœ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์˜ render ๋ฉ”์„œ๋“œ๊ฐ€ this.props, this.state ๋˜๋Š” this.context์—์„œ๋งŒ ์ฝ๋Š” ๊ฒฝ์šฐ, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ๋˜๋Š” ๋ถ€๋ชจ ์ค‘ ํ•˜๋‚˜์—์„œ setState๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ์˜ render ๋ฉ”์„œ๋“œ๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ์ฝ์–ด์˜ค๋Š” ๊ฒฝ์šฐ, ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก React์— ์ง€์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ forceUpdate๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ž…๋‹ˆ๋‹ค.

forceUpdate์˜ ๋ชจ๋“  ์‚ฌ์šฉ์„ ํ”ผํ•˜๊ณ  render์—์„œ this.props์™€ this.state๋กœ๋ถ€ํ„ฐ๋งŒ ์ฝ๋„๋ก ํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • optional callback: ์ง€์ •ํ•œ ๊ฒฝ์šฐ React๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ปค๋ฐ‹๋œ ํ›„ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ callback์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

forceUpdate๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • forceUpdate๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด React๋Š” shouldComponentUpdate๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ฝ๋Š” ๊ฒƒ๊ณผ forceUpdate๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์— ๋”ฐ๋ผ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋„๋ก ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useSyncExternalStore๋กœ ๋Œ€์ฒด๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


getChildContext()

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API๋Š” ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  Context.Provider๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” legacy context์— ๋Œ€ํ•œ ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด React๊ฐ€ DOM์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ๋ฐ”๋กœ ์ „์— ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž ์žฌ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— DOM์—์„œ ์ผ๋ถ€ ์ •๋ณด(์˜ˆ: ์Šคํฌ๋กค ์œ„์น˜)๋ฅผ ์บก์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ๊ฐ’์€ componentDidUpdate์— ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์—…๋ฐ์ดํŠธ ์ค‘์— ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ์ฑ„ํŒ… ์Šค๋ ˆ๋“œ์™€ ๊ฐ™์€ UI์—์„œ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

getSnapshotBeforeUpdate(prevProps, prevState) {
// ๋ชฉ๋ก์— ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์žˆ๋‚˜์š”?
// ๋‚˜์ค‘์— ์Šคํฌ๋กค์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ์บก์ฒ˜ํ•ฉ๋‹ˆ๋‹ค.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
// ์Šค๋ƒ…์ƒท ๊ฐ’์ด ์žˆ์œผ๋ฉด ๋ฐฉ๊ธˆ ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
// ์ƒˆ ํ•ญ๋ชฉ์ด ๊ธฐ์กด ํ•ญ๋ชฉ์„ ์‹œ์•ผ ๋ฐ–์œผ๋กœ ๋ฐ€์–ด๋‚ด์ง€ ์•Š๋„๋ก ์Šคํฌ๋กค์„ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
// (์—ฌ๊ธฐ์„œ ์Šค๋ƒ…์ƒท์€ getSnapshotBeforeUpdate์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์ž…๋‹ˆ๋‹ค.)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}

render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}

์œ„์˜ ์˜ˆ์‹œ์—์„œ๋Š” getSnapshotBeforeUpdate์—์„œ ์ง์ ‘ scrollHeight ์†์„ฑ์„ ์ฝ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. render, UNSAFE_componentWillReceiveProps ๋˜๋Š” UNSAFE_componentWillUpdate๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ๊ณผ React๊ฐ€ DOM์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์‹œ์  ์‚ฌ์ด์— ์ž ์žฌ์ ์ธ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ์—์„œ ์ด(์—ญ์ฃผ: scrollHeight)๋ฅผ ์ฝ๋Š” ๊ฒƒ์€ ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • prevProps: ์—…๋ฐ์ดํŠธ ์ด์ „์˜ props. prevProps์™€ this.props๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

  • prevState: ์—…๋ฐ์ดํŠธ ์ „ state. prevState๋ฅผ this.state์™€ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

์›ํ•˜๋Š” ์œ ํ˜•์˜ ์Šค๋ƒ…์ƒท ๊ฐ’ ๋˜๋Š” null์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์€ componentDidUpdate์˜ ์„ธ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • shouldComponentUpdate๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉด getSnapshotBeforeUpdate๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ณ  false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ˜„์žฌ๋กœ์„œ๋Š” ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ getSnapshotBeforeUpdate์™€ ๋™๋“ฑํ•œ ํ•จ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋งค์šฐ ๋“œ๋ฌผ์ง€๋งŒ, ์ด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ˜„์žฌ๋กœ์„œ๋Š” ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


render()

render ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ ์œ ์ผํ•˜๊ฒŒ ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค.

render ๋ฉ”์„œ๋“œ๋Š” ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋‚ด์šฉ์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค, ์˜ˆ๋ฅผ ๋“ค์–ด

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

React๋Š” ์–ธ์ œ๋“  render๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํŠน์ • ์‹œ๊ฐ„์— ์‹คํ–‰๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ render ๋ฉ”์„œ๋“œ๋Š” JSX๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ (๋ฌธ์ž์—ด๊ณผ ๊ฐ™์€) ๋‹ค๋ฅธ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์ง€์›๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜๋œ JSX๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด render ๋ฉ”์„œ๋“œ๋Š” this.props, this.state ๋ฐ this.context๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

render ๋ฉ”์„œ๋“œ๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, props, state ๋ฐ context๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ (๊ตฌ๋… ์„ค์ •๊ณผ ๊ฐ™์€) ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ํฌํ•จํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋ผ์šฐ์ € API์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋ถ€์ˆ˜ ํšจ๊ณผ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ componentDidMount์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ์—์„œ ๋ฐœ์ƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • render: ์–ด๋–ค ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

render๋Š” ์œ ํšจํ•œ ๋ชจ๋“  React ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” <div />, ๋ฌธ์ž์—ด, ์ˆซ์ž, portals, ๋นˆ ๋…ธ๋“œ(null, undefined, true, false) ๋ฐ React ๋…ธ๋“œ์˜ ๋ฐฐ์—ด๊ณผ ๊ฐ™์€ React ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • render๋Š” props, state, context์˜ ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜๋กœ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ถ€์ˆ˜ ํšจ๊ณผ๊ฐ€ ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • shouldComponentUpdate๊ฐ€ ์ •์˜๋˜๊ณ  false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด render๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • Strict ๋ชจ๋“œ๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด React๋Š” ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ render๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•œ ๋‹ค์Œ ๊ฒฐ๊ณผ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด render ๋ฉ”์„œ๋“œ์—์„œ ์ œ๊ฑฐํ•ด์•ผ ํ•˜๋Š” ์šฐ๋ฐœ์ ์ธ ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • render ํ˜ธ์ถœ๊ณผ ํ›„์† componentDidMount ๋˜๋Š” componentDidUpdate ํ˜ธ์ถœ ์‚ฌ์ด์—๋Š” ์ผ๋Œ€์ผ ๋Œ€์‘์ด ์—†์Šต๋‹ˆ๋‹ค. render ํ˜ธ์ถœ ๊ฒฐ๊ณผ ์ค‘ ์ผ๋ถ€๋Š” ์œ ์ตํ•  ๋•Œ React์— ์˜ํ•ด ๋ฒ„๋ ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


setState(nextState, callback?)

setState๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ React ์ปดํฌ๋„ŒํŠธ์˜ state๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

class Form extends Component {
state = {
name: 'Taylor',
};

handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}

render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.</p>
</>
);
}
}

setState๋Š” ์ปดํฌ๋„ŒํŠธ state์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ์™€ ๊ทธ ์ž์‹์ด ์ƒˆ๋กœ์šด state๋กœ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ React์—๊ฒŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ƒํ˜ธ์ž‘์šฉ์— ๋ฐ˜์‘ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ฃผ์š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

setState๋ฅผ ํ˜ธ์ถœํ•ด๋„ ์ด๋ฏธ ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ์˜ ํ˜„์žฌ state๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

function handleClick() {
console.log(this.state.name); // "Taylor"
this.setState({
name: 'Robin'
});
console.log(this.state.name); // Still "Taylor"!
}

์˜ค๋กœ์ง€ ๋‹ค์Œ ๋ Œ๋”๋ง๋ถ€ํ„ฐ this.state๊ฐ€ ๋ฐ˜ํ™˜ํ•  ๋‚ด์šฉ์—๋งŒ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค.

setState์— ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ „ state๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ state๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ๋™์ผํ•œ ์ด๋ฒคํŠธ ์ค‘์— state๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • nextState: ๊ฐ์ฒด ๋˜๋Š” ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

    • ๊ฐ์ฒด๋ฅผ nextState๋กœ ์ „๋‹ฌํ•˜๋ฉด this.state์— ์–•๊ฒŒ(shallowly) ๋ณ‘ํ•ฉ๋ฉ๋‹ˆ๋‹ค.
    • ํ•จ์ˆ˜๋ฅผ nextState๋กœ ์ „๋‹ฌํ•˜๋ฉด ์—…๋ฐ์ดํ„ฐ ํ•จ์ˆ˜ ๋กœ ์ทจ๊ธ‰๋ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•ด์•ผ ํ•˜๊ณ , pending state์™€ props๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„์•ผ ํ•˜๋ฉฐ, this.state์— ์–•๊ฒŒ(shallowly) ๋ณ‘ํ•ฉํ•  ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. React๋Š” ์—…๋ฐ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ์— ๋„ฃ๊ณ  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ Œ๋”๋ง ์ค‘์— React๋Š” ํ์— ์žˆ๋Š” ๋ชจ๋“  ์—…๋ฐ์ดํ„ฐ๋ฅผ ์ด์ „ state์— ์ ์šฉํ•˜์—ฌ ๋‹ค์Œ state๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
  • optional callback: ์ง€์ •ํ•œ ๊ฒฝ์šฐ React๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ์ปค๋ฐ‹๋œ ํ›„ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ callback์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

setState๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • setState๋ฅผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ฆ‰๊ฐ์ ์ธ ๋ช…๋ น์ด ์•„๋‹Œ ์š”์ฒญ์œผ๋กœ ์ƒ๊ฐํ•˜์„ธ์š”. ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•˜์—ฌ state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด React๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ batchํ•˜๊ณ  ์ด๋ฒคํŠธ๊ฐ€ ๋๋‚  ๋•Œ ๋‹จ์ผ ํŒจ์Šค๋กœ ํ•จ๊ป˜ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ๋“œ๋ฌผ๊ฒŒ ํŠน์ • state ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ•์ œ๋กœ ๋™๊ธฐํ™”ํ•˜์—ฌ ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, flushSync๋กœ ๋ž˜ํ•‘ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ๊ฒฝ์šฐ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • setState๋Š” this.state๋ฅผ ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ setState๋ฅผ ํ˜ธ์ถœํ•œ ์งํ›„ this.state๋ฅผ ์ฝ๋Š” ๊ฒƒ์€ ์ž ์žฌ์ ์ธ ์œ„ํ—˜์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ , ์—…๋ฐ์ดํŠธ๊ฐ€ ์ ์šฉ๋œ ํ›„์— ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅ๋˜๋Š” componentDidUpdate ๋˜๋Š” setState callback ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์ด์ „ state๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ state๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋Œ€๋กœ ํ•จ์ˆ˜๋ฅผ nextState์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ setState๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ set ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


shouldComponentUpdate(nextProps, nextState, nextContext)

shouldComponentUpdate๋ฅผ ์ •์˜ํ•˜๋ฉด React๊ฐ€ ์ด๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์žฌ๋ Œ๋”๋ง์„ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

์ง์ ‘ ์ž‘์„ฑ์„ ์›ํ•˜๋Š” ๊ฒƒ์ด ํ™•์‹คํ•˜๋‹ค๋ฉด, this.props๋ฅผ nextProps์™€, this.state๋ฅผ nextState์™€ ๋น„๊ตํ•˜๊ณ  false๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ React์— ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์Œ์„ ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Rectangle extends Component {
state = {
isHovered: false
};

shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์—†์œผ๋ฏ€๋กœ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
return false;
}
return true;
}

// ...
}

์ƒˆ๋กœ์šด props๋‚˜ state๊ฐ€ ์ˆ˜์‹ ๋˜๋ฉด ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— React๊ฐ€ shouldComponentUpdate๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ true์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์ดˆ๊ธฐ ๋ Œ๋”๋ง์ด๋‚˜ forceUpdate๊ฐ€ ์‚ฌ์šฉ๋  ๋•Œ๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜

  • nextProps: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ props์ž…๋‹ˆ๋‹ค. nextProps์™€ this.props๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • nextState: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ state์ž…๋‹ˆ๋‹ค. nextState์™€ this.state๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • nextContext: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ context์ž…๋‹ˆ๋‹ค. nextContext๋ฅผ this.context์™€ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. static contextType(modern) ๋˜๋Š” static contextTypes(legacy)๋ฅผ ์ง€์ •ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๊ธฐ๋ณธ ๋™์ž‘์ž…๋‹ˆ๋‹ค.

React์— ์žฌ๋ Œ๋”๋ง์„ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์Œ์„ ์•Œ๋ฆฌ๋ ค๋ฉด false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ์ด ๋ฉ”์„œ๋“œ๋Š” ์˜ค์ง ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด์„œ๋งŒ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ ์—†์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝ์šฐ ๋จผ์ € ๊ทธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์„ธ์š”.

  • shouldComponentUpdate๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  PureComponent๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”. PureComponent๋Š” props์™€ state๋ฅผ ์–•๊ฒŒ(shallowly) ๋น„๊ตํ•˜์—ฌ ํ•„์š”ํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฑด๋„ˆ๋›ธ ๊ฐ€๋Šฅ์„ฑ์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.

  • shouldComponentUpdate์—์„œ ์™„์ „ ์ผ์น˜(deep equality) ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ฑฐ๋‚˜ JSON.stringify๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„ฑ๋Šฅ์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๊ณ  ๋ชจ๋“  prop๊ณผ state์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์— ์˜์กด์ ์ด๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ƒ์˜ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋ช‡ ์ดˆ์”ฉ ๋ฉˆ์ถ”๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๊ณ  ์ตœ์•…์˜ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ถฉ๋Œํ•  ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • false๋ฅผ ๋ฐ˜ํ™˜ํ•ด๋„ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—์„œ ๊ทธ๋“ค์˜ state๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ง‰์ง€๋Š” ๋ชปํ•ฉ๋‹ˆ๋‹ค.

  • false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ณด์žฅ์€ ์—†์Šต๋‹ˆ๋‹ค. React๋Š” ๋ฐ˜ํ™˜๊ฐ’์„ ํžŒํŠธ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์ด์œ ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ผ ๊ฒฝ์šฐ ์—ฌ์ „ํžˆ ๋ Œ๋”๋ง์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

shouldComponentUpdate๋กœ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์€ memo๋กœ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋Š” useMemo๋ฅผ ํ†ตํ•ด ๋” ์„ธ๋ถ„ํ™”๋œ ์ตœ์ ํ™”๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


UNSAFE_componentWillMount()

UNSAFE_componentWillMount๋ฅผ ์ •์˜ํ•˜๋ฉด React๋Š” constructor ๋ฐ”๋กœ ๋’ค์— ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์—ญ์‚ฌ์ ์ธ ์ด์œ ๋กœ๋งŒ ์กด์žฌํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ๋‹ค๋ฅธ ๋Œ€์•ˆ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • state๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด state๋ฅผ class ํ•„๋“œ๋กœ ์„ ์–ธํ•˜๊ฑฐ๋‚˜ constructor ๋‚ด์—์„œ this.state๋ฅผ ์„ค์ •ํ•˜์„ธ์š”.
  • ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋…์„ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋กœ์ง์„ componentDidMount๋กœ ์˜ฎ๊ธฐ์„ธ์š”.

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ƒ๋ช…์ฃผ๊ธฐ์—์„œ ๋ฒ—์–ด๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•œ ์‚ฌ๋ก€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

UNSAFE_componentWillMount๋Š” ์–ด๋– ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

UNSAFE_componentWillMount๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ static getDerivedStateFromProps ๋˜๋Š” getSnapshotBeforeUpdate๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillMount๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฆ„๊ณผ๋Š” ๋‹ฌ๋ฆฌ, ์•ฑ์ด Suspense์™€ ๊ฐ™์€ ์ตœ์‹  React ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillMount๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๊ฒƒ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ์‹œ๋„๊ฐ€ ์ผ์‹œ ์ค‘๋‹จ๋˜๋ฉด(์˜ˆ๋ฅผ ๋“ค์–ด ์ผ๋ถ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ์•„์ง ๋กœ๋“œ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—) React๋Š” ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋‹ค์Œ ์‹œ๋„์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ด ๋ฉ”์„œ๋“œ๊ฐ€ โ€œ์•ˆ์ „ํ•˜์ง€ ์•Š์€โ€ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋งˆ์šดํŒ…์— ์˜์กดํ•˜๋Š” ์ฝ”๋“œ(์˜ˆ: ๊ตฌ๋… ์ถ”๊ฐ€)๋Š” componentDidMount๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • UNSAFE_componentWillMount๋Š” ์„œ๋ฒ„ ๋ Œ๋”๋ง ์ค‘์— ์‹คํ–‰๋˜๋Š” ์œ ์ผํ•œ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‹ค์šฉ์ ์ธ ์šฉ๋„๋กœ ๋ณผ ๋•Œ constructor์™€ ๋™์ผํ•˜๋ฏ€๋กœ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋กœ์ง์—๋Š” constructor๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๋‚ด UNSAFE_componentWillMount ๋‚ด๋ถ€์—์„œ setState๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ state๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•ด๋‹น state๋ฅผ useState์— ์ดˆ๊ธฐ state๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.


UNSAFE_componentWillReceiveProps(nextProps, nextContext)

UNSAFE_componentWillReceiveProps๋ฅผ ์ •์˜ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒˆ๋กœ์šด props๋ฅผ ์ˆ˜์‹ ํ•  ๋•Œ React๊ฐ€ ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์—ญ์‚ฌ์ ์ธ ์ด์œ ๋กœ๋งŒ ์กด์žฌํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • props ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์‹คํ–‰(์˜ˆ: ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹คํ–‰, ๊ตฌ๋… ์žฌ์ดˆ๊ธฐํ™”)ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋กœ์ง์„ componentDidUpdate๋กœ ์˜ฎ๊ธฐ์„ธ์š”.
  • props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋Œ€์‹  memoization helper๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ผ๋ถ€ state๋ฅผ โ€œ์ดˆ๊ธฐํ™”โ€ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์™„์ „ํžˆ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ key๋กœ ์™„์ „ํžˆ ์ œ์–ดํ•˜์ง€ ์•Š๋„๋ก ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ผ๋ถ€ state๋ฅผ โ€œ์กฐ์ •โ€ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋ Œ๋”๋ง ์ค‘์— props๋งŒ์œผ๋กœ ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ๊ณ„์‚ฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ static getDerivedStateFromProps๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•˜์„ธ์š”.

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ƒ๋ช…์ฃผ๊ธฐ์—์„œ ๋ฒ—์–ด๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•œ ์‚ฌ๋ก€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • nextProps: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ›์œผ๋ ค๋Š” ๋‹ค์Œ props์ž…๋‹ˆ๋‹ค. nextProps์™€ this.props๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • nextContext: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ณต๊ธ‰์ž(provider)๋กœ๋ถ€ํ„ฐ ๋ฐ›์œผ๋ ค๋Š” ๋‹ค์Œ props์ž…๋‹ˆ๋‹ค. nextContext๋ฅผ this.context์™€ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. static contextType(modern) ๋˜๋Š” static contextTypes(legacy)๋ฅผ ์ง€์ •ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

UNSAFE_componentWillReceiveProps๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ static getDerivedStateFromProps ๋˜๋Š” getSnapshotBeforeUpdate๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillReceiveProps๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฆ„๊ณผ๋Š” ๋‹ฌ๋ฆฌ, ์•ฑ์ด Suspense์™€ ๊ฐ™์€ ์ตœ์‹  React ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillReceiveProps๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ด๋‹น props๋ฅผ ์ˆ˜์‹ ํ•  ๊ฒƒ์„ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ์‹œ๋„๊ฐ€ ์ผ์‹œ ์ค‘๋‹จ๋˜๋ฉด(์˜ˆ๋ฅผ ๋“ค์–ด ์ผ๋ถ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ์•„์ง ๋กœ๋“œ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—) React๋Š” ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋‹ค์Œ ์‹œ๋„ ์ค‘์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ Œ๋”๋ง์„ ์‹œ๋„ํ•  ๋•Œ์ฏค์ด๋ฉด props๊ฐ€ ๋‹ฌ๋ผ์ ธ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ด ๋ฉ”์„œ๋“œ๊ฐ€ โ€œ์•ˆ์ „ํ•˜์ง€ ์•Š์€โ€ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ปค๋ฐ‹๋œ ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•ด์„œ๋งŒ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ(์˜ˆ: ๊ตฌ๋… ์žฌ์„ค์ •)๋Š” componentDidUpdate๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • UNSAFE_componentWillReceiveProps๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ง€๋‚œ๋ฒˆ๊ณผ ๋‹ค๋ฅธ props๋ฅผ ๋ฐ›์•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. nextProps์™€ this.props๋ฅผ ์ง์ ‘ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • React๋Š” ๋งˆ์šดํŠธํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐ props์™€ ํ•จ๊ป˜ UNSAFE_componentWillReceiveProps๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ์˜ ์ผ๋ถ€ props๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๊ฒฝ์šฐ์—๋งŒ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ setState๋ฅผ ํ˜ธ์ถœํ•ด๋„ UNSAFE_componentWillReceiveProps๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ UNSAFE_componentWillReceiveProps ๋‚ด๋ถ€์˜ setState๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ state๋ฅผ โ€œ์กฐ์ •โ€ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋ง ์ค‘์— useState์—์„œ set ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.


UNSAFE_componentWillUpdate(nextProps, nextState)

UNSAFE_componentWillUpdate๋ฅผ ์ •์˜ํ•˜๋ฉด React๋Š” ์ƒˆ props๋‚˜ state๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ์—ญ์‚ฌ์ ์ธ ์ด์œ ๋กœ๋งŒ ์กด์žฌํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ์ฝ”๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ๋‹ค๋ฅธ ๋Œ€์•ˆ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • props๋‚˜ state ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋ถ€์ˆ˜ ํšจ๊ณผ(์˜ˆ: ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์‹คํ–‰, ๊ตฌ๋… ์žฌ์ดˆ๊ธฐํ™”)๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ๋กœ์ง์„ componentDidUpdate๋กœ ์ด๋™ํ•˜์„ธ์š”.
  • ๋‚˜์ค‘์— componentDidUpdate์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก DOM์—์„œ ์ผ๋ถ€ ์ •๋ณด(์˜ˆ: ํ˜„์žฌ ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด)๋ฅผ ์ฝ์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ, ๋Œ€์‹  getSnapshotBeforeUpdate ๋‚ด๋ถ€์—์„œ ์ฝ์Šต๋‹ˆ๋‹ค.

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ƒ๋ช…์ฃผ๊ธฐ์—์„œ ๋ฒ—์–ด๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•œ ์‚ฌ๋ก€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • nextProps: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ props์ž…๋‹ˆ๋‹ค. nextProps์™€ this.props๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • nextState: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ state์ž…๋‹ˆ๋‹ค. nextState์™€ this.state๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

UNSAFE_componentWillUpdate๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • shouldComponentUpdate๊ฐ€ ์ •์˜๋œ ๊ฒฝ์šฐ UNSAFE_componentWillUpdate๋Š” ํ˜ธ์ถœ๋˜์ง€ ์•Š์œผ๋ฉฐ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ static getDerivedStateFromProps ๋˜๋Š” getSnapshotBeforeUpdate๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillUpdate๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • componentWillUpdate ์ค‘์— setState๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ(๋˜๋Š” Redux ์•ก์…˜์„ dispatchํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด setState๊ฐ€ ํ˜ธ์ถœ๋˜๋„๋ก ํ•˜๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ)์€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฆ„๊ณผ๋Š” ๋‹ฌ๋ฆฌ, ์•ฑ์ด Suspense์™€ ๊ฐ™์€ ์ตœ์‹  React ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ UNSAFE_componentWillUpdate๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๊ฒƒ์„ ๋ณด์žฅํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๋ Œ๋”๋ง ์‹œ๋„๊ฐ€ ์ผ์‹œ ์ค‘๋‹จ๋˜๋ฉด(์˜ˆ๋ฅผ ๋“ค์–ด ์ผ๋ถ€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ์ฝ”๋“œ๊ฐ€ ์•„์ง ๋กœ๋“œ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—) React๋Š” ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋ฆฌ๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋‹ค์Œ ์‹œ๋„์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์ƒˆ๋กœ ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ Œ๋”๋ง ์‹œ๋„ ์‹œ์—๋Š” props์™€ state๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ด ๋ฉ”์„œ๋“œ๊ฐ€ โ€œ์•ˆ์ „ํ•˜์ง€ ์•Š์€โ€ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ปค๋ฐ‹๋œ ์—…๋ฐ์ดํŠธ์— ๋Œ€ํ•ด์„œ๋งŒ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ์ฝ”๋“œ(์˜ˆ: ๊ตฌ๋… ์žฌ์„ค์ •)๋Š” componentDidUpdate๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • UNSAFE_componentWillUpdate๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ง€๋‚œ๋ฒˆ๊ณผ ๋‹ค๋ฅธ props๋‚˜ state๋ฅผ ๋ฐ›์•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. nextProps๋ฅผ this.props์™€, nextState๋ฅผ this.state์™€ ์ง์ ‘ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • React๋Š” ๋งˆ์šดํŠธํ•˜๋Š” ๋™์•ˆ ์ดˆ๊ธฐ props์™€ state์™€ ํ•จ๊ป˜ UNSAFE_componentWillUpdate๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—๋Š” UNSAFE_componentWillUpdate์™€ ์ง์ ‘์ ์œผ๋กœ ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค.


static childContextTypes

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API๋Š” ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  static contextType์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” legacy context๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


static contextTypes

๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ด API๋Š” ํ–ฅํ›„ React์˜ ์ฃผ์š” ๋ฒ„์ „์—์„œ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋Œ€์‹  static contextType์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉํ•  legacy context๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


static contextType

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ this.context ๋ฅผ ์ฝ์œผ๋ ค๋ฉด ์ฝ์–ด์•ผ ํ•˜๋Š” context๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. static contextType์œผ๋กœ ์ง€์ •ํ•˜๋Š” context๋Š” ์ด์ „์— createContext๋กœ ์ƒ์„ฑํ•œ ๊ฐ’์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class Button extends Component {
static contextType = ThemeContext;

render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ this.context๋ฅผ ์ฝ๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


static defaultProps

static defaultProps๋ฅผ ์ •์˜ํ•˜์—ฌ class์˜ ๊ธฐ๋ณธ props์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. undefined์™€ ๋ˆ„๋ฝ๋œ props์—๋Š” ์‚ฌ์šฉ๋˜์ง€๋งŒ null props์—๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, color prop์˜ ๊ธฐ๋ณธ๊ฐ’์„ 'blue'๋กœ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

class Button extends Component {
static defaultProps = {
color: 'blue'
};

render() {
return <button className={this.props.color}>click me</button>;
}
}

color props์ด ์ œ๊ณต๋˜์ง€ ์•Š๊ฑฐ๋‚˜ undefined์ธ ๊ฒฝ์šฐ ๊ธฐ๋ณธ์ ์œผ๋กœ โ€™blue'๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

<>
{/* this.props.color is "blue" */}
<Button />

{/* this.props.color is "blue" */}
<Button color={undefined} />

{/* this.props.color is null */}
<Button color={null} />

{/* this.props.color is "red" */}
<Button color="red" />
</>

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ defaultProps๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ default values๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.


static propTypes

prop-types ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ•จ๊ป˜ static propTypes๋ฅผ ์ •์˜ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ—ˆ์šฉ๋˜๋Š” props์˜ ์œ ํ˜•์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ ํ˜•์€ ๋ Œ๋”๋ง ์ค‘๊ณผ ๊ฐœ๋ฐœ ์ค‘์—๋งŒ ํ™•์ธ๋ฉ๋‹ˆ๋‹ค.

import PropTypes from 'prop-types';

class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string
};

render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๋Ÿฐํƒ€์ž„์— prop ํƒ€์ž…์„ ํ™•์ธํ•˜๋Š” ๋Œ€์‹  TypeScript๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.


static getDerivedStateFromError(error)

static getDerivedStateFromError๋ฅผ ์ •์˜ํ•˜๋ฉด ๋ Œ๋”๋ง ๋„์ค‘ ์ž์‹ ์ปดํฌ๋„ŒํŠธ(๋ฉ€๋ฆฌ ๋–จ์–ด์ง„ ์ž์‹ ํฌํ•จ)๊ฐ€ ์—๋Ÿฌ๋ฅผ throw ํ•  ๋•Œ React๊ฐ€ ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด UI๋ฅผ ์ง€์šฐ๋Š” ๋Œ€์‹  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ์ผ๋ถ€ ๋ถ„์„ ์„œ๋น„์Šค์— ์˜ค๋ฅ˜ ๋ณด๊ณ ์„œ๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” componentDidCatch์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ error boundary ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • error: throw ๋œ ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ Error์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋˜์ง€๋งŒ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋ฌธ์ž์—ด์ด๋‚˜ ์‹ฌ์ง€์–ด null์„ ํฌํ•จํ•œ ๋ชจ๋“  ๊ฐ’์„ throw ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณด์žฅ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

static getDerivedStateFromError๋Š” ์ปดํฌ๋„ŒํŠธ์— ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋„๋ก ์ง€์‹œํ•˜๋Š” state๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • static getDerivedStateFromError๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ถ„์„ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋“ฑ์˜ ๋ถ€์ˆ˜ ํšจ๊ณผ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด componentDidCatch๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ static getDerivedStateFromError์— ๋Œ€ํ•ด ์ง์ ‘์ ์œผ๋กœ ๋™๋“ฑํ•œ ๊ฒƒ์€ ์•„์ง ์—†์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์œผ๋ ค๋ฉด ์œ„์™€ ๊ฐ™์ด ํ•˜๋‚˜์˜ ErrorBoundary ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์•ฑ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋˜๋Š” ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” react-error-boundary package๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.


static getDerivedStateFromProps(props, state)

static getDerivedStateFromProps๋ฅผ ์ •์˜ํ•˜๋ฉด React๋Š” ์ดˆ๊ธฐ ๋งˆ์šดํŠธ ๋ฐ ํ›„์† ์—…๋ฐ์ดํŠธ ๋ชจ๋‘์—์„œ render๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ๋ฐ”๋กœ ์ „์— ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์•„๋ฌด๊ฒƒ๋„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด null์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ props์˜ ๋ณ€๊ฒฝ์— ๋”ฐ๋ผ state๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๋“œ๋ฌธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์œ„ํ•ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด Form ์ปดํฌ๋„ŒํŠธ๋Š” userId props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด email state๋ฅผ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};

static getDerivedStateFromProps(props, state) {
// ํ˜„์žฌ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค,
// ํ•ด๋‹น ์‚ฌ์šฉ์ž์™€ ์—ฐ๊ฒฐ๋œ state์˜ ๋ชจ๋“  ๋ถ€๋ถ„์„ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
// ์ด ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ์—์„œ๋Š” ์ด๋ฉ”์ผ๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}

// ...
}

์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด props์˜ ์ด์ „ ๊ฐ’(์˜ˆ: userID)์„ state(์˜ˆ: prevUserID)๋กœ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.

์ฃผ์˜ํ•˜์„ธ์š”!

state๋ฅผ ํŒŒ์ƒํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์žฅํ™ฉํ•ด์ง€๊ณ  ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ๋” ๊ฐ„๋‹จํ•œ ๋Œ€์•ˆ์— ์ต์ˆ™ํ•ด์ง€๋„๋ก ํ•˜์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

  • props: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ props์ž…๋‹ˆ๋‹ค.
  • state: ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋‹ค์Œ state์ž…๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

static getDerivedStateFromProps๋Š” state๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜, ์•„๋ฌด๊ฒƒ๋„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์œผ๋ฉด null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

  • ์ด ๋ฉ”์„œ๋“œ๋Š” ์›์ธ์— ๊ด€๊ณ„์—†์ด ๋ชจ๋“  ๋ Œ๋”๋ง์—์„œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ถ€๋ชจ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง์„ ์ผ์œผํ‚ฌ ๋•Œ๋งŒ ๋ฐœ๋™ํ•˜๊ณ  ๋กœ์ปฌ setState์˜ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹ ๋•Œ๋งŒ ๋ฐœ๋™ํ•˜๋Š” UNSAFE_componentWillReceiveProps์™€๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

  • ์ด ๋ฉ”์„œ๋“œ์—๋Š” ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๊ฒฝ์šฐ class ์ •์˜ ์™ธ๋ถ€ ์ปดํฌ๋„ŒํŠธ props ๋ฐ state์˜ ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์ถ”์ถœํ•˜์—ฌ static getDerivedStateFromProps์™€ ๋‹ค๋ฅธ class ๋ฉ”์„œ๋“œ ์‚ฌ์ด์— ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—์„œ static getDerivedStateFromProps๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ useState์—์„œ set ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.


์‚ฌ์šฉ๋ฒ•

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ์ •์˜ํ•˜๊ธฐ

React ์ปดํฌ๋„ŒํŠธ๋ฅผ class๋กœ ์ •์˜ํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ์ œ๊ณต Component class๋ฅผ ํ™•์žฅํ•˜๊ณ  render ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค,

import { Component } from 'react';

class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}

React๋Š” ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋‚ด์šฉ์„ ํŒŒ์•…ํ•ด์•ผ ํ•  ๋•Œ๋งˆ๋‹ค render ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋ณดํ†ต์€ JSX๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. render ๋ฉ”์„œ๋“œ๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. JSX๋งŒ ๊ณ„์‚ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ props๋กœ ์ •๋ณด๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ props๋ฅผ ์ฝ๋Š” ๋ฌธ๋ฒ•์€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ <Greeting name="Taylor" />๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒฝ์šฐ, this.props.name๊ณผ ๊ฐ™์ด this.props์—์„œ name prop์„ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ๋Š” Hooks(use๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ•จ์ˆ˜, ์˜ˆ๋ฅผ ๋“ค์–ด useState)๊ฐ€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

์ปดํฌ๋„ŒํŠธ๋ฅผ class ๋Œ€์‹  ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— state ์ถ”๊ฐ€ํ•˜๊ธฐ

class์— state๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด state๋ผ๋Š” ํ”„๋กœํผํ‹ฐ์— ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด this.setState๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = () => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

์ฃผ์˜ํ•˜์„ธ์š”!

์ปดํฌ๋„ŒํŠธ๋ฅผ class ๋Œ€์‹  ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์— ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€ํ•˜๊ธฐ

class์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ํŠน๋ณ„ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

componentDidMount ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ์ถ”๊ฐ€ (๋งˆ์šดํŠธ) ๋  ๋•Œ React๊ฐ€ ์ด๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ props๋‚˜ state ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•ด ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋ฉด React๋Š” componentDidUpdate๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์—์„œ ์ œ๊ฑฐ (๋งˆ์šดํŠธ ํ•ด์ œ) ๋œ ํ›„ React๋Š” componentWillUnmount๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

componentDidMount๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฒ„๊ทธ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์„ธ ๊ฐ€์ง€ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด componentDidMount๊ฐ€ state๋‚˜ props๋ฅผ ์ฝ์—ˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด componentDidUpdate๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ณ , componentDidMount๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋˜ ์ž‘์—…์„ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด componentWillUnmount๋„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด ChatRoom ์ปดํฌ๋„ŒํŠธ๋Š” ์ฑ„ํŒ… ์—ฐ๊ฒฐ์„ props ๋ฐ state์™€ ๋™๊ธฐํ™”ํ•˜์—ฌ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

Strict ๋ชจ๋“œ๊ฐ€ ์ผœ์ ธ ์žˆ์„ ๋•Œ ๊ฐœ๋ฐœํ•  ๋•Œ React๋Š” componentDidMount๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์ฆ‰์‹œ componentWillUnmount๋ฅผ ํ˜ธ์ถœํ•œ ๋‹ค์Œ, componentDidMount๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด componentWillUnmount๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ ธ๊ฑฐ๋‚˜ ๊ทธ ๋กœ์ง์ด componentDidMount์˜ ๋™์ž‘์„ ์™„์ „ํžˆ โ€œ๋ฏธ๋Ÿฌ๋งโ€ํ•˜์ง€ ์•Š๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜ํ•˜์„ธ์š”!

์ปดํฌ๋„ŒํŠธ๋ฅผ class ๋Œ€์‹  ํ•จ์ˆ˜๋กœ ์ •์˜ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”.


error boundary๋กœ ๋ Œ๋”๋ง ์˜ค๋ฅ˜ ํฌ์ฐฉํ•˜๊ธฐ

๊ธฐ๋ณธ์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ Œ๋”๋ง ๋„์ค‘ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด React๋Š” ํ™”๋ฉด์—์„œ ํ•ด๋‹น UI๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด UI์˜ ์ผ๋ถ€๋ฅผ error boundary๋กœ ๊ฐ์‹ธ๋ฉด ๋ฉ๋‹ˆ๋‹ค. error boundary๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๋ถ€๋ถ„ ๋Œ€์‹  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ๊ฐ™์€ fallback UI๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ˆ˜ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

error boundary ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” static getDerivedStateFromError๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์„ ํƒ์ ์œผ๋กœ componentDidCatch๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋ถ„์„ ์„œ๋น„์Šค์— ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๋“ฑ์˜ ์ถ”๊ฐ€ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(error) {
// state๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ๋‹ค์Œ ๋ Œ๋”๋ง์— fallback UI๊ฐ€ ํ‘œ์‹œ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
return { hasError: true };
}

componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logErrorToMyService(error, info.componentStack);
}

render() {
if (this.state.hasError) {
// ์‚ฌ์šฉ์ž ์ง€์ • fallback UI๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
return this.props.fallback;
}

return this.props.children;
}
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์˜ ์ผ๋ถ€๋ฅผ ๋ž˜ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<ErrorBoundary fallback={<p>Something went wrong</p>}>
<Profile />
</ErrorBoundary>

Profile ๋˜๋Š” ๊ทธ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด ErrorBoundary๊ฐ€ ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ โ€œํฌ์ฐฉโ€ํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ fallback UI๋ฅผ ํ‘œ์‹œํ•œ ๋‹ค์Œ ํ”„๋กœ๋•์…˜ ์˜ค๋ฅ˜ ๋ณด๊ณ ์„œ๋ฅผ ์˜ค๋ฅ˜ ๋ณด๊ณ  ์„œ๋น„์Šค์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณ„๋„์˜ error boundary๋กœ ๋ฌถ์„ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. error boundary์˜ ์„ธ๋ถ„ํ™”๋ฅผ ๊ณ ๋ คํ•  ๋•Œ๋Š” ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•œ ์œ„์น˜๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฉ”์‹œ์ง• ์•ฑ์˜ ๊ฒฝ์šฐ error boundary๋ฅผ ๋Œ€ํ™” ๋ชฉ๋ก ์ฃผ์œ„์— ์œ„์น˜์‹œํ‚ค๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ชจ๋“  ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€ ์ฃผ์œ„์— ์œ„์น˜์‹œํ‚ค๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ชจ๋“  ์•„๋ฐ”ํƒ€ ์ฃผ์œ„์— boundary๋ฅผ ์œ„์น˜์‹œํ‚ค๋Š” ๊ฒƒ์€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

ํ˜„์žฌ error boundary๋ฅผ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ error boundary class๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด react-error-boundary๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋Œ€์•ˆ

class์—์„œ ํ•จ์ˆ˜๋กœ ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ

์ผ๋ฐ˜์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ์ˆ˜๋กœ ๋Œ€์‹  ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์ด Greeting ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import { Component } from 'react';

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

Greeting์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋กœ render ํ•จ์ˆ˜์˜ ๋ณธ๋ฌธ์„ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

function Greeting() {
// ... render ๋ฉ”์„œ๋“œ์˜ ์ฝ”๋“œ๋ฅผ ์—ฌ๊ธฐ๋กœ ์˜ฎ๊น๋‹ˆ๋‹ค ...
}

this.props.name ๋Œ€์‹  ๊ตฌ์กฐ ๋ถ„ํ•ด ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ name prop์„ ์ •์˜ํ•˜๊ณ  ์ง์ ‘ ์ฝ์Šต๋‹ˆ๋‹ค.

function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}

๋‹ค์Œ์€ ์ „์ฒด ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}


state๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ class์—์„œ ํ•จ์ˆ˜๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ

์ด Counter ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค.

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = (e) => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

ํ•„์š”ํ•œ state ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•˜์„ธ์š”.

import { useState } from 'react';

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...

๋‹ค์Œ์œผ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);

function handleNameChange(e) {
setName(e.target.value);
}

function handleAgeChange() {
setAge(age + 1);
}
// ...

๋งˆ์ง€๋ง‰์œผ๋กœ, this์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ •์˜ํ•œ ๋ณ€์ˆ˜ ๋ฐ ํ•จ์ˆ˜๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, this.state.age๋ฅผ age๋กœ ๋ฐ”๊พธ๊ณ  this.handleNameChange๋ฅผ handleNameChange๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์™„์ „ํžˆ ๋ณ€ํ™˜๋œ ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

import { useState } from 'react';

export default function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  function handleNameChange(e) {
    setName(e.target.value);
  }

  function handleAgeChange() {
    setAge(age + 1);
  }

  return (
    <>
      <input
        value={name}
        onChange={handleNameChange}
      />
      <button onClick={handleAgeChange}>
        Increment age
      </button>
      <p>Hello, {name}. You are {age}.</p>
    </>
  )
}


์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ class์—์„œ ํ•จ์ˆ˜๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ

์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” ChatRoom ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•จ์ˆ˜๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

๋จผ์ € componentWillUnmount๊ฐ€ componentDidMount์™€ ๋ฐ˜๋Œ€ ๋™์ž‘์„ ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ์—์„œ๋Š” componentDidMount๊ฐ€ ์„ค์ •ํ•œ ์—ฐ๊ฒฐ์„ ๋Š์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋กœ์ง์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ ๋จผ์ € ์ถ”๊ฐ€ํ•˜์„ธ์š”.

๋‹ค์Œ์œผ๋กœ, componentDidUpdate ๋ฉ”์„œ๋“œ๊ฐ€ componentDidMount์—์„œ ์‚ฌ์šฉ ์ค‘์ธ props ๋ฐ state์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ์—์„œ componentDidMount๋Š” this.state.serverUrl๊ณผ this.props.roomId๋ฅผ ์ฝ๋Š” setupConnection์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์— componentDidUpdate๋Š” this.state.serverUrl๊ณผ this.props.roomId๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ์—ฐ๊ฒฐ์„ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. componentDidUpdate ๋กœ์ง์ด ๋ˆ„๋ฝ๋˜์—ˆ๊ฑฐ๋‚˜ ๋ชจ๋“  ๊ด€๋ จ props ๋ฐ state์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋จผ์ € ํ•ด๋‹น ๋กœ์ง์„ ์ˆ˜์ •ํ•˜์„ธ์š”.

์œ„์˜ ์˜ˆ์‹œ์—์„œ, ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์˜ ๋กœ์ง์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ React ์™ธ๋ถ€์˜ ์‹œ์Šคํ…œ(์ฑ„ํŒ… ์„œ๋ฒ„)์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์™ธ๋ถ€ ์‹œ์Šคํ…œ์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ์ด ๋กœ์ง์„ ํ•˜๋‚˜์˜ Effect๋กœ ์„ค๋ช…ํ•˜์„ธ์š”.

import { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);

// ...
}

์ด useEffect ํ˜ธ์ถœ์€ ์œ„์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ์˜ ๋กœ์ง๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๊ฐ€ ์„œ๋กœ ๊ด€๋ จ์ด ์—†๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ์ด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ Effect๋กœ ๋ถ„ํ• ํ•˜์„ธ์š”. ๋‹ค์Œ์€ ์™„์ „ํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId, serverUrl]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>Welcome to the {roomId} room!</h1>
    </>
  );
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

์ปดํฌ๋„ŒํŠธ๊ฐ€ ์™ธ๋ถ€ ์‹œ์Šคํ…œ๊ณผ ๋™๊ธฐํ™”๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ Effect๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


context๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ class์—์„œ ํ•จ์ˆ˜๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ

์ด ์˜ˆ์ œ์—์„œ Panel ๋ฐ Button ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” this.context์—์„œ context๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค:

import { createContext, Component } from 'react';

const ThemeContext = createContext(null);

class Panel extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'panel-' + theme;
    return (
      <section className={className}>
        <h1>{this.props.title}</h1>
        {this.props.children}
      </section>
    );    
  }
}

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ๋Š” this.context๋ฅผ useContext ํ˜ธ์ถœ๋กœ ๋ฐ”๊ฟ”์ฃผ์„ธ์š”.

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}