React - ๊ธฐ๋ณธ์ ์ธ ์ด๋ก  ์ปจ์…‰

React - ๊ธฐ๋ณธ์ ์ธ ์ด๋ก  ์ปจ์…‰

Front-end developer WONISM
Interested in ReactJS, RxJS and ReasonML.

์ฐธ๊ณ  : ์ด ๋ฌธ์„œ๋Š” react-basic ์„ ๋ฒˆ์—ญํ•œ ๊ฒƒ์œผ๋กœ ์˜์—ญ ํ˜น์€ ์˜ค์—ญ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ์„ ์ฐธ๊ณ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ๋Š” ํ•„์ž์˜ React ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ์„œ์ด๋‹ค. ์ด ๋””์ž์ธ์„ ์ด๋„๋Š” ์—ฐ์—ญ์  ์ถ”๋ก ์˜ ๊ด€์ ์—์„œ ์ด๋ฅผ ์„ค๋ช…ํ•˜๊ณ ์ž ํ•œ๋‹ค.

๋ถ„๋ช… ๋…ผ์Ÿ์˜ ์—ฌ์ง€๊ฐ€ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ „์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์˜ˆ์ œ์˜ ์‹ค์ œ ๋””์ž์ธ์€ ๋ฒ„๊ทธ๋‚˜ ํ‹ˆ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด ์˜ˆ์ œ๋Š” ๋‹จ์ง€ ๊ณต์‹ํ™”์˜ ์‹œ์ž‘์ด๋ฉฐ, ์–ด๋–ป๊ฒŒ ๊ณต์‹ํ™”ํ•˜๋Š” ์ง€์— ๋Œ€ํ•œ ๋” ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ง์„ค์ด์ง€ ๋ง๊ณ  Pull Request๋ฅผ ๋ณด๋‚ด์ฃผ๊ธธ ๋ฐ”๋ž€๋‹ค. ๋‹จ์ˆœ > ๋ณต์žก์œผ๋กœ์˜ ์ง„ํ–‰์€ ๋„ˆ๋ฌด ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ธ๋ถ€์‚ฌํ•ญ ์—†์ด๋„ ํ•ฉ๋‹นํ•ด์•ผ ํ•œ๋‹ค.

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

๋‚˜๋Š” ๋‚ด๊ฐ€ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋” ๋‹จ์ˆœํ•œ ์ดํ•ด๋ฅผ ํ•˜๊ณ  ์‹ถ๋‹ค.

๋ณ€ํ˜•

๋ฆฌ์•กํŠธ์˜ ํ•ต์ง ์ „์ œ๋Š” UI๊ฐ€ ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฅธ ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ๋กœ ํˆฌ์˜ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋™์ผํ•œ ์ž…๋ ฅ์€ ํ•ญ์ƒ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๋ฉฐ, ๋‹จ์ˆœํ•œ ์ˆœ์ˆ˜ ํ•จ์ˆ˜์ด๋‹ค.

function NameBox(name) {
  return { fontWeight: 'bold', labelContent: name };
}
'Sebastian Markbรฅge' ->
{ fontWeight: 'bold', labelContent: 'Sebastian Markbรฅge' };

์ถ”์ƒ

ํ•˜๋‚˜์˜ ํ•จ์ˆ˜์— ๋ณต์žกํ•œ UI๋ฅผ ๋„ฃ์„ ์ˆ˜ ์—†๋‹ค. UI๋ฅผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์œผ๋กœ ์ถ”์ƒํ™”ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฉฐ, ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์€ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ๋ˆ„์„คํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋ฅผ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•œ๋‹ค.

function FancyUserBox(user) {
  return {
    borderStyle: '1px solid blue',
    childContent: [
      'Name: ',
      NameBox(user.firstName + ' ' + user.lastName)
    ]
  };
}
{ firstName: 'Sebastian', lastName: 'Markbรฅge' } ->
{
  borderStyle: '1px solid blue',
  childContent: [
    'Name: ',
    { fontWeight: 'bold', labelContent: 'Sebastian Markbรฅge' }
  ]
};

๊ตฌ์„ฑ

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

function FancyBox(children) {
  return {
    borderStyle: '1px solid blue',
    children: children
  };
}

function UserBox(user) {
  return FancyBox([
    'Name: ',
    NameBox(user.firstName + ' ' + user.lastName)
  ]);
}

์ƒํƒœ

