Ember.js: [ํ€˜์ŠคํŠธ] Ember์˜ ๊ธ€๋ฆฌ๋จธ ๊ตฌ์„ฑํ’ˆ

์— ๋งŒ๋“  2018๋…„ 02์›” 28์ผ  ยท  23์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: emberjs/ember.js

์ด ํ€˜์ŠคํŠธ ๋ฌธ์ œ๋Š” Ember.js์—์„œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ตฌํ˜„์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

๊ณ„ํš

Glimmer.js ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. "์™ธ๋ถ€ HTML" ํ…œํ”Œ๋ฆฟ( tagName , attributeBindings ๋“ฑ ์—†์Œ)
  2. ํ…œํ”Œ๋ฆฟ์˜ ์ธ์ˆ˜๋Š” {{@firstName}} ์™€ ๊ฐ™์ด @ ์ ‘๋‘์‚ฌ์ž…๋‹ˆ๋‹ค.
  3. ๊ตฌ์„ฑ ์š”์†Œ์— ์ธ์ˆ˜๊ฐ€ this.args ๋กœ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  4. ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค๋Š” JavaScript ํด๋ž˜์Šค ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์ƒํƒœ๋Š” @tracked ์†์„ฑ์œผ๋กœ ์ฃผ์„ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.
  6. ๊ตฌ์„ฑ ์š”์†Œ๋Š” <AngleBracket /> ๊ตฌ๋ฌธ์„ ํ†ตํ•ด ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  7. โ€ฆattributes ๋ฅผ ํ†ตํ•ด ์†์„ฑ์„ "์Šคํ”Œ๋ž˜ํŒ…"ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Ember์˜ ์ฆ๋ถ„์ฃผ์˜ ์ •์‹ ์— ๋”ฐ๋ผ ์šฐ๋ฆฌ๋Š” ์ด ๊ธฐ๋Šฅ์„ ์• ๋“œ์˜จ์„ ํ†ตํ•ด ํ•˜๋‚˜์”ฉ ๋„์ž…ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ํ”„๋กœ์„ธ์Šค ์ดˆ๊ธฐ์— ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค, ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ Ember์—์„œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๊ฐ€๋Š” ๊ธธ์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ ๋‘ ๊ธฐ๋Šฅ์€ ์ด๋ฏธ ์ฐฉ๋ฅ™ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ํ…œํ”Œ๋ฆฟ ์ „์šฉ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํ…œํ”Œ๋ฆฟ์€ "์™ธ๋ถ€ HTML"์ž…๋‹ˆ๋‹ค( template-only-glimmer-components ์„ ํƒ์  ๊ธฐ๋Šฅ ์ด ํ™œ์„ฑํ™”๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •).
  2. @ ์ ‘๋‘์‚ฌ(์˜ˆ: {{@firstName}} )๋ฅผ ํ†ตํ•ด ํ…œํ”Œ๋ฆฟ์—์„œ ์ธ์ˆ˜์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํ˜ธ์—์„œ๋Š” ์• ๋“œ์˜จ์ด ๋Œ€์ฒด ๊ตฌ์„ฑ ์š”์†Œ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋„๋ก ํ—ˆ์šฉํ•œ ๋‹ค์Œ @glimmer/component ํŒจํ‚ค์ง€๋ฅผ Glimmer.js ๊ตฌ์„ฑ ์š”์†Œ API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” Ember ์• ๋“œ์˜จ์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Glimmer ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ Ember๋กœ ๊ฐ€์ ธ์˜ค๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ์™„๋ฃŒํ•˜๋Š” ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ทธ ์ž‘์—…์„ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆŒ ๊ฒƒ์ด๋ฉฐ, ๊ฐ๊ฐ์€ ๊ธฐ์กด Ember ์•ฑ๊ณผ ์• ๋“œ์˜จ์˜ ์ด์ ์„ ์ž ๊ธˆ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค. 0๋‹จ๊ณ„๋Š” ๋Œ€์ฒด ๊ตฌ์„ฑ ์š”์†Œ ๊ตฌํ˜„์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด Ember.js์— ํ•„์š”ํ•œ ๊ธฐ๋ณธ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 1, 2, 3๋‹จ๊ณ„๋Š” Glimmer.js ๊ตฌ์„ฑ ์š”์†Œ API๋ฅผ ์ ์ง„์ ์œผ๋กœ ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

0๋‹จ๊ณ„์™€ 1๋‹จ๊ณ„์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋Š” ๋™์•ˆ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๊ฐ€ ์™„๋ฃŒ์— ๊ฐ€๊นŒ์›Œ์งˆ ๋•Œ๊นŒ์ง€ ์ดํ›„ ๋‹จ๊ณ„์˜ ๊ธฐ์ˆ ์ ์ธ ์„ธ๋ถ€ ์ •๋ณด ํƒ์ƒ‰์„ ์—ฐ๊ธฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

0๋‹จ๊ณ„: ๊ตฌ์„ฑ ์š”์†Œ ๋™์ž‘ ์‚ฌ์šฉ์ž ์ง€์ •

TL;DR: Ember.js์— CustomComponentManager API๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์• ๋“œ์˜จ์ด ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ API๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

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

"์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๋™์ž‘"์ด๋ผ๊ณ  ํ•  ๋•Œ ๊ตฌ์ฒด์ ์œผ๋กœ ๋‹ค์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  2. ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค๊ฐ€ ํŒŒ๊ดด๋˜๋Š” ๋ฐฉ๋ฒ•.
  3. ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค์— ์ธ์ˆ˜๊ฐ€ ์ œ๊ณต๋˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  4. ์ด๋Ÿฌํ•œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ตฌ์„ฑ ์š”์†Œ์— ์•Œ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

Glimmer VM์€ ์ด๋Ÿฌํ•œ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๋Š” ๊ฐœ์ฒด์ธ "๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž"์˜ ๊ฐœ๋…์„ ๋„์ž…ํ•˜์ง€๋งŒ ์ด API๋Š” ๋งค์šฐ ๋‚ฎ์€ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค. ์ž‘์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ณ  ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์†์ƒ์‹œํ‚ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๊ธฐ ์‰ฝ๊ณ  ์•„์ง ์•ˆ์ •์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Ember์—์„œ ๊ณต๊ฐœ API๋กœ ์ง์ ‘ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ธฐ์ƒ์กฐ์ž…๋‹ˆ๋‹ค.

