Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.

Latest commit

ย 

History

History
472 lines (376 loc) ยท 17.2 KB

File metadata and controls

472 lines (376 loc) ยท 17.2 KB

6. ์‹ฌํ™”: ๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ

์—ฌ๋Ÿฌ๋ถ„์€ ์ด์ œ ๊ธฐ๋ณธ์ ์ธ ๋ฆฌ์•กํŠธ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์žฅ์—์„œ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ ์‹ฌํ™” ๋‚ด์šฉ์œผ๋กœ ๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ชจ๋ฒ” ์‚ฌ๋ก€์™€ ์ ์šฉ ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค. ๋” ๋‚˜์•„๊ฐ€ ๋Œ€ํ‘œ์ ์ธ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ํ•จ๊ป˜ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

6.1 ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ

App ์ปดํฌ๋„ŒํŠธ๋Š” ES6 ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ์—์„œ ์ƒํƒœ์™€ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. Table ์ปดํฌ๋„ŒํŠธ๋กœ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋ฅผ props๋กœ ๋„˜๊ฒผ์Šต๋‹ˆ๋‹ค. ์ด props๋Š” Table ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ App ์ปดํฌ๋„ŒํŠธ๋Š” Table ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š”์ง€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๋ฆฌ์ŠคํŠธ ์ •๋ ฌ ๊ธฐ๋Šฅ์€ Table ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. App ์ปดํฌ๋„ŒํŠธ๋Š” Table ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๊ธฐ๋Šฅ์„ Table ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠน์ • ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ „๋‹ฌํ•œ ํ•˜์œ„ ์ƒํƒœ๋ฅผ ๋ฆฌํŒฉํ„ฐ๋ง ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒํƒœ ๋Œ์–ด์˜ฌ๋ฆฌ๊ธฐ(lifting state) ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” App ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ƒํƒœ๋ฅผ Table ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ธฐ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ธฐ๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.

Table ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ์™€ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ES6 ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ES6 ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฆฌํŒฉํ„ฐ๋ง์€ ์‰ฝ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ Table ์ปดํฌ๋„ŒํŠธ๋Š” ๋น„ ์ƒํƒœ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

const Table = ({
  list,
  sortKey,
  isSortReverse,
  onSort,
  onDismiss
}) => {
  const sortedList = SORTS[sortKey](list);
  const reverseSortedList = isSortReverse
    ? sortedList.reverse()
    : sortedList;

  return(
    ...
  );
}

Table ์ปดํฌ๋„ŒํŠธ๋ฅผ ES6 ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋กœ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

# leanpub-start-insert
class Table extends Component {
  render() {
    const {
      list,
      sortKey,
      isSortReverse,
      onSort,
      onDismiss
    } = this.props;

    const sortedList = SORTS[sortKey](list);
    const reverseSortedList = isSortReverse
      ? sortedList.reverse()
      : sortedList;

    return(
      ...
    );
  }
}
# leanpub-end-insert

์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ์ž์™€ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

class Table extends Component {
# leanpub-start-insert
  constructor(props) {
    super(props);

    this.state = {};
  }
# leanpub-end-insert

  render() {
    ...
  }
}

์ด์ œ App ์ปดํฌ๋„ŒํŠธ์˜ ์ •๋ ฌ ๊ธฐ๋Šฅ์— ํ•ด๋‹นํ•˜๋Š” ์ƒํƒœ์™€ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ Table ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊น๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

class Table extends Component {
  constructor(props) {
    super(props);

# leanpub-start-insert
    this.state = {
      sortKey: 'NONE',
      isSortReverse: false,
    };

    this.onSort = this.onSort.bind(this);
# leanpub-end-insert
  }

# leanpub-start-insert
  onSort(sortKey) {
    const isSortReverse = this.state.sortKey === sortKey && !this.state.isSortReverse;
    this.setState({ sortKey, isSortReverse });
  }
# leanpub-end-insert

  render() {
    ...
  }
}

App ์ปดํฌ๋„ŒํŠธ์—์„œ ์˜ฎ๊ธด ์ƒํƒœ์™€ onSort() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ญ์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      results: null,
      searchKey: '',
      searchTerm: DEFAULT_QUERY,
      error: null,
      isLoading: false,
    };

    this.setSearchTopStories = this.setSearchTopStories.bind(this);
    this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this);
    this.onDismiss = this.onDismiss.bind(this);
    this.onSearchSubmit = this.onSearchSubmit.bind(this);
    this.onSearchChange = this.onSearchChange.bind(this);
    this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this);
  }

  ...

}