UI๋Š” ๋‹จ์ˆœํžˆ ์„œ๋ฒ„์™€ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์˜ ์ƒํƒœ์— ๋Œ€ํ•œ ์‚ฌ๋ณธ์ด ์•„๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ •ํ™•ํ•œ ํˆฌ์˜๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ๋งŽ์ด ์žˆ์œผ๋ฉฐ, ๋‹ค๋ฅธ ํˆฌ์˜๊ณผ๋Š” ๊ด€๋ จ์ด ์—†๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ…์ŠคํŠธ ํ•„๋“œ์— ์ž…๋ ฅ์„ ํ•˜๋ฉด, ๋‹ค๋ฅธ ํƒญ์ด๋‚˜ ๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ์— ๋ณต์ œ๋˜๊ฑฐ๋‚˜ ๋ณต์ œ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์Šคํฌ๋กค ์œ„์น˜๋Š” ์—ฌ๋Ÿฌ ํˆฌ์˜ ์‚ฌ์ด์— ๊ฑฐ์˜ ๋ณต์ œ๋˜์ง€ ์•Š๋Š” ์ „ํ˜•์ ์ธ ์˜ˆ์ด๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด ๋ถˆ๋ณ€ํ•˜๊ธฐ๋ฅผ ์„ ํ˜ธํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋งจ ์œ„์— ์žˆ๋Š” ๋‹จ์ผ ์›์ž๋กœ์จ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์“ฐ๋ ˆ๋“œํ•œ๋‹ค.

function FancyNameBox(user, likes, onClick) {
  return FancyBox([
    'Name: ', NameBox(user.firstName + ' ' + user.lastName),
    'Likes: ', LikeBox(likes),
    LikeButton(onClick)
  ]);
}

// Implementation Details

var likes = 0;
function addOneMoreLike() {
  likes++;
  rerender();
}

// Init

FancyNameBox(
  { firstName: 'Sebastian', lastName: 'Markbรฅge' },
  likes,
  addOneMoreLike
);

์ฐธ๊ณ  : ์ด ์˜ˆ์ œ๋Š” ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์‹ค์ œ ๋ฆฌ์•กํŠธ์˜ ๋ชจ๋ธ์€ ์—…๋ฐ์ดํŠธ ๊ณผ์ •์—์„œ ๋‹ค์Œ ๋ฒ„์ „์˜ ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ๋ฏธ๋ž˜์— ์ด ์˜ˆ์ œ๋ฅผ ๋ฐ”๊พธ๊ณ ์ž ํ•œ๋‹ค.

๋ฉ”๋ชจ์ด์ œ์ด์…˜

์–ด๋–ค ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ˆ˜ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•„๋Š” ์ƒํƒœ์—์„œ ๊ทธ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๋‚ญ๋น„์ด๋‹ค. ๋งˆ์ง€๋ง‰ ์ธ์ž์™€ ๋งˆ์ง€๋ง‰ ๊ฒฐ๊ณผ๋ฅผ ์ถ”์ ํ•˜๋Š” ๋ฉ”๋ชจ์ด์ฆˆ๋œ ๋ฒ„์ „์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ™์€ ๊ฐ’์„ ๋„˜๊ฒจ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

function memoize(fn) {
  var cachedArg;
  var cachedResult;
  return function(arg) {
    if (cachedArg === arg) {
      return cachedResult;
    }
    cachedArg = arg;
    cachedResult = fn(arg);
    return cachedResult;
  };
}

var MemoizedNameBox = memoize(NameBox);

function NameAndAgeBox(user, currentTime) {
  return FancyBox([
    'Name: ',
    MemoizedNameBox(user.firstName + ' ' + user.lastName),
    'Age in milliseconds: ',
    currentTime - user.dateOfBirth
  ]);
}

์—ญ์ž ์ฃผ : ๋ฉ”๋ชจ์ด์ œ์ด์…˜์— ๋Œ€ํ•ด ์ž‘์„ฑํ•œ ๊ธ€์„ ๋ณด๋ฉด ๋” ์ž์„ธํžˆ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๋ฆฌ์ŠคํŠธ

๋Œ€๋ถ€๋ถ„์˜ UI๋Š” ๋ชฉ๋ก์— ์žˆ๋Š” ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋งŒ๋“œ๋Š” ์–ด๋–ค ํ˜•ํƒœ์˜ ๋ชฉ๋ก์ด๋‹ค. ์ด๊ฒƒ์€ ์ž์—ฐ์ ์ธ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค.