๋Œ€์‹ ์— ๋Œ€๋ฆฌ์ž ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๋Š” CustomComponentManager ๋ผ๋Š” ์ƒˆ๋กœ์šด Ember API๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. CustomComponentManager ๋Š” ์™„์ „ํ•œ ComponentManager Glimmer VM API๋ณด๋‹ค ๋” ์ž‘์€ API ๋…ธ์ถœ ์˜์—ญ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์• ๋“œ์˜จ ์ž‘์„ฑ์ž๊ฐ€ "์„ฑ๊ณต์˜ ๊ตฌ๋ฉ์ด"์— ๋น ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด Ember๋Š” ์ฃผ์–ด์ง„ ๊ตฌ์„ฑ ์š”์†Œ์— ์‚ฌ์šฉํ•  ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? Custom Components RFC ์˜ ์›๋ž˜ ๋ฐ˜๋ณต์—์„œ๋Š” Ember์— ์—ด์‹ฌํžˆ ๋“ฑ๋กํ•˜๊ณ  ์‚ฌ์šฉํ•  ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์ธ ComponentDefinition ๊ฐœ๋…์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

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

์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž ๊ฒ€์ƒ‰

์ด ๋ฐ˜๋ณต์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๋Œ€์ฒด ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Ember์—์„œ ๋‚ด๋ณด๋‚ธ ํŠน์ˆ˜ componentManager ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋Ÿฐํƒ€์ž„ ์‹œ ํŠน์ • ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค์— ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž์— ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

import { componentManager } from '@ember/custom-component-manager';
import EmberObject from '@ember/object';

export default componentManager(EmberObject.extend({
  // ...
}), 'glimmer');

๊ฒฐ๊ตญ ์ด๊ฒƒ์€ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { componentManager } from '@ember/custom-component-manager';

export default @componentManager('glimmer') class {
  // ...
}

์ด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ฒ˜์Œ ํ˜ธ์ถœ๋  ๋•Œ Ember๋Š” ํด๋ž˜์Šค๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž ์ฃผ์„์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋ฌธ์ž์—ด ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํ…Œ์ด๋„ˆ์— ๋Œ€ํ•œ ์กฐํšŒ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์—์„œ Ember๋Š” ์ปจํ…Œ์ด๋„ˆ ํ‚ค๊ฐ€ component-manager:glimmer ๊ฐœ์ฒด์— ๋Œ€ํ•ด ์ปจํ…Œ์ด๋„ˆ์— ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์• ๋“œ์˜จ์€ ์ผ๋ฐ˜ ํ•ด์ƒ๋„ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ Glimmer ๊ตฌ์„ฑ ์š”์†Œ ์• ๋“œ์˜จ์€ addon/component-managers/glimmer.js ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋Š” ์ผ๋ฐ˜ ํ•ด๊ฒฐ ๊ทœ์น™์„ ํ†ตํ•ด ์ž๋™์œผ๋กœ ๊ฒ€์ƒ‰๋ฉ๋‹ˆ๋‹ค.

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

// addon/index.js
import EmberObject from '@ember/object';
import { componentManager } from '@ember/custom-component-manager';

export default componentManager(EmberObject.extend({
  // ...
}), 'turbo');

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

import TurboComponent from 'turbo-component';

export default TurboComponent.extend({
  didInsertElementQuickly() {
    // ...
  }
});

์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ API

์–ด๋–ค ๊ตฌ์„ฑ ์š”์†Œ๋„ ์„ฌ์ด ์•„๋‹ˆ๋ฉฐ ํ•˜์œ„ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ์ƒˆ ๊ตฌ์„ฑ ์š”์†Œ API์˜ ๋„์ž…์œผ๋กœ ์ธํ•ด ๊ธฐ์กด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์†์ƒ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ํ•œ ๊ฐ€์ง€ ์˜ˆ๋Š” ๊ธฐ์กด ๋ณด๊ธฐ ๊ณ„์ธต ๊ตฌ์กฐ API์ž…๋‹ˆ๋‹ค. Ember ๊ตฌ์„ฑ ์š”์†Œ๋Š” parentView ์†์„ฑ์„ ํ†ตํ•ด ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถ€๋ชจ๊ฐ€ Ember.Component ๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ ์ž์‹ Ember ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” ์—ฌ์ „ํžˆ null์ด ์•„๋‹Œ parentView ์†์„ฑ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ Ember์˜ CurlyComponentManager ๋Š” ์ด ์ƒํƒœ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ž‘์—… ๋Œ€์ƒ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์ฃผ๋ณ€ "๋ฒ”์œ„ ์ƒํƒœ"๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

import CustomComponentManager from "@ember/custom-component-manager";

export default new CustomComponentManager({
  // major and minor Ember version this manager targets
  version: "3.1",
  create({ ComponentClass, args }) {
    // Responsible for instantiating the component class and passing provided
    // component arguments.
    // The value returned here is passed as `component` in the below hooks.
  },
  getContext(component) {
    // Returns the object that serves as the root scope of the component template.
    // Most implementations should return `component`, so the component's properties
    // are looked up in curly expressions.
  },
  update(component, args) {
    // Called whenever the arguments to a component change.
  },
  destroy(component) {
  }
});

1๋‹จ๊ณ„: Ember Object Glimmer ๊ตฌ์„ฑ ์š”์†Œ

Ember์˜ Component ๊ธฐ๋ณธ ํด๋ž˜์Šค๋Š” ๋” ์ด์ƒ ๋งŽ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ธด ๊ธฐ๋Šฅ ๋ชฉ๋ก์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋„ ์„ฑ๋Šฅ ๋น„์šฉ์„ ๋ถ€๊ณผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋กœ @glimmer/component ํŒจํ‚ค์ง€๋ฅผ ํ†ตํ•ด ๊ฐ„์†Œํ™”๋œ Glimmer.js ๊ตฌ์„ฑ ์š”์†Œ API๋ฅผ ์„ ํƒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‰ฝ๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด, ์šฐ๋ฆฌ๋Š” ํฌ๋ฏธํ•œ ๋น›์˜ ๊ตฌํ˜„์„ ์ œ๊ณต ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค Component ๊ธฐ๋ณธ ํด๋ž˜์Šค์™€๋Š” ์ƒ์† Ember.Object ์—์„œ @glimmer/component/compat .

๋‹ค์Œ์€ "Ember-Glimmer ๊ตฌ์„ฑ ์š”์†Œ"๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€์— ๋Œ€ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

// src/ui/components/user-profile/component.js
import Component from '@glimmer/component/compat';
import { computed } from '@ember/object';