Table ์ปดํฌ๋„ŒํŠธ API๋ฅผ ๋” ๊ฐ€๋ณ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. App ์ปดํฌ๋„ŒํŠธ์—์„œ ์ „๋‹ฌ๋œ props๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด, Table ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ญ์‹œ๋‹ค.

{title="src/App.js",lang=javascript}

class App extends Component {

  ...

  render() {
# leanpub-start-insert
    const {
      searchTerm,
      results,
      searchKey,
      error,
      isLoading
    } = this.state;
# leanpub-end-insert

    ...

    return (
      <div className="page">
        ...
# leanpub-start-insert
        <Table
          list={list}
          onDismiss={this.onDismiss}
        />
# leanpub-end-insert
        ...
      </div>
    );
  }
}

์ด์ œ Table ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ onSort() ๋ฉ”์„œ๋“œ์™€ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

class Table extends Component {

  ...

  render() {
# leanpub-start-insert
    const {
      list,
      onDismiss
    } = this.props;

    const {
      sortKey,
      isSortReverse,
    } = this.state;
# leanpub-end-insert

    const sortedList = SORTS[sortKey](list);
    const reverseSortedList = isSortReverse
      ? sortedList.reverse()
      : sortedList;

    return(
      <div className="table">
        <div className="table-header">
          <span style={{ width: '40%' }}>
            <Sort
              sortKey={'TITLE'}
# leanpub-start-insert
              onSort={this.onSort}
# leanpub-end-insert
              activeSortKey={sortKey}
            >
              Title
            </Sort>
          </span>
          <span style={{ width: '30%' }}>
            <Sort
              sortKey={'AUTHOR'}
# leanpub-start-insert
              onSort={this.onSort}
# leanpub-end-insert
              activeSortKey={sortKey}
            >
              Author
            </Sort>
          </span>
          <span style={{ width: '10%' }}>
            <Sort
              sortKey={'COMMENTS'}
# leanpub-start-insert
              onSort={this.onSort}
# leanpub-end-insert
              activeSortKey={sortKey}
            >
              Comments
            </Sort>
          </span>
          <span style={{ width: '10%' }}>
            <Sort
              sortKey={'POINTS'}
# leanpub-start-insert
              onSort={this.onSort}
# leanpub-end-insert
              activeSortKey={sortKey}
            >
              Points
            </Sort>
          </span>
          <span style={{ width: '10%' }}>
            Archive
          </span>
        </div>
        { reverseSortedList.map((item) =>
          ...
        )}
      </div>
    );
  }
}

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ์—ฌ๋Ÿฌ๋ถ„์€ ์ง€๊ธˆ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ์—์„œ ์ œ์ผ ์ค‘์š”ํ•œ ๋ฆฌํŒฉํ„ฐ๋ง ๊ณผ์ •์„ ํ•ด๋ƒˆ์Šต๋‹ˆ๋‹ค. Table ์ปดํฌ๋„ŒํŠธ API๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ •๋ ฌ ๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ด€๋ จ ์žˆ๋Š” ์ƒํƒœ์™€ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ด๋™์‹œ์ผœ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€๋ณ๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํƒœ๋ฅผ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ๊ทธ ์ƒํƒœ๊ฐ€ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•œ๋‹ค๋ฉด, ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํƒœ๋ฅผ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋” ๋‚˜์•„๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ํ˜•์ œ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค. ์ด ์—ญ์‹œ ํ˜•์ œ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋ฅผ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋‘ ์ปดํฌ๋„ŒํŠธ์— ๋ชจ๋‘ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์ฝ์–ด๋ณด๊ธฐ

6.2 ์‹ฌํ™”: setState()

์ง€๊ธˆ๊นŒ์ง€ setState() ๋ฉ”์„œ๋“œ๋กœ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ „์ฒด ์ƒํƒœ ์ค‘ ๋ถ€๋ถ„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ๊ฐ์ฒด๋ฅผ ํ•จ์ˆ˜์— ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

{title="Code Playground",lang="javascript"}

this.setState({ foo: bar });

setState()๋Š” ๊ฐ์ฒด ํ•˜๋‚˜๋งŒ ์ทจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{title="Code Playground",lang="javascript"}

this.setState((prevState, props) => {
  ...
});

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

{title="Code Playground",lang="javascript"}

const { fooCount } = this.state;
const { barCount } = this.props;
this.setState({ count: fooCount + barCount });

fooCount๊ณผ barCount๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  setState() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ state ๋˜๋Š” props์— ๋”ฐ๋ผ ์–ด๋–ค ๊ณณ์ด ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ํ•ฉ์‹œ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด์„œ ํ•œ ๊ฐœ ์ด์ƒ์˜ setState()๊ฐ€ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ์ผ์ด ์ƒ๊น๋‹ˆ๋‹ค. setState()๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด์ „ ์ƒํƒœ ๊ฐ’์„ ์˜์กดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

