제목에 적어놓은 Tracked, Getter, Actions는 컴포넌트에만 존재하는 것이 아니라 Controller에서 사용된다.
뿐만아니라 관련해서는 현재 튜토리얼 페이지에서 따라해보면 Route에서도 사용되는 것 같다.
먼저 컴포넌트의 구성부터 살펴보자면
import Component from '@glimmer/component'
import {tracked} from '@glimmer/trancking'
export default class MyComponent extends Component {
@tracked firstName = 'Shawn';
@tracked lastName = 'Chen'
get fullName() {
return this.firstName + this.lastName;
}
}
glimmer
에서 import
시킨 tracked
는 데코레이터로 속성 앞에 작성할 경우 동작한다.
어떤 것에 대한 동작이냐?
간단히 설명하면 React에서 사용했던 useState같은 느낌과 비슷하다.
우리가 React를 사용할 때 상태가 변경됨을 체크하려면 useState를 썼던 것처럼 속성이 변경될 때 알림을 받으려면 @tracked
즉, GIT
을 할 때 한번쯤 들었던 것처럼 트랙킹,추적을 해야한다.
이경우 hbs
파일에서
<h1>{{this.fullName}}</h1>
사용했을 때 fullName을 렌더링 해야한다면 일단 처음 만들어질 때 초기화 된 Shawn Chen
을 출력할 것이다.
tracked
되어 있기 때문에 아마 변경이 된다면 최신 정보를 출력할 것이다.
그럼 최신으로 바꾸기 위해 필요한 Action
부분을 살펴보자
import Component from '@glimmer/component'
import {tracked} from '@glimmer/trancking'
import {action} from '@ember/object'
export default class MyComponent extends Component {
@tracked number = 0;
@action
addNumber() {
this.number = this.number + 1;
}
}
action
데커레이터를 통해서 숫자를 증가시키는 간단한 액션을 추가한다. 이후 template
부분에서 보자면
<h1>Number : {{this.number}}</h1>
<button {{on "click" this.addNumber}}>Add</button>
다른 React 등을 보다 보면 되게 생소할 수 잇다. 저게 함수인가?? 뭐지? 하는 느낌이 나도 처음 들었는데 일단 하나씩 살펴보자면..
on
부분은 이벤트를 트리거 할 수 있도록 도와주는 ember helper인데 이 부분인데 정확한 설명은 없고 일단 버튼에 이벤트를 트리거 하기 위해선 첫번째로 on이 들어가는 구나를 일단 인식해보자
2번째 인수로 들어간 "click"
은 이벤트의 이름을 알려주고 클릭임으로 클릭이벤트를 트리거 한다라고 알려주는 것이다.
그리고 마지막 이벤트는 우리가 정의한 액션을 집어 넣는 것이다.
on
을 통해 ember helper를 불러서 ember가 이벤트를 트리거 할 수 있도록 부르고 "click"
어떤 이벤트인지 알려주고, this.addNumber
실행할 이벤트를 적는 것이다.
onClick={clickHandler}
를 on/Click/={clickHandler}
react에서 사용된 클릭 이벤트를 저렇게 나눠 쓴다고 생각하면 바로 이해가 온다
그럼 이걸 이전에 만든 컴포넌트들에 적용시키려면 어떻게 해야할까?
똑같이 emberCLI를 이용한다면 만들기 쉽다
ember g component-class product
를 입력할 경우 product
의 class
가 담긴 app/components/product.js
가 생성되게 된다.
해당 파일에서 tracked
와 action
을 이용해 다양한 함수 처리를 해보고 익혀보자
그렇다면 속성과 인수부분은 어떻게 될까??
여기서 속성은 현재 정의된 변수라 보면 편한데
export default class Child extends Component {
propA = 1;
}
export default class Parent extends Component {
propB = 2;
}
클래스와 인수는 상위 구성요소에서 전달된 것이므로 예시로 바로 확인해보자
<!-- parent.hbs -->
<Child @propB={{this.propB}} />
<!-- child.hbs -->
<h1>Child : {{this.propA}}</h1>
<h1>Parent : {{@propB}}</h1>
이렇듯 상위에 있는 parent.hbs
에서 Child
컴포넌트에게 React처럼 props
를 보내고 싶을 때 @
를 사용해서 보내면 된다
@
뒤에 보낼 prop에 이름을 명시하고 ={{this.propB}}
으로 Parent
컴포넌트가 렌더링 될 당시 실행될 class Parent
에 있는 속성 propB
의 값 2
를 Child
에게 보낸다
이러면 Child.hbs
에선 propB
라는 이름으로 2
라는 값을 받아 사용할 수 있게 되고 그사용되는 부분이 {{@propB}}
이다.
React에서 props로 어떠한 값을 보낼대 사용한 <Child data={user} />
에서 @
와 {}
만 더 추가된 느낌이라 크게 어려울 것은 없다.
css에서도 똑같이 동적인클래스를 만들 수 있다
@tarcked
된 속성을 변경됨에 따라 클래스를 변경할 수 있는데, 이는class
에서도 똑같이{{}}
를 사용해서 classname을 동적으로 줄 수 있다.
이는 만약 텍스트 샊깔을 바꾼다 했을 때 기본 프로퍼티로는@tracked color = black;
을 설정해놓은 상태다
그리고 변경버튼을 누를 경우red
색깔로 바뀐다고 가정했을 때 변경될 곳에
class="text-{{this.color}}
식으로 넣을경우 동적으로 클래스 네임을 변경할 수 있게 된다.
그럼 클릭을 눌렀을 때 어떠한 매개변수나 인자를 받고 싶다면 어떻게 하는게 좋을까?
{{on 'click' this.changeColor}}
이렇게 사용되는 걸 {{on 'click' this.changeColor('red')}}
이렇게 바꾸면 될까?
이때는 함수도우미를 사용하면 인자를 넘겨줄 수 있게 된다
<button {{on "click" (fn this.changeColor "red")}}>ChangeRed</button>
이런 식으로 함수 도우미인 fn
을 사용하고 함수명 뒤에 적는 것이 인자로 넘어가게 된다.
여러개라면 {{on "click" (fn this.changeColor 인자1 인자2 인자3)}}
으로 넘겨주면 동일하게 동작한다.
주의할 점으론 javascript 함수 법칙에 따라 인자와 매개변수의 위치에 대해 주의하자. 이는 typescript를 쓴다면 명확하게 코딩을 할 때 잡을 수 있는 부분이기도 하다