We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

์ปดํฌ๋„ŒํŠธ์— ํ•จ์ˆ˜ ์ „๋‹ฌํ•˜๊ธฐ

์ปดํฌ๋„ŒํŠธ๋กœ onClick๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์–ด๋–ป๊ฒŒ ์ „๋‹ฌ ํ• ๊นŒ์š”?

์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ํ”„๋กœํผํ‹ฐ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์™€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

<button onClick={this.handleClick}>

ํ•ธ๋“ค๋Ÿฌ ์•ˆ์—์„œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ์ ‘๊ทผํ•  ํ•„์š”๊ฐ€ ์žˆ์œผ๋ฉด ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์— ํ•จ์ˆ˜๋ฅผ ๋ฐ”์ธ๋”ฉํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋กœ ํ•จ์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ”์ธ๋”ฉํ• ๊นŒ์š”?

์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ฌธ๋ฒ•๊ณผ ๋นŒ๋“œ ๋‹จ๊ณ„์— ๋”ฐ๋ผ this.props, this.state์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ์˜ ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์— ํ•จ์ˆ˜๋“ค์ด ํ™•์‹คํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž์—์„œ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ (ES2015)

class Foo extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <button onClick={this.handleClick}>Click Me</button>;
  }
}

ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ (ES2022)

class Foo extends Component {
  handleClick = () => {
    console.log('Click happened');
  };
  render() {
    return <button onClick={this.handleClick}>Click Me</button>;
  }
}

render ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ๋ฐ”์ธ๋”ฉํ•˜๊ธฐ

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
  }
}

์ฃผ์˜

Function.prototype.bind๋ฅผ render ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

render ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜ ์‚ฌ์šฉ

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <button onClick={() => this.handleClick()}>Click Me</button>;
  }
}

์ฃผ์˜

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

render ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ์„๊นŒ์š”?

์ด ๋ฐฉ๋ฒ•์€ ๋Œ€์ฒด๋กœ ์‚ฌ์šฉํ•ด๋„ ๊ดœ์ฐฎ๊ณ , ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ ์ตœ์ ํ™”๋ฅผ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”์ธ๋”ฉ์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ผ ๊นŒ์š”?

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์•„๋ž˜ ๋‘ ๊ฐœ์˜ ์ฝ”๋“œ ์กฐ๊ฐ์€ ๋™์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

obj.method();
var method = obj.method;
method();

๋ฐ”์ธ๋”ฉ ๋ฉ”์„œ๋“œ๋Š” ๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ ์กฐ๊ฐ์ด ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ์กฐ๊ฐ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ React์—์„œ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ๋ฉ”์„œ๋“œ๋ฅผ ์ „๋‹ฌํ•ด ์ค„ ๋•Œ๋งŒ ๋ฐ”์ธ๋”ฉํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด <button onClick={this.handleClick}>๋Š” this.handleClick์„ ์ „๋‹ฌํ•˜์—ฌ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ render ๋ฉ”์„œ๋“œ๋‚˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”์ธ๋”ฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Yehuda Katz์˜ ๊ธ€์—์„œ ๋ฐ”์ธ๋”ฉ์ด ๋ฌด์—‡์ธ์ง€, JavaScript์—์„œ ์–ด๋–ป๊ฒŒ ํ•จ์ˆ˜๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์ƒ์„ธํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ ๊นŒ์š”?

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

render() {
  // ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•: handleClick์€ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ „๋‹ฌ๋˜์ง€ ์•Š๊ณ  ํ˜ธ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!
  return <button onClick={this.handleClick()}>Click Me</button>
}

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ ๊ด„ํ˜ธ ์—†์ด ํ•จ์ˆ˜ ๊ทธ ์ž์ฒด๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

render() {
  // ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• : handleClick์ด ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ „๋‹ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  return <button onClick={this.handleClick}>Click Me</button>
}

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ ์ฝœ๋ฐฑ์— ์–ด๋–ป๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ• ๋‚˜์š”?

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์‹ผ ๋‹ค์Œ์— ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<button onClick={() => this.handleClick(id)} />

.bind๋ฅผ ํ˜ธ์ถœํ•œ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<button onClick={this.handleClick.bind(this, id)} />

์˜ˆ์‹œ: ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌํ•˜๊ธฐ

const A = 65 // ASCII character code