export default Component({
  fullName: computed('args.firstName', 'args.lastName', function() {
    let { firstName, lastName } = this.args
    return `${firstName} ${lastName}`;
  })

  isAdmin: false,

  toggleAdmin() {
    this.set('isAdmin', !this.isAdmin);
  }
});
{{!-- src/ui/components/user-profile/template.hbs --}}
<h1>{{fullName}}</h1>
<p>
  Welcome back, {{@firstName}}!
  {{#if isAdmin}}
    <strong>You are an admin.</strong>
  {{/if}}
</p>
<button {{action toggleAdmin}}>Toggle Admin Status</button>

์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ฃผ๋ชฉํ• ๋งŒํ•œ ํŠน์„ฑ:

  • ํ…œํ”Œ๋ฆฟ์€ ์™ธ๋ถ€ HTML ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ ํ…œํ”Œ๋ฆฟ์—๋Š” ๋‹จ์ผ ๋ฃจํŠธ ์š”์†Œ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— "ํƒœ๊ทธ ์—†๋Š” ๊ตฌ์„ฑ ์š”์†Œ"๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
  • ์ž‘์—…์€ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋ฟ์ด๋ฉฐ actions ํ•ด์‹œ์— ์ค‘์ฒฉ๋  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ๊ตฌ์„ฑ ์š”์†Œ์˜ ๊ฐœ๋ณ„ ์†์„ฑ์„ ์ง์ ‘ ์„ค์ •ํ•˜๋Š” ๋Œ€์‹  args ์†์„ฑ์— ์ธ์ˆ˜๊ฐ€ ์„ค์ • ๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋“ค์€ Ember ๊ฐœ์ฒด ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค . ์ด๋Š” Ember ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ด๋ฏธ ์นœ์ˆ™ํ•œ ๊ณ„์‚ฐ ์†์„ฑ ๋ฐ ๋ฏน์Šค์ธ๊ณผ ๊ฐ™์€ ๋„๊ตฌ๊ฐ€ ๊ณ„์† ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํฌํ•จ ๋˜์ง€ ์•Š์€ ํ•ญ๋ชฉ ๋„ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

  • @tracked ์†์„ฑ์€ 3๋‹จ๊ณ„๊นŒ์ง€ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ตฌ์„ฑ ์š”์†Œ์— layout ๋˜๋Š” template ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • childViews , parentView , nearestWithProperty ๋“ฑ๊ณผ ๊ฐ™์€ ๋ทฐ ๊ณ„์ธต ๊ตฌ์กฐ์™€ ๊ด€๋ จ๋œ ๋ฉ”์„œ๋“œ ๋˜๋Š” ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ๋ฃจํŠธ ์š”์†Œ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•œ tagName , attributeBindings ๋˜๋Š” ๊ธฐํƒ€ ์‚ฌ์šฉ์ž ์ •์˜ JavaScript DSL์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฒคํŠธ ๋””์ŠคํŒจ์น˜์— send ๋˜๋Š” sendAction ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ํ•„์ˆ˜ ember-view ํด๋ž˜์Šค ๋˜๋Š” ์ž๋™ ์ƒ์„ฑ๋œ guid ์š”์†Œ ID๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ˆ˜๋™ rerender() ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.
  • attrs ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค(๋Œ€์‹  args ์‚ฌ์šฉ).
  • ์ „๋‹ฌ๋œ ์ธ์ˆ˜๋Š” "๋‹จ๋ฐฉํ–ฅ"์ด๋ฉฐ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์„ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ „๋‹ฌ๋œ ์ธ์ˆ˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ ์ธ์Šคํ„ด์Šค์˜ ์†์„ฑ์œผ๋กœ ์„ค์ •๋˜์ง€ ์•Š์•„ ๋””๋ฒ„๊ทธํ•˜๊ธฐ ์–ด๋ ค์šด ์ด๋ฆ„ ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ตฌ์„ฑ ์š”์†Œ ์š”์†Œ์— ๋Œ€ํ•œ jQuery ๊ฐœ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ this.$() ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • DOM์— ์ˆ˜๋™ appendTo ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋‹ค์Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ด๋ฒคํŠธ๋Š” ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    • willInsertElement

    • didRender

    • willRender

    • willClearRender

    • willUpdate

    • didReceiveAttrs

    • didUpdateAttrs

    • parentViewDidChange

  • ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ on() ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ›„ํฌ๋Š” ๋ฉ”์„œ๋“œ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ ์„ธํŠธ์˜ ํฅ๋ฏธ๋กœ์šด ๋ถ€์ž‘์šฉ ์ค‘ ํ•˜๋‚˜๋Š” JavaScript ํด๋ž˜์Šค ๋ฅผ ES Classes RFC ์—์„œ ์ œ์•ˆ๋œ ์„ค๊ณ„์™€ ํ•จ๊ป˜ ์œ„ ๊ตฌ์„ฑ ์š”์†Œ์˜ ๋Œ€์ฒด ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// src/ui/components/user-profile/component.js
import Component from '@glimmer/component/compat';
import { computed } from 'ember-decorators/object';

export default class extends Component {
  isAdmin = false;

  @computed('args.firstName', 'args.lastName')
  get fullName() {
    let { firstName, lastName } = this.args;
    return `${firstName} ${lastName}`;
  })

  toggleAdmin() {
    this.set('isAdmin', !this.isAdmin);
  }
});

2๋‹จ๊ณ„ - ์•ต๊ธ€ ๋ธŒ๋ž˜ํ‚ท ๊ตฌ๋ฌธ

2 ๋‹จ๊ณ„ (๊ฐ๊ด„ํ˜ธ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ˜ธ์ถœ ๊ฐ€๋Šฅ <UserAvatar @user={{currentUser}} /> (์ค‘๊ด„ํ˜ธ ์ด์™ธ์—) {{my-component user=currentUser}} ). ์ด ๊ตฌ๋ฌธ์€ ๊ตฌ์„ฑ ์š”์†Œ ์ธ์ˆ˜์™€ HTML ์†์„ฑ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด โ€ฆattributes ๋ฅผ ํ†ตํ•ด ์†์„ฑ์„ ๊ตฌ์„ฑ ์š”์†Œ ํ…œํ”Œ๋ฆฟ์— "๋ถ„ํ• "ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

{{! src/ui/components/UserAvatar/template.hbs }}
<div ...attributes> {{! <-- attributes will be inserted here }}
  <h1>Hello, {{@firstName}}!</h1>
</div>
<UserAvatar @user={{currentUser}} aria-expanded={{isExpanded}} />

๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•œ ์ถœ๋ ฅ์ด ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

<div aria-expanded="true">
  <h1>Hello, Steven!</h1>
</div>

3๋‹จ๊ณ„ - ์ถ”์ ๋œ ์†์„ฑ