setState() ๋ฉ”์„œ๋“œ๋Š” state์™€ props๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. setState() ๋ฉ”์„œ๋“œ๋Š” ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰๋  ๋•Œ ์ด์ „ state์™€ props๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

{title="Code Playground",lang="javascript"}

this.setState((prevState, props) => {
  const { fooCount } = prevState;
  const { barCount } = props;
  return { count: fooCount + barCount };
});

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ด…์‹œ๋‹ค. setState() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ณณ์„ ์ˆ˜์ •ํ•ด state์™€ props๋ฅผ ์˜์กดํ•˜๊ฒŒ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค๋ฅธ ๊ณณ๋„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

setSearchTopStories() ๋ฉ”์„œ๋“œ๋Š” ์ด์ „ ์ƒํƒœ๋ฅผ ์˜์กดํ•จ์œผ๋กœ setState() ๋ฉ”์„œ๋“œ์—์„œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ํ˜„์žฌ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

setSearchTopStories(result) {
  const { hits, page } = result;
  const { searchKey, results } = this.state;

  const oldHits = results && results[searchKey]
    ? results[searchKey].hits
    : [];

  const updatedHits = [
    ...oldHits,
    ...hits
  ];

  this.setState({
    results: {
      ...results,
      [searchKey]: { hits: updatedHits, page }
    },
    isLoading: false
  });
}

์ƒํƒœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค์ง€๋งŒ ๋น„๋™๊ธฐ๋กœ ์ด์ „ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์ด์ „ ์ƒํƒœ๋กœ ์ธํ•ด ๋ฒ„๊ทธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

{title="src/App.js",lang=javascript}

setSearchTopStories(result) {
  const { hits, page } = result;

# leanpub-start-insert
  this.setState(prevState => {
    ...
  });
# leanpub-end-insert
}

์—ฌ๊ธฐ์„œ ๊ตฌํ˜„ํ•œ ๋ธ”๋ก ์ „์ฒด๋ฅผ ํ•จ์ˆ˜ ์•ˆ์œผ๋กœ ์˜ฎ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. this.state์„ prevState์œผ๋กœ ๋ฐ”๊พธ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

{title="src/App.js",lang=javascript}

setSearchTopStories(result) {
  const { hits, page } = result;

  this.setState(prevState => {
# leanpub-start-insert
    const { searchKey, results } = prevState;

    const oldHits = results && results[searchKey]
      ? results[searchKey].hits
      : [];

    const updatedHits = [
      ...oldHits,
      ...hits
    ];

    return {
      results: {
        ...results,
        [searchKey]: { hits: updatedHits, page }
      },
      isLoading: false
    };
# leanpub-end-insert
  });
}

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

{title="src/App.js",lang=javascript}

setSearchTopStories(result) {
  const { hits, page } = result;
  this.setState(updateSearchTopStoriesState(hits, page));
}

updateSearchTopStoriesState() ๋ฉ”์„œ๋“œ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณ ์ฐจ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ณ ์ฐจ ํ•จ์ˆ˜๋Š” App ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ์ •์˜ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ์กฐ๊ธˆ ๋‹ฌ๋ผ์กŒ๋‹ค๋Š” ์ ๋งŒ ์œ ๋…ํ•ฉ์‹œ๋‹ค.

{title="src/App.js",lang=javascript}

# leanpub-start-insert
const updateSearchTopStoriesState = (hits, page) => (prevState) => {
  const { searchKey, results } = prevState;

  const oldHits = results && results[searchKey]
    ? results[searchKey].hits
    : [];

  const updatedHits = [
    ...oldHits,
    ...hits
  ];

  return {
    results: {
      ...results,
      [searchKey]: { hits: updatedHits, page }
    },
    isLoading: false
  };
};
# leanpub-end-insert

class App extends Component {
  ...
}

setState() ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ์ฒด ์ ‘๊ทผ ํ•จ์ˆ˜๋Š” ์ž ์žฌ์ ์ธ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ๊ณ  ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์„ ๋†’์—ฌ์ค๋‹ˆ๋‹ค. ๋˜ํ•œ App ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ ๋ฐ–์œผ๋กœ export ํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ์–ด๋ณด๊ธฐ

์‹ค์Šตํ•˜๊ธฐ

  • setState() ๋ฉ”์„œ๋“œ์—์„œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฆฌํŒฉํ„ฐ๋ง ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜์กด๋œ props ๋˜๋Š” state๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ
  • ํ…Œ์ŠคํŠธ๋ฅผ ์žฌ์‹คํ–‰ํ•˜๊ณ  ์—…๋ฐ์ดํŠธ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