๋ชฉ๋ก์— ์žˆ๋Š” ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ • ํ•ญ๋ชฉ์˜ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” Map์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

function UserList(users, likesPerUser, updateUserLikes) {
  return users.map(user => FancyNameBox(
    user,
    likesPerUser.get(user.id),
    () => updateUserLikes(user.id, likesPerUser.get(user.id) + 1)
  ));
}

var likesPerUser = new Map();
function updateUserLikes(id, likeCount) {
  likesPerUser.set(id, likeCount);
  rerender();
}

UserList(data.users, likesPerUser, updateUserLikes);

์ฐธ๊ณ  : ์ด์ œ FancyNameBox์— ์ „๋‹ฌ๋˜๋Š” ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์ธ์ž๋“ค์ด ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์ธ์ž๋“ค๊ณผ ํ•จ๊ป˜ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋กœ ํ•˜์—ฌ๊ธˆ ๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ๊นจ์ง€๊ฒŒ ํ•˜๋Š”๋ฐ, ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๊ฐ’๋งŒ ๊ธฐ์–ตํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์•„๋ž˜์— ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์ด ํ›„์ˆ ๋œ๋‹ค.

์—ฐ์†์„ฑ

๋ถˆํ–‰ํžˆ๋„, UI ๋ชฉ๋ก์—๋Š” ๋„ˆ๋ฌด ๋งŽ์€ ๋ชฉ๋ก์ด ์žˆ์–ด์„œ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•ด์•ผํ•˜๋Š” ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง„๋‹ค.

ํ•จ์ˆ˜์˜ ์‹คํ–‰์„ ์—ฐ๊ธฐํ•จ์œผ๋กœ์จ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ์˜ ์ผ๋ถ€๋ฅผ ์ค‘์š” ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๋ฐ”๊นฅ์œผ๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Partial Application์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ๋‹ค์Œ, ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋กœ ๋ถ€ํ„ฐ ์ž์œ ๋กœ์›Œ์ง„ ํ•ต์‹ฌ ํ•จ์ˆ˜์˜ ์™ธ๋ถ€๋กœ๋ถ€ํ„ฐ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

์—ญ์ž ์ฃผ : ์› ๊ธ€์—์„œ๋Š” Partial Application์ด ์•„๋‹Œ Currying์ด๋ผ๊ณ  ๋˜์–ด์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ปค๋ง์ด๋ผ๋ฉด, box.children(likesPerUser)(updateUserLikes)๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค. ์ด ์™ธ์—๋„ bind ์— ๋Œ€ํ•œ ๋งํฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š”๋ฐ, ๋ณ„ ๊ด€๋ จ์„ฑ์ด ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ œ๊ฑฐํ•˜์˜€๋‹ค. ์ปค๋ง๊ณผ ํŒŒ์…œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฐจ์ด๋Š” Javascript- Currying VS Partial Application์—์„œ ๋” ์ž์„ธํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๊ฒƒ์€ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ค„์ด์ง„ ์•Š์ง€๋งŒ, ์ค‘์š”ํ•œ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ๋ฐ”๊นฅ์œผ๋กœ ๋ฒ—์–ด๋‚˜์•ผ ํ•œ๋‹ค.

function FancyUserList(users) {
  return FancyBox(
    UserList.bind(null, users)
  );
}

const box = FancyUserList(data.users);
const resolvedChildren = box.children(likesPerUser, updateUserLikes);
const resolvedBox = {
  ...box,
  children: resolvedChildren
};

์ƒํƒœ Map

์•ž์„œ ์šฐ๋ฆฌ๋Š” ๋ฐ˜๋ณต๋˜๋Š” ํŒจํ„ด์„ ๋ณผ ๋•Œ ๊ฐ™์€ ํŒจํ„ด์„ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•ˆ๋‹ค. ์ƒํƒœ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์ „๋‹ฌํ•˜๋Š” ๋กœ์ง์„ ์žฌ์‚ฌ์šฉ๋˜๋Š” ์ €์ˆ˜์ค€ ํ•จ์ˆ˜๋กœ ์˜ฎ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

function FancyBoxWithState(
  children,
  stateMap,
  updateState
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState
    ))
  );
}