class Alphabet extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      justClicked: null,
      letters: Array.from({length: 26}, (_, i) => String.fromCharCode(A + i))
    };
  }
  handleClick(letter) {
    this.setState({ justClicked: letter });
  }
  render() {
    return (
      <div>
        Just clicked: {this.state.justClicked}
        <ul>
          {this.state.letters.map(letter =>
            <li key={letter} onClick={() => this.handleClick(letter)}>
              {letter}
            </li>
          )}
        </ul>
      </div>
    )
  }
}

์˜ˆ์‹œ: data-attributes๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ „๋‹ฌํ•˜๊ธฐ

๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด DOM API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์•„์ฃผ ๋งŽ์€ ์š”์†Œ๋ฅผ ์ตœ์ ํ™”ํ•˜๊ฑฐ๋‚˜ React.PureComponent ๋™์ผ์„ฑ ๊ฒ€์‚ฌ์— ์˜์กดํ•˜๋Š” ๋ Œ๋”๋ง ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ณ ๋ คํ•ด ๋ณผ ๋งŒํ•ฉ๋‹ˆ๋‹ค.

const A = 65 // ASCII character code

class Alphabet extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      justClicked: null,
      letters: Array.from({length: 26}, (_, i) => String.fromCharCode(A + i))
    };
  }

  handleClick(e) {
    this.setState({
      justClicked: e.target.dataset.letter
    });
  }

  render() {
    return (
      <div>
        Just clicked: {this.state.justClicked}
        <ul>
          {this.state.letters.map(letter =>
            <li key={letter} data-letter={letter} onClick={this.handleClick}>
              {letter}
            </li>
          )}
        </ul>
      </div>
    )
  }
}

์–ด๋–ป๊ฒŒ ํ•จ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋นจ๋ฆฌ, ๋„ˆ๋ฌด ๋งŽ์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‚˜์š”?

onClick ๋˜๋Š” onScroll๊ณผ ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์„ ๋•Œ ์ฝœ๋ฐฑ์ด ๋„ˆ๋ฌด ๋น ๋ฅด๊ฒŒ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋˜๋Š” ์†๋„๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์˜ ํ•จ์ˆ˜๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • throttling: ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋นˆ๋„์— ๋”ฐ๋ฅธ ๋ณ€๊ฒฝ ์ƒ˜ํ”Œ๋ง (์˜ˆ์‹œ _.throttle)
  • debouncing: ๋น„ํ™œ์„ฑ ์ฃผ๊ธฐ ์ดํ›„์— ๋ณ€๊ฒฝ ์ ์šฉ (์˜ˆ์‹œ _.debounce)
  • requestAnimationFrame throttling: requestAnimationFrame (์˜ˆ์‹œ raf-schd)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ณ€๊ฒฝ ์ƒ˜ํ”Œ๋ง

throttle๊ณผ debounce ํ•จ์ˆ˜๋ฅผ ๋น„๊ตํ•˜๊ณ  ์‹ถ์œผ๋ฉด ์‹œ๊ฐํ™”๋ฅผ ํ™•์ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์˜

_.debounce, _.throttle, raf-schd๋Š” ์ง€์—ฐ๋˜๋Š” ์ฝœ๋ฐฑ์„ ์ทจ์†Œํ•˜๋Š” ๋ฉ”์„œ๋“œ cancel์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. componentWillUnmount์—์„œ ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋˜๋Š” ์ง€์—ฐ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๊ฐ€ ๋˜์–ด์žˆ์Œ์„ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Throttle

Throttling์€ ํ•จ์ˆ˜๊ฐ€ ์ฃผ์–ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ์— ํ•œ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” โ€œclickโ€ ํ•ธ๋“ค๋Ÿฌ์— throttling์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๋‹น ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋˜๋„๋ก ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

import throttle from 'lodash.throttle';

class LoadMoreButton extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.handleClickThrottled = throttle(this.handleClick, 1000);
  }

  componentWillUnmount() {
    this.handleClickThrottled.cancel();
  }

  render() {
    return <button onClick={this.handleClickThrottled}>Load More</button>;
  }

  handleClick() {
    this.props.loadMore();
  }
}

Debounce

Debouncing์€ ํ•จ์ˆ˜๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ˜ธ์ถœ๋œ ํ›„ ํŠน์ • ์‹œ๊ฐ„๊นŒ์ง€ ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ๋น ๋ฅด๊ฒŒ ๋ฐœํ–‰ํ•˜๋Š” ์ด๋ฒคํŠธ(์˜ˆ์‹œ ์Šคํฌ๋กค, ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ)์˜ ์‘๋‹ต์œผ๋กœ ์–ด๋–ค ๋น„์‹ผ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” 250 ๋ฐ€๋ฆฌ์ดˆ ์ด๋‚ด์˜ ํ…์ŠคํŠธ ์ž…๋ ฅ์„ Debouncingํ–ˆ์Šต๋‹ˆ๋‹ค.