6.3 ์ƒํƒœ ์ œ์–ด

๊ทœ๋ชจ๊ฐ€ ํฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒํƒœ ๊ด€๋ฆฌ๋Š” ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ๋ฌผ๋ก  ๋งŽ์€ SPA ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ตœ๊ทผ ๋ช‡ ๋…„๊ฐ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋” ๋ณต์žกํ•ด์ง์— ๋”ฐ๋ผ ์ƒํƒœ ์ œ์–ดํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋Œ€๋‘๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ์•กํŠธ๋Š” ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์— ๋น„ํ•ด์„œ ์ด๋ฏธ ํฐ ๋ฐœ์ „์„ ์ด๋ค˜์Šต๋‹ˆ๋‹ค. ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” API๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ƒํƒœ์™€ ์ƒํƒœ ๋ณ€๊ฒฝ ์‚ฌํ•ญ, ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์—์„œ ํŠน์ • ์ˆ˜์ค€์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ๊นŒ์ง€ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

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

์ด๋Ÿฌํ•œ ๋ชจ๋“  ์ด์œ ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋…๋ฆฝํ˜• ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์†”๋ฃจ์…˜์€ ๋ฆฌ์•กํŠธ์—๋งŒ ํ—ˆ์šฉ๋œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํƒ€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ ์ด ๋ฐ”๋กœ ๋ฆฌ์•กํŠธ ์ƒํƒœ๊ณ„๋ฅผ ํ’๋ถ€ํ•˜๊ณ  ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค. ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ ๋ฆฌ๋•์Šค(Redux)์™€ ๋ชจ๋ธŒ์—‘์Šค(MobX)์— ๋Œ€ํ•ด ๋“ค์–ด๋ดค์„ ๊ฒ๋‹ˆ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด ๋ฆฌ์•กํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. react-redux ๋˜๋Š” mobx-react ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„์ž…ํ•ด ๋ฆฌ์•กํŠธ ๋ทฐ ๋ ˆ์ด์–ด์— ํ†ตํ•ฉ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋•์Šค์™€ ๋ชจ๋ธŒ์—‘์Šค๋Š” ์ด ์ฑ…์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ๋ฆฌ์•กํŠธ ํ•™์Šต ๋ฐฉ๋ฒ•์„ ์Šค์Šค๋กœ ํ„ฐ๋“ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ๋ฆฌ์•กํŠธ ์ƒํƒœ๊ณ„๋ฅผ ํƒํ—˜ํ•˜๋ฉฐ ๋” ๋„“๊ณ  ๊นŠ๊ฒŒ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฆฌ์•กํŠธ๋ฅผ ์ถฉ๋ถ„ํžˆ ์ต์ˆ™ํ•ด์ง„ ๋‹ค์Œ ๋ฆฌ๋•์Šค๋ฅผ ์‹œ์ž‘ํ•˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋ฆฌ๋•์Šค๋กœ ๋„˜์–ด๊ฐ€๊ธฐ ์ „, ์ €์ž์˜ '๋ฆฌ๋•์Šค์™€ ๋ชจ๋ธŒ์—‘์Šค ๋ฐ”๋กœ ์•Œ๊ธฐ - ์™ธ๋ถ€ ์ƒํƒœ ๊ด€๋ฆฌ ํ•™์Šต ๋ฐฉ๋ฒ•' ๊ธ€๋„ ์ฐธ๊ณ ํ•˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ฝ์–ด๋ณด๊ธฐ

{pagebreak}

6.4 ์ •๋ฆฌํ•˜๋ฉด

6์žฅ์—์„œ๋Š” ์‹ฌํ™” ์ˆ˜์ค€์˜ ๋ฆฌ์•กํŠธ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ด…์‹œ๋‹ค.

  • ๋ฆฌ์•กํŠธ
    • ์“ฐ์ž„์ƒˆ์™€ ์—ญํ• ์— ๋งž๊ฒŒ ์ƒํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒํƒœ๋ฅผ ์žฌ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.
    • setState() ๋ฉ”์„œ๋“œ์—์„œ ๊ณผ๊ฑฐ ์ƒํƒœ๋กœ ์ธํ•œ ๋ฒ„๊ทธ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์™ธ๋ถ€์—์„œ ๋ณ„๋„ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ธ์ž๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ์™ธ๋ถ€์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์Šต ์ฝ”๋“œ๋Š” ๊นƒํ—ˆ๋ธŒ ๋ฆฌํผ์ง€ํ† ๋ฆฌ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.