function UserList(users) {
  return users.map(user => ({
    continuation: FancyNameBox.bind(null, user),
    key: user.id
  }));
}

function FancyUserList(users) {
  return FancyBoxWithState.bind(null,
    UserList(users)
  );
}

const continuation = FancyUserList(data.users);
continuation(likesPerUser, updateUserLikes);

๋ฉ”๋ชจ์ด์ œ์ด์…˜ Map

๋ชฉ๋ก์— ์žˆ๋Š” ์—ฌ๋Ÿฌ ํ•ญ๋ณต์„ ๋ฉ”๋ชจ์ด์ฆˆํ•˜๋Š” ๊ฒƒ์€ ์ƒ๋‹นํžˆ ์–ด๋ ต๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๊ณผ ๋นˆ๋„ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๋งž์ถ”๋Š” ๋ณต์žกํ•œ ์บ์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค.

๋‹คํ–‰ํžˆ๋„, UI๋Š” ๋™์ผํ•œ ์œ„์น˜์—์„œ ์•ˆ์ •๋˜๋ ค๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค. ํŠธ๋ฆฌ์˜ ๊ฐ™์€ ์œ„์น˜๋Š” ํ•ญ์ƒ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๋ฉฐ, ์ด ํŠธ๋ฆฌ๋Š” ๋ฉ”๋ชจ์ด์ œ์ด์…˜์— ์œ ์šฉํ•œ ์ „๋žต์ž„์ด ๋ฐํ˜€์กŒ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ƒํƒœ์— ์‚ฌ์šฉํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋™์ผํ•œ ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ตฌ์„ฑ ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ์บ์‹œ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

function memoize(fn) {
  return function(arg, memoizationCache) {
    if (memoizationCache.arg === arg) {
      return memoizationCache.result;
    }
    const result = fn(arg);
    memoizationCache.arg = arg;
    memoizationCache.result = result;
    return result;
  };
}

function FancyBoxWithState(
  children,
  stateMap,
  updateState,
  memoizationCache
) {
  return FancyBox(
    children.map(child => child.continuation(
      stateMap.get(child.key),
      updateState,
      memoizationCache.get(child.key)
    ))
  );
}

const MemoizedFancyNameBox = memoize(FancyNameBox);

๋Œ€์ˆ˜ํ•™ ํšจ๊ณผ

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

์—ญ์ž ์ฃผ : PITA์˜ ๋œป์ด ๏ฟฝ๏ฟฝ๏ฟฝ์ง€ ์ฐพ์•„๋ดค๋Š”๋ฐ, ์•Œ์•„๋‚ด์ง€ ๋ชปํ–ˆ๋‹ค. ์›๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
It turns out that it is kind of a PITA to pass every little value you might need through several levels of abstractions.

๋•Œ๋กœ๋Š” ๋ฐ์ดํ„ฐ ์ข…์†์„ฑ์ด ์ถ”์ƒํ™” ํŠธ๋ฆฌ๋ฅผ ์™„์ „ํžˆ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ ˆ์ด์•„์›ƒ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ํ•˜์œ„์˜ ํฌ๊ธฐ๋ฅผ ์•Œ์•„์•ผ ๊ทธ๋“ค์˜ ์œ„์น˜๋ฅผ ์™„์ „ํ•˜๊ฒŒ ์ดํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ, ์ด ์˜ˆ์ œ๋Š” ์กฐ๊ธˆ ๋ฐ”๊นฅ์— ์žˆ๋‹ค. ECMAScript์— ์ œ์•ˆ๋œ ๋Œ€์ˆ˜ํ•™ ํšจ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค. ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์ต์ˆ™ํ•˜๋‹ค๋ฉด ๋ชจ๋‚˜๋“œ์— ์˜ํ•ด ๋ถ€๊ณผ๋œ ์ค‘๊ฐ„ ์‹์„ ํ”ผํ•  ๊ฒƒ์ด๋‹ค.

function ThemeBorderColorRequest() { }

function FancyBox(children) {
  const color = raise new ThemeBorderColorRequest();
  return {
    borderWidth: '1px',
    borderColor: color,
    children: children
  };
}

function BlueTheme(children) {
  return try {
    children();
  } catch effect ThemeBorderColorRequest -> [, continuation] {
    continuation('blue');
  }
}

function App(data) {
  return BlueTheme(
    FancyUserList.bind(null, data.users)
  );
}