이 시리즈의 이전 글은 아래로...
feat/#3_ExampleComponent
브랜치에서 자세히 확인 하실 수 있습니다! 😊
컴포넌트는 항상 하나의 부모 프래그먼트로 감싸주어야 합니다!
template() {
return `
<div>
<h1>Hello, World!</h1>
<p>Hello, Component!</p>
</div>
`
}
template() {
return `
<h1>Hello, World!</h1>
<p>Hello, Component!</p>
`
}
// components/example/Button
interface IButtonState {
onClick(): void
}
...
export default class Button extends Component<IButtonState> {
template(): string {
const children = this.node.textContent || '버튼'
return `
<button>${children}</button>
`
}
setEvent(): void {
this.node.addEventListener('click', this.state.onClick)
}
clearEvent(): void {
this.node.removeEventListener('click', this.state.onClick)
}
}
render
시, 실행될 html을 반환 해줍니다.render
이후, 현재 node에 이벤트를 바인딩해줍니다.unMount(update)
시, 현재 node의 이벤트를 제거해줍니다.// components/example/ExampleText
interface IExampleTextState {
text: string
}
...
export default class ExampleText extends Component<IExampleTextState> {
template(): string {
const { text } = this.state
return `
<div>
<h1>Example Component</h1>
<p>${text}</p>
</div>
`
}
}
잘 만들어진 하위 컴포넌트를 상위 컴포넌트에서 사용해보자!
// App.ts
...
constructor({ node }: IComponentParams<IAppState>) {
const initalState = {
initalText: '이 Text가 변경될 때는 렌더링이 되지 않아요!',
text: `initalState`,
handleChangeText: (): void => {
this.setState({
text: `Changed State: ${Math.random()}`
})
},
handleChangeInitalText: (): void => {
this.setState({
initalText: `다른 컴포넌트의 렌더링 영향으로 렌더링이 되었습니다! ${Math.random()}`
})
},
onClick: (type: string): void => {
if (type === 'initalText') {
this.state.handleChangeInitalText()
return
}
this.state.handleChangeText()
}
}
super({ node, initalState })
}
initalState
가 없는 경우, constructor()
에서 새롭게 정의해준 뒤, super()
메서드를 호출합니다.// App.ts
template(): string {
return `
<main id="App">
<ExampleText></ExampleText>
<HandleTextButton>Change Text!</HandleTextButton>
<HandleInitalTextButton>Change InitalText</HandleInitalTextButton>
</main>
`
}
template()
에 하위 컴포넌트가 들어갈 자리를 태그로 만들어 표시합니다.document.createElement()
로 만들어도 되지만 편의성 및 컴포넌트 확인을 위해 위와 같이 작성하였습니다! )// App.ts
...
attachChildComponent(): void {
const { initalText, text, onClick } = this.state
const exampleText = new ExampleText({
node: selectEl(this.node, 'ExampleText'),
preventRenderStateKey: ['initalText'],
initalState: {
initalText,
text
}
})
new Button({
node: selectEl(this.node, 'HandleTextButton'),
initalState: {
onClick: (): void => {
onClick('text')
}
}
})
new Button({
node: selectEl(this.node, 'HandleInitalTextButton'),
initalState: {
onClick: (): void => {
onClick('initalText')
}
}
})
this.subscribe(exampleText)
}
attachChildComponent()
에 부착할 컴포넌트를 new
키워드와 함께 호출합니다.subscribe()
메서드에 해당 컴포넌트를 넣어 추적합니다.preventRenderKeys
에 배열로 해당 키를 넣어줍니다.preventRenderKeys
에 포함되어 있지 않은 키값이 setState()
되는 경우, 여부와 관계없이 무조건 렌더링 됩니다.
Button
컴포넌트와 같이App
컴포넌트의 상태가 변경이 되었을 때, 리렌더링이 필요가 없는 컴포넌트는 구독을 해주지 않아도 됩니다.
=> 구독을 안해주면 초기 상태만 넘겨받은 뒤, 부모 컴포넌트의 상태를 추적하지 않습니다.
휴,,, 아직 any로 되어 있는 타입들도 많고 state에 대한 방어처리, 렌더링 최소화 처리에 대한 아이디어는 많지만.. 시간이 없으니 차근차근 해보는걸로....
다음편 기대돼요 !!!!!