3๋‹จ๊ณ„์—์„œ๋Š” Ember์˜ @tracked ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ์ถ”์ ๋œ ์†์„ฑ์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. Ember์˜ ๊ฐœ์ฒด ๋ชจ๋ธ๊ณผ ์ถ”์ ๋œ ์†์„ฑ ๊ฐ„์˜ ์ƒํ˜ธ ์šด์šฉ์„ฑ์— ๋Œ€ํ•œ ์„ธ๋ถ€ ์‚ฌํ•ญ์€ ์ž‘์—… ์ค‘์ž…๋‹ˆ๋‹ค. ์ถ”์ ๋œ ์†์„ฑ์ด ํ‘œ์‹œ๋˜๋ฉด ์‚ฌ์šฉ์ž๋Š” @glimmer/component/compat ๋ชจ๋“ˆ์„ ์‚ญ์ œํ•˜๊ณ  Ember.Object๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ๊ตฌ์„ฑ ์š”์†Œ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

import Component, { tracked } from '@glimmer/component';

export default class extends Component {
  <strong i="24">@tracked</strong> isAdmin = false;

  <strong i="25">@tracked</strong> get fullName() {
    let { firstName, lastName } = this.args;
    return `${firstName} ${lastName}`;
  }

  toggleAdmin() {
    this.isAdmin = !this.isAdmin;
  }
}

Q&A

๊ธฐ์กด CSS์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ember-view ํด๋ž˜์Šค ์ด๋ฆ„ ๋˜๋Š” ์ž๋™ ์ƒ์„ฑ๋œ id ์†์„ฑ๊ณผ ๊ฐ™์€ ํ•ญ๋ชฉ์„ Glimmer ๊ตฌ์„ฑ ์š”์†Œ์— ๋‹ค์‹œ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ. ์˜ˆ์‹œ:

<div class="ember-view" id="{{uniqueId}}">
  Component content goes here.
</div>
import Component from '@glimmer/component';
import { guidFor } from '@ember/object/internals';

export default class extends Component {
  get uniqueId() {
    return guidFor(this);
  }
}

์ž์›

์ž‘์—…

์•„๋ž˜ ๋ชฉ๋ก์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง„ํ–‰ ์ค‘์ธ ์ž‘์—…์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„ํ•˜๋Š” ๋™์•ˆ ๋” ๋งŽ์ด ๋ฐฐ์šฐ๋ฉด ๋ชฉ๋ก์— ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž API

  • [x] ์œ„์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋„๋ก ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ RFC ์—…๋ฐ์ดํŠธ(@chancancode)
  • [x] glimmer-custom-component-manager ๊ธฐ๋Šฅ ํ”Œ๋ž˜๊ทธ ์ถ”๊ฐ€
  • [x] componentManager ๊ธฐ๋Šฅ ๊ตฌํ˜„

    • [x] { componentManager } from '@ember/custom-component-manager' ๋กœ ๋…ธ์ถœ

  • [x] ํ•ด์„๊ธฐ๋Š” ์ฃผ์„์ด ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ๊ฐ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • [x] ๋ฆฌ์กธ๋ฒ„๋Š” ์ง€์ •๋œ ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ์กฐํšŒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    • [ ] ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์–ด๋””์— ๋‘˜ ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์• ๋“œ์˜จ ์ž‘์„ฑ์ž๋ฅผ ์œ„ํ•œ ์ง€์นจ

    • [ ] ์ด๊ฒƒ์€ ๋ชจ๋“ˆ ํ†ตํ•ฉ๊ณผ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ? (@mixonic)

  • [x] CustomComponentManager API ๊ตฌํ˜„

    • [x] CustomComponentManagerDelegate ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜

    • [x] version

    • [x] create()

    • [x] getContext()

    • [x] update()

    • [x] destroy?()

    • [x] didCreate?()

    • [x] didUpdate?()

    • [x] getView?()

    • [x] ์ƒ์„ฑ ์‹œ version ์†์„ฑ ํ™•์ธ

    • [x] ๋‚ด๋ถ€

    • [x] ๊ธฐ์กด ๊ตฌ์„ฑ ์š”์†Œ์—์„œ childViews ๋ฐ parentView

    • [ ] ๋ Œ๋”๋ง ์„ฑ๋Šฅ์„ ์œ„ํ•œ ๋„๊ตฌ

    • [ ] Ember Inspector์™€์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•œ ๋„๊ตฌ

๊ธ€๋ฆฌ๋จธ ์ปดํฌ๋„ŒํŠธ ์• ๋“œ์˜จ

  • [x] sparkles-components ์• ๋“œ์˜จ ์‚ฌ์šฉ ์ง€์›

    • [x] ๊ธฐ๋ณธ ํด๋ž˜์Šค๋Š” Ember์—์„œ ์‚ฌ์šฉํ•  ๋•Œ componentManager ์ฃผ์„์„ ๊ฐ€์ ธ์™€ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    • [x] CustomComponentManager ๊ตฌํ˜„์€ Ember์˜ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • [ ] @glimmer/component ๋ฅผ Ember ์• ๋“œ์˜จ์œผ๋กœ ์‚ฌ์šฉ ์ง€์›

    • [ ] Glimmer.js์—์„œ ์‚ฌ์šฉํ•  ๋•Œ ๊ธฐ์กด ๋™์ž‘ ์œ ์ง€

    • [ ] import Component from '@glimmer/component' ๋Š” ์ผ๋ฐ˜ JavaScript ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

    • [ ] import Component from '@glimmer/component/compat' ๋Š” Ember.Object ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

      ์กฐํšŒ

  • [ ] ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ

    • [x] ์ •์  create(injections)

    • [x] didInsertElement()

    • [x] willDestroy()

    • [x] didUpdate()

    • [x] ์ด๋ฒคํŠธ ์œ„์ž„ ํ˜ธ์ถœ ๋ฉ”์„œ๋“œ( click() ๋“ฑ)๋Š” ํŠธ๋ฆฌ๊ฑฐ ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • [ ] ์š”์†Œ ์•ก์„ธ์Šค

    • [ ] this.bounds

    • [ ] this.element ๊ณ„์‚ฐ๋œ ์†์„ฑ ๋ณ„์นญ์„ this.bounds

    • [ ] ์š”์†Œ ๋…ธ์ถœ์„ ์œ„ํ•œ ์š”์†Œ ์ˆ˜์ •์ž ๊ธฐ๋ฐ˜ API

  • [ ] ์ธ์ˆ˜

    • [x] this.args ๋Š” ์ƒ์„ฑ์ž์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    • [x] this.args didUpdate ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— this.args ๊ฐ€ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค.

    • [ ] this.args ๋Š” ๋ฌดํ•œ ์žฌ๋ Œ๋”๋ง ์ฃผ๊ธฐ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค(ํ™•์ธ ํ•„์š”).

  • [ ] ๋ฌธ์„œ

    • [ ] ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•

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

    • [ ] ์นด๋‚˜๋ฆฌ์•„ ์ „์šฉ

    • [ ] 1.0 ์ด์ „

    • [ ] Ember-Glimmer "ํ˜ธํ™˜" ๊ตฌ์„ฑ ์š”์†Œ

    • [ ] ์™ธ๋ถ€ HTML ํ…œํ”Œ๋ฆฟ

    • [ ] ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ

    • [ ] ๊ณ„์‚ฐ๋œ ์†์„ฑ ์ •์˜



      • [ ] args ์— ์˜์กดํ•˜๋Š” ๋ฐฉ๋ฒ•



    • [ ] ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ / Glimmer ๊ตฌ์„ฑ ์š”์†Œโ€ฆ

    • ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ต์ˆ™ํ•œ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ํšจ๊ณผ์ ์ธ Glimmer ๊ตฌ์„ฑ ์š”์†Œ ์ž‘์„ฑ ๊ฐ€์ด๋“œ

    • [ ] Ember ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ

    • [ ] React ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ

    • [ ] Angular ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ

    • [ ] COBOL ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ Glimmer ๊ตฌ์„ฑ ์š”์†Œ