import debounce from 'lodash.debounce';

class Searchbox extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.emitChangeDebounced = debounce(this.emitChange, 250);
  }

  componentWillUnmount() {
    this.emitChangeDebounced.cancel();
  }

  render() {
    return (
      <input
        type="text"
        onChange={this.handleChange}
        placeholder="Search..."
        defaultValue={this.props.value}
      />
    );
  }

  handleChange(e) {
    this.emitChangeDebounced(e.target.value);
  }

  emitChange(value) {
    this.props.onChange(value);
  }
}

requestAnimationFrame throttling

requestAnimationFrame์€ ๋ Œ๋”๋ง ์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ตœ์ ํ™”๋œ ์‹œ๊ฐ„์— ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ํ•จ์ˆ˜๋ฅผ ํ์ž‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. requestAnimationFrame์˜ ํ๋กœ ๋“ค์–ด๊ฐ„ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ ํ”„๋ ˆ์ž„์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” 1์ดˆ๋‹น 60 ํ”„๋ ˆ์ž„(60 fps)์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์—ด์‹ฌํžˆ ์ผํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด๋ฅผ ํ•˜์ง€ ๋ชปํ• ๋•Œ ์ €์ ˆ๋กœ ํ”„๋ ˆ์ž„์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ํ•œ ๊ธฐ๊ธฐ๊ฐ€ 30 fps๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด 1์ดˆ ๋™์•ˆ 30 ํ”„๋ ˆ์ž„๋งŒ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. throttling์„ ์œ„ํ•ด requestAnimationFrame์„ ์‚ฌ์šฉํ•˜๋ฉด 1์ดˆ์— 60๋ฒˆ ์ด์ƒ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 1์ดˆ๋‹น 100๋ฒˆ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๋ธŒ๋ผ์šฐ์ €์— ์ผ์„ ๋งŒ๋“ค์–ด ์ฃผ์–ด๋„, ์œ ์ €๋Š” ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ฃผ์˜

์ด ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด, ํ”„๋ ˆ์ž„์— ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฒŒ์žฌ๋œ ๊ฐ’๋งŒ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ตœ์ ํ™”๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์˜ˆ์‹œ๋Š” MDN์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import rafSchedule from 'raf-schd';

class ScrollListener extends React.Component {
  constructor(props) {
    super(props);

    this.handleScroll = this.handleScroll.bind(this);

    // ์—…๋ฐ์ดํŠธ ์ผ์ •์„ ์ •ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    this.scheduleUpdate = rafSchedule(
      point => this.props.onScroll(point)
    );
  }

  handleScroll(e) {
    // ์Šคํฌ๋กค ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๊ฒŒ ๋˜๋ฉด ์—…๋ฐ์ดํŠธ๋ฅผ ์ผ์ •์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    // ํ•œ ํ”„๋ ˆ์ž„ ์•ˆ์— ๋งŽ์€ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ›์œผ๋ฉด ์˜ค์ง ๋งˆ์ง€๋ง‰ ๊ฐ’๋งŒ ๊ฒŒ์žฌํ•ฉ๋‹ˆ๋‹ค.
    this.scheduleUpdate({ x: e.clientX, y: e.clientY });
  }

  componentWillUnmount() {
    // ๋งˆ์šดํŠธ ํ•ด์ œ ์ค‘์— ์ž„์‹œ์ƒํƒœ์˜ ์—…๋ฐ์ดํŠธ๋“ค์„ ๋ชจ๋‘ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.
    this.scheduleUpdate.cancel();
  }

  render() {
    return (
      <div
        style={{ overflow: 'scroll' }}
        onScroll={this.handleScroll}
      >
        <img src="/my-huge-image.jpg" />
      </div>
    );
  }
}

์†๋„ ์ œํ•œ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

์†๋„ ์ œํ•œ ์ฝ”๋“œ๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•  ๋•Œ, ๋นจ๋ฆฌ ๊ฐ๊ธฐ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. jest๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด mock timers๋ฅผ ๋นจ๋ฆฌ ๊ฐ๊ธฐ ๋„๊ตฌ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. requestAnimationFrame throttling์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์• ๋‹ˆ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„์˜ ํ‹ฑ์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ ํˆด๋กœ raf-stub๋ฅผ ๋ณด๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

Is this page useful?Edit this page