์—ด๋ฆฐ ์งˆ๋ฌธ

  1. ์ž‘์—…์— ๋Œ€ํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ์ด ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๊ฐ€ ์—ฐ๊ฒฐ๋˜๋„๋ก ํ—ˆ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ?
  2. ๊ธฐ๋ณธ JavaScript ํด๋ž˜์Šค(์ •์  create() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ํด๋ž˜์Šค)๋ฅผ ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค๋กœ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ? ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์€ ๊ฐ„๋‹จํ•ด ๋ณด์ด์ง€๋งŒ ์˜์™ธ๋กœ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค.
  3. CustomComponentManager ์™€ ๊ฐ™์€ "์• ๋“œ์˜จ API"๋ฅผ ๋ฌธ์„œํ™”ํ•˜๊ธฐ์— ๊ฐ€์žฅ ์ข‹์€ ์œ„์น˜๋Š” ์–ด๋””์ž…๋‹ˆ๊นŒ?
  4. CustomComponentManager ๋ฒ„์ „ ๊ด€๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๊นŒ?

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@dbbk ์šฐ๋ฆฌ๊ฐ€ {{...attributes}} ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์šฐ๋ฆฌ๊ฐ€ curlies๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๋‹ค๋ฅธ ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์ผ๋ฐ˜ ์†์„ฑ๊ณผ ๊ตฌ๋ฌธ์ ์œผ๋กœ ๋ชจํ˜ธํ•˜์ง€ ์•Š๊ณ  4๊ฐœ์˜ ์ ์€ ๋ฌธ์ž๊ฐ€ ํƒ€์ดํ•‘ํ•˜๊ธฐ ์‰ฝ๊ณ  ์‹œ๊ฐ์ ์œผ๋กœ ๋œ ์‹œ๋„๋Ÿฝ๊ฒŒ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์‚ฌ๋žŒ๋“ค์ด attributes ๊ฐ€ ๋ฒ”์œ„ ๋‚ด ์†์„ฑ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•ด๋‹น ๊ตฌ๋ฌธ์—์„œ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ <SomeComponent something={{attributes}} /> ์ˆ˜ํ–‰ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์Šคํ”„๋ ˆ๋“œ ๊ตฌ๋ฌธ์ด ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๋•Œ ๋‹ค๋ฅธ ์œ„์น˜์—์„œ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์•”์‹œํ•ฉ๋‹ˆ๋‹ค.

@arguments ๋ฅผ ๋ชจ๋‘ ํŠน์ˆ˜ ํ…œํ”Œ๋ฆฟ ๋ฐ”์ธ๋”ฉ์œผ๋กœ ์ฑ„ํƒํ•˜๊ณ  ํ•ธ๋“ค๋ฐ”์— ... ์Šคํ”„๋ ˆ๋“œ ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•˜์ž๋Š” ์ œ์•ˆ์ด ์žˆ์—ˆ์ง€๋งŒ ์ฆ‰๊ฐ์ ์ธ ๋กœ๋“œ๋งต์— ์—†๋Š” ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์— ...attributes ๋ฅผ {{...@attributes}} ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์ „ํ˜€ ๋†€๋ผ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Gaurav0 Glimmer ๊ตฌ์„ฑ ์š”์†Œ API๋Š” Ember ์•ฑ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜๊ธฐ ์ „์— RFC ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž ์ ‘๊ทผ ๋ฐฉ์‹์˜ ํ•œ ๊ฐ€์ง€ ์ข‹์€ ์ ์€ "์ฐจ์„ธ๋Œ€" API๋ฅผ ์ •์‹ํ™”ํ•˜์ง€ ์•Š์ง€๋งŒ ์• ๋“œ์˜จ ์—์ฝ”์‹œ์Šคํ…œ์„ ํ†ตํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ๋””์ž์ธ์ด ์žฅ์ ์„ ๋†“๊ณ  ๊ฒฝ์Ÿํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Turbo87 ์ข‹์€ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํŒจํ„ด๊ณผ ์ƒˆ๋กœ์šด API๋กœ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

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

๋Œ€์‹ :

import Component from "@ember/component";
import { computed } from "@ember/object";

export default Component.extend({
  didReceiveAttrs() {
    this.set('firstName', this.attrs.firstName || 'Tobias');
    this.set('lastName', this.attrs.lastName || 'Bieniek');
  },

  fullName: computed('firstName', 'lastName', function() {
    return `${this.firstName} ${this.lastName}`;
  })
});

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰:

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  <strong i="27">@tracked</strong> get firstName() {
    return this.args.firstName || 'Tobias';
  }

  <strong i="28">@tracked</strong> get lastName() {
    return this.args.lastName || 'Bieniek';
  }

  <strong i="29">@tracked</strong> get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

์ฒ˜์Œ์—๋Š” ์ด์— ๋Œ€ํ•ด ํšŒ์˜์ ์ด์—ˆ์ง€๋งŒ @wycats ๊ฐ€ ์ €๋ฅผ ์„ค๋“ํ–ˆ๊ณ  ์ง€๋‚œ 1๋…„ ๋™์•ˆ ํฐ Glimmer.js ์•ฑ์„ ๊ตฌ์ถ•ํ•œ ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด didReceiveAttrs ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋งŒ๋‚œ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋” ํšจ์œจ์ ์ธ ๊ณ„์‚ฐ ์†์„ฑ์œผ๋กœ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  23 ๋Œ“๊ธ€

๋„์›€์ด ํ•„์š”ํ•˜์‹œ๋ฉด Ember ์ปค๋ฎค๋‹ˆํ‹ฐ Slack ์˜ #st-glimmer-components ์ฑ„๋„์—์„œ ์ž‘์—…์„ ์กฐ์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค! ์†Œ์‹œ์ง€๊ฐ€ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋Š”์ง€ ๊ถ๊ธˆํ•˜๋‹ค๋ฉด Lurkers๋„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ๊ณ ๋ คํ•˜๋ฉด;

{{! src/ui/components/UserAvatar/template.hbs }}
<div ...attributes> {{! <-- attributes will be inserted here }}
  <h1>Hello, {{@firstName}}!</h1>
</div>

์™œ ์ค‘๊ด„ํ˜ธ๊ฐ€ ๋™์  ๋ณ€์ˆ˜( {{@firstName}} )๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋˜์ง€๋งŒ splatted ์†์„ฑ์€ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”์ง€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์‹œ๊ฐ์ ์œผ๋กœ๋Š” <div ...attributes> ๊ฐ€ ๋ Œ๋”๋ง๋  ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด <div {{...attributes}}> ๋กœ ๋” ๋‚ซ์ง€ ์•Š์„๊นŒ์š”?

์–ด๋–ป๊ฒŒ ๋ณด์ด๊ณ  ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”์ง€ ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ๋Š” glimmer ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ RFC๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@tomdale ์œ„์˜ ๋ฌธ์ œ๋Š” ๊ตฌ์„ฑ ์š”์†Œ ํ˜ธํ™˜ ๋ชจ๋“œ ๋ฌธ์„œํ™”๋ฅผ ์–ธ๊ธ‰ํ•˜์ง€๋งŒ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ ๋ฌธ์„œํ™”๋Š” ์–ธ๊ธ‰ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด didReceiveAttrs() ๊ฐ€ ๋” ์ด์ƒ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์— ์ƒ๋‹นํžˆ ๋†€๋ž๊ณ  ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ƒˆ๋กœ์šด ๋ชจ๋ฒ” ์‚ฌ๋ก€ ํŒจํ„ด์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ๋ฌธ์„œ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@dbbk ์šฐ๋ฆฌ๊ฐ€ {{...attributes}} ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์šฐ๋ฆฌ๊ฐ€ curlies๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๋‹ค๋ฅธ ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์ผ๋ฐ˜ ์†์„ฑ๊ณผ ๊ตฌ๋ฌธ์ ์œผ๋กœ ๋ชจํ˜ธํ•˜์ง€ ์•Š๊ณ  4๊ฐœ์˜ ์ ์€ ๋ฌธ์ž๊ฐ€ ํƒ€์ดํ•‘ํ•˜๊ธฐ ์‰ฝ๊ณ  ์‹œ๊ฐ์ ์œผ๋กœ ๋œ ์‹œ๋„๋Ÿฝ๊ฒŒ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ์‚ฌ๋žŒ๋“ค์ด attributes ๊ฐ€ ๋ฒ”์œ„ ๋‚ด ์†์„ฑ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•ด๋‹น ๊ตฌ๋ฌธ์—์„œ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ <SomeComponent something={{attributes}} /> ์ˆ˜ํ–‰ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์Šคํ”„๋ ˆ๋“œ ๊ตฌ๋ฌธ์ด ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๋•Œ ๋‹ค๋ฅธ ์œ„์น˜์—์„œ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋” ๊ฐ•๋ ฅํ•˜๊ฒŒ ์•”์‹œํ•ฉ๋‹ˆ๋‹ค.

@arguments ๋ฅผ ๋ชจ๋‘ ํŠน์ˆ˜ ํ…œํ”Œ๋ฆฟ ๋ฐ”์ธ๋”ฉ์œผ๋กœ ์ฑ„ํƒํ•˜๊ณ  ํ•ธ๋“ค๋ฐ”์— ... ์Šคํ”„๋ ˆ๋“œ ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•˜์ž๋Š” ์ œ์•ˆ์ด ์žˆ์—ˆ์ง€๋งŒ ์ฆ‰๊ฐ์ ์ธ ๋กœ๋“œ๋งต์— ์—†๋Š” ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์— ...attributes ๋ฅผ {{...@attributes}} ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ๋ฉด ์ „ํ˜€ ๋†€๋ผ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Gaurav0 Glimmer ๊ตฌ์„ฑ ์š”์†Œ API๋Š” Ember ์•ฑ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜๊ธฐ ์ „์— RFC ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž ์ ‘๊ทผ ๋ฐฉ์‹์˜ ํ•œ ๊ฐ€์ง€ ์ข‹์€ ์ ์€ "์ฐจ์„ธ๋Œ€" API๋ฅผ ์ •์‹ํ™”ํ•˜์ง€ ์•Š์ง€๋งŒ ์• ๋“œ์˜จ ์—์ฝ”์‹œ์Šคํ…œ์„ ํ†ตํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ๋””์ž์ธ์ด ์žฅ์ ์„ ๋†“๊ณ  ๊ฒฝ์Ÿํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Turbo87 ์ข‹์€ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํŒจํ„ด๊ณผ ์ƒˆ๋กœ์šด API๋กœ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

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

๋Œ€์‹ :

import Component from "@ember/component";
import { computed } from "@ember/object";

export default Component.extend({
  didReceiveAttrs() {
    this.set('firstName', this.attrs.firstName || 'Tobias');
    this.set('lastName', this.attrs.lastName || 'Bieniek');
  },

  fullName: computed('firstName', 'lastName', function() {
    return `${this.firstName} ${this.lastName}`;
  })
});

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰:

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  <strong i="27">@tracked</strong> get firstName() {
    return this.args.firstName || 'Tobias';
  }

  <strong i="28">@tracked</strong> get lastName() {
    return this.args.lastName || 'Bieniek';
  }

  <strong i="29">@tracked</strong> get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

์ฒ˜์Œ์—๋Š” ์ด์— ๋Œ€ํ•ด ํšŒ์˜์ ์ด์—ˆ์ง€๋งŒ @wycats ๊ฐ€ ์ €๋ฅผ ์„ค๋“ํ–ˆ๊ณ  ์ง€๋‚œ 1๋…„ ๋™์•ˆ ํฐ Glimmer.js ์•ฑ์„ ๊ตฌ์ถ•ํ•œ ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด didReceiveAttrs ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋งŒ๋‚œ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋” ํšจ์œจ์ ์ธ ๊ณ„์‚ฐ ์†์„ฑ์œผ๋กœ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@tomdale ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ didReceiveAttrs ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋•Œ๋กœ๋Š” ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋œ ์†์„ฑ ์ค‘ ํ•˜๋‚˜์— ๋Œ€ํ•ด ๊ด€์ฐฐ์ž๋ฅผ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์†์„ฑ โ€‹โ€‹์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ajax ์š”์ฒญ์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”? ๋‚˜๋Š” getter์— ๊ทธ๋Ÿฐ ์ข…๋ฅ˜์˜ ๋ถ€์ž‘์šฉ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ, ๋น„์Šทํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์˜ˆ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์ž…๋‹ˆ๋‹ค. collapsed ๊ฐ€ true ์—์„œ false ๋˜๊ณ  ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ๋ณ€๊ฒฝ๋  ๋•Œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. glimmer ๊ตฌ์„ฑ ์š”์†Œ์™€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

@turbo87 @Gaurav0 ์•„ ์ข‹์•„, ์‹œ์Šคํ…œ์ด ์ž‘๋™ํ•˜๋Š” ์ด์œ ๋Š” ๋ชจ๋‘ ๋™๊ธฐ์‹์ธ didReceiveAttrs ์—์„œ ์ˆ˜ํ–‰ํ•ด์„œ๋Š” ์•ˆ ๋˜๋Š” ์„ฑ๋Šฅ ํ’‹๊ฑด ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค! ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ๊ณผ ๊ฐ™์€ ๋ถ€์ž‘์šฉ์ด ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์€ didInsertElement ๋˜๋Š” didUpdate ์™€ ๊ฐ™์€ ๋น„๋™๊ธฐ ํ›„ํฌ๋กœ ์˜ˆ์•ฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

didInsertElement ๋Š” ์œ„์˜ ์˜ˆ์—์„œ ์ž˜ ๋งž์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. didUpdate ๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋  ๋•Œ๋งŒ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋งž์Šต๋‹ˆ๊นŒ? ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋ Œ๋”๋ง์— ํ•ด๋‹น ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๊ทธ๋Ÿฌ๋ฉด ์ธ์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ didUpdate ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๐Ÿค”

๋˜ํ•œ didInsertElement ๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋ฉด Glimmer์—์„œ ํ•˜๋“œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

@Turbo87 didUpdate ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์˜คํ•ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ›„ํฌ๋Š” ํ…œํ”Œ๋ฆฟ์— ์‚ฌ์šฉ๋œ ์ถ”์  ์†์„ฑ ๋˜๋Š” ์ „๋‹ฌ๋œ ์ธ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค: http://tinyurl.com/y7osxpy2. ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ํ•ด๋‹น ์ธ์ˆ˜๋ฅผ "์‚ฌ์šฉ"ํ•œ ์ ์ด ์—†๋”๋ผ๋„ ํ˜ธ์ถœ๋œ didUpdate ํ›„ํฌ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

@Gaurav0 ๊ณจ๋Œ€๋ฅผ ์˜ฎ๊ธฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ;) ๊ท€ํ•˜์˜ ์˜ˆ๋Š” didInsertElement ์—์„œ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ธ์ˆ˜ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ajax ์š”์ฒญ์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋™์‹œ์— ์†์„ฑ์„ ๋™๊ธฐ์ ์œผ๋กœ ์„ค์ •ํ•˜๋ ค๋ฉด ์ง€์—ฐ ๊ฒŒํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ๋™์ž‘์„ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ajax ์ดํ›„์— ์†์„ฑ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์˜ค๋ฅ˜๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ข‹์•„, ๋‚˜์—๊ฒŒ ์ถฉ๋ถ„ํ•ด ๋ณด์ธ๋‹ค. ์–ด์จŒ๋“  ์ด ํŠน์ • ์‚ฌํ•ญ์„ ํ™•์žฅํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ฒ ์ €ํ•œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ์ ์„ ๊ฐ•์กฐํ•˜๊ณ  ์‹ถ์—ˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค. :)

@tomdale ์ด๊ฒŒ ์•„์ง ์ตœ์‹  ์ƒํƒœ์ธ๊ฐ€์š”? ํ•œ๋™์•ˆ ๋น„ํ™œ์„ฑ ์ƒํƒœ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@tomdale ์ข‹์Šต๋‹ˆ๋‹ค. ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ํŠน์ • ์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜๊ณ  ํ•ด๋‹น ์†์„ฑ๋งŒ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ

@Gaurav0 ์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜๋Š” ์›์ธ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? DDAU์— ์ด์–ด ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์„ ๋‹ด๋‹นํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ AJAX ์š”์ฒญ์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ๋„ ๋‹ด๋‹นํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์†์„ฑ์ด ์ƒ์œ„ ๊ตฌ์„ฑ ์š”์†Œ/์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์šฐ.

@Gaurav0 @tomdale ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๋˜ ๋‹ค๋ฅธ ์˜ˆ๋Š” ๋‹ค๋ฅธ "๊ฐ์ฒด"์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•˜๋Š” (๋Œ€๋ถ€๋ถ„) "DOM์ด ์—†๋Š”" ๊ตฌ์„ฑ ์š”์†Œ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ์˜ˆ๋Š” ์ „๋‹จ์ง€ ์ง€๋„์˜ ๋‚ด์šฉ์„ ์„ ์–ธ์ ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ember-leaflet/ ember-composability-tools ์ž…๋‹ˆ๋‹ค. ๋‚˜์—๊ฒŒ ์ด๊ฒƒ์€ didReceiveAttrs ๋˜๋Š” observer ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ Glimmer ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@nickschot ์ €๋Š” ์ด๊ฒƒ์„ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๋‹ค์–‘ํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ์• ๋“œ์˜จ ๋ฐ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ์„ค๊ณ„ ๊ณผ์ •์—์„œ ๊ฐ์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ ๊ตฌ์ฒด์ ์œผ๋กœ ember-leaflet ๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค.

ember-leaflet / ember-composability-tools ๋ฅผ ํŒŒํ—ค์ณ ๋ณด๋ฉด ์‹ค์ œ๋กœ didReceiveAttrs ๋˜๋Š” didUpdate ๋˜๋Š” ์ด์™€ ๊ฐ™์€ ์ˆ˜๋ช… ์ฃผ๊ธฐ ํ›„ํฌ๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. . ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ถ€๋ชจ(๊ทธ๋ฆฌ๊ณ  ๊ถ๊ทน์ ์œผ๋กœ ๋ฃจํŠธ ๋ Œ๋”๋ง ๋ถ€๋ชจ)์— ๋“ฑ๋ก/๋“ฑ๋ก ์ทจ์†Œํ•˜๋ ค๋ฉด ์‹ค์ œ๋กœ init ๋ฐ willDestroy ํ›„ํฌ๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ Glimmer ๊ตฌ์„ฑ ์š”์†Œ์˜ constructor ๋ฐ willDestroy ํ›„ํฌ์—์„œ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฃจํŠธ ์ƒ์œ„ ๊ตฌ์„ฑ์š”์†Œ๋Š” didInsertElement ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด _ํ•„์š”ํ•˜์ง€๋งŒ {{did-insert}} ์ˆ˜์ •์ž๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ {{did-insert}} / {{did-update}} ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOM ์š”์†Œ์— ์†์„ฑ ์ˆ˜๋ฅผ ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์€ ์ž๋™ ์ถ”์ ๋˜๋ฏ€๋กœ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ๋‹ค์‹œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๊ฒฝ์šฐ ๊ณ ์œ ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ์ˆ˜์ •์ž๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์ด ๋˜ํ•œ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํฌ๋ฏธํ•œ ๋น›์˜ ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค ์–ด๋Š ์ •๋„ ๊ด€๋ จ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€์žˆ๋‹ค - A๋Š” ๊ฐ™์€ "๊ฐ์ง€๊ธฐ๋ฅผ ๋ Œ๋”๋ง" ์ด ํ•˜๋‚˜ ์—์„œ ember-google-maps ์ถ”๊ฐ€ ๊ธฐ๋Šฅ. ์ด๊ฒƒ์€ ํ›จ์”ฌ ๋œ ์ผ๋ฐ˜์ ์ด๋ฉฐ(์ด๊ฒƒ์€ ํ•œ ๋ฒˆ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธ๋จ) DOM์„ ๋ณด๊ธฐ ์œ„ํ•ด MutationObserver ๋˜๋Š” ์‹คํ–‰ ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค didUpdate / didRender ํ›„ํฌ. ์ €๋Š” ์‹ค์ œ๋กœ ๋ฒ”์šฉ <RenderDetector> ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ตฌ์„ฑ ์š”์†Œ ํ•˜์œ„ ํŠธ๋ฆฌ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ์‹œํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ฐพ๊ธฐ ์‰ฌ์šด ๋‹จ์ผ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

@pzuraq ์˜ค๋žœ๋งŒ ์ด์ง€๋งŒ ์ด ์˜์—ญ์—์„œ ์ž‘์€ ์—…๋ฐ์ดํŠธ์ž…๋‹ˆ๋‹ค. ๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด์— DOM์ด ์ „ํ˜€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ˆ˜์ •์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ˜„์žฌ ํ•œ ์ผ์€ didUpdate ํ›„ํฌ๋ฅผ ๋‹ค์‹œ ํ™œ์„ฑํ™”ํ•˜๋Š” ํฌ๋ฏธํ•œ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ ๊ด€๋ฆฌ์ž๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@nickschot ์‹ค์ œ๋กœ ๋„์šฐ๋ฏธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ—ฌํผ๋Š” ์ต์ˆ™ํ•˜๋‹ค๋ฉด React์˜ useEffect ์™€ ์œ ์‚ฌํ•œ ๋ถ€์ž‘์šฉ๊ณผ ์•„๋ฌด ๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ˆ˜์ •์ž๋Š” useLayoutEffect ์™€ ๋” ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค).

ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๋„์šฐ๋ฏธ API๋Š” ์•ฝ๊ฐ„์˜ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š” ์ตœ์ข… ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜์ •์ž API์— ์ง๋ฉดํ•˜๋Š” ๊ฒƒ๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ฒŒ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋””์ž์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์šฐ๋ฏธ ๊ด€๋ฆฌ์ž๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•จ). ํ•˜์ง€๋งŒ ํ˜„์žฌ API๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๋ถ€์ž‘์šฉ์„ ๋‹ฌ์„ฑํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋Šฅ๋ ฅ์ž…๋‹ˆ๋‹ค.

@pzuraq ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ? ์‚ฌ์šฉ์ž ์ง€์ • ๋„์šฐ๋ฏธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋‚˜์š” ์•„๋‹ˆ๋ฉด ๋„์šฐ๋ฏธ๊ฐ€ ๋งŒ๋“ค๊นŒ์š”?

๊ตฌ๋ฌธ์ด ์ด๋ ‡์Šต๋‹ˆ๊นŒ?

{{concat (did-insert this.myAction)}}

์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๊ณ  "์ˆ˜์ •"ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.

์•„๋‹ˆ๋ฉด ์ˆ˜์ •์ž ๋Œ€์‹  ๋„์šฐ๋ฏธ

{{my-did-insert this.myAction}}

๊ทธ๋ ‡๋‹ค๋ฉด ๋ฌธ์„œ ๋ฐ ์˜ˆ์ œ์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค. ํด๋ž˜์Šค ๋„์šฐ๋ฏธ์˜ ํ˜„์žฌ ๊ณต๊ฐœ API์—๋Š” compute ๋ฐ recompute ์žˆ๊ณ  ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ฌด ๊ฒƒ๋„ ์—†์Šต๋‹ˆ๋‹ค.

์–ด๋ฆฌ์„์€ ์งˆ๋ฌธ์„ ์šฉ์„œํ•ด ์ฃผ์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜ Ember ์‚ฌ์šฉ์ž์—๊ฒŒ ์ด ๋ฌธ์ œ๋Š” ๋งค์šฐ ๋น„๋ฐ€์Šค๋Ÿฝ๊ณ  ๋ฌธ์„œ๊ฐ€ ๋ถ€์กฑํ•˜๊ณ  ํฉ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋‹ˆ๋ฉด ์ˆ˜์ •์ž ๋Œ€์‹  ๋„์šฐ๋ฏธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๋งž์•„์š”. ์˜ˆ๋ฅผ ๋“ค์–ด @ember/render-modifiers API๋ฅผ ๋ชจ๋ฐฉํ•˜๋Š” ember-render-helpers ์—์„œ ์ด์— ๋Œ€ํ•œ ์˜ˆ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ compute ๋Š” ๋„์šฐ๋ฏธ๊ฐ€ ํ…œํ”Œ๋ฆฟ/๊ณ„์‚ฐ์— ์ฒ˜์Œ ์‚ฝ์ž…๋  ๋•Œ ํŠธ๋ฆฌ๊ฑฐ๋˜๊ณ  ์ธ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ 3.13+์—์„œ ์ž๋™ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด {{did-insert}} ํ–‰์„ ๋”ฐ๋ผ ๋ฌด์–ธ๊ฐ€๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export default class didInsert extends Helper {
  compute(fn) {
    if (!this.rendered) {
      fn();
      this.rendered = true;
    }
  }
}

๊ทธ๋ฆฌ๊ณ  ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. ์•ฝ๊ฐ„ ๋‹ต๋‹ตํ•˜๊ณ  ๋น„๋ฐ€์Šค๋Ÿฌ์›Œ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์ตœ์ฒจ๋‹จ/์นด๋‚˜๋ฆฌ์•„ ์ธก๋ฉด์— ์žˆ๋Š” ํŠน์„ฑ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์•„์ง ๋ชจ๋“  ์ƒˆ๋กœ์šด ํŒจํ„ด์„ ๋ฌธ์„œํ™”ํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿ™‚

Octane์ด ์ถœ์‹œ๋œ ์ง€๊ธˆ ์ด ๋ฌธ์ œ๋ฅผ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜„

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