파트 3
3.0 파트 3 (클릭 가능)
마운트(Mount)
componentMount
메소드는 이 여정에서 가장 큰 부분 중 하나입니다! 그래서, ReactCompositeComponent.mountComponent
(1)는 흥미로운 메소드 입니다.
기억하시겠지만, 컴포넌트의 트리에 처음 삽입되는 컴포넌트는TopLevelWrapper
(내부 리엑트 클래스)라고 한 적이 있었습니다. 이제 그것 마운팅 하려고 합니다. 하지만, 이건 사실 비어있는 래퍼이므로 디버깅이 좀 지루합니다. 지금 흐름에 전혀 영향을 주지 않기 때문에 지금은 이걸 건너 뛰고 자식으로 이동하겠습니다.
부모와 그 부모의 자식, 그 자식의 자식을 계속해서 마운트하는 것이 트리의 마운팅이 실제로 하는 일입니다. 저를 믿으세요, TopLevelWrapper
가 마운트 된 후에, 그것(ExampleApplication 컴포넌트를 관리하는ReactCompositeComponent
)의 자식도 같은 단계에 놓이게됩니다.
좋습니다, 이제 다시 step(1)로 돌아갑시다. 안에 뭐가 있는지 봅시다. 몇 가지 주요 동작이 발생하므로, 자세하게 이 로직을 살펴 보겠습니다.
인스턴스 updater 할당
transaction.getUpdateQueue()
에서 리턴되는 updater
(2)는 사실 ReactUpdateQueue
모듈입니다. 그런데 updater
가 왜 여기서 할당될까요? ReactCompositeComponent
(우리가 현재보고있는 클래스)는 모든 플랫폼에서 사용되지만, updater는 그렇지 않기 때문에 플랫폼에 따라 마운팅되는 동안 동적으로 할당합니다.
지금은 updater
가 필요하지 않지만 기억해 두십시오. updater
는 정말 중요합니다. 잘 알려진 컴포넌트 메소드인 setState
에 의해 곧 사용될 것입니다.
이 단계에서 인스턴스에 updater
가 할당될뿐만 아니라 컴포넌트 인스턴스(사용자 정의 컴포넌트)도 props
, context
, refs
로 확장됩니다.
아래 코드를 확인하십시오 :
// \src\renderers\shared\stack\reconciler\ReactCompositeComponent.js #255
// 이것들은 생성자안에서 설정되어야하지만,
// 좀더 단순한 클래스 추상화의 편의를 위해, 생성자 이후에 설정했다.
inst.props = publicProps;
inst.context = publicContext;
inst.refs = emptyObject;
inst.updater = updateQueue;
이제, this.props
로 인스턴스의 props
에 접근 할 수 있습니다.
ExampleApplication 인스턴스 생성
_constructComponent
(3)을 호출하고 여러 가지 구성 메소드를 통해 마침내 new ExampleApplication()
이 생성됩니다. 생성자가 호출 될 때가 중요합니다. 이 시점이 리엑트의 생태계로 부터 실제로 영향을 받은 첫번째 순간 입니다.
초기 마운트 수행
mount(4)를 지나면, 먼저 componentWillMount
(명시된 경우)가 호출됩니다. 이건 라이프 사이클 훅의 첫 번째 메소드입니다. 또한, 뒤에서 componentDidMount
를 볼 수 있지만 직접 호출되어서는 안되기 때문에 트랜잭션 대기열에 넣습니다. 이건 마운트 작업이 끝나는 마지막에만 발생합니다. setState
호출은 componentWillMount
안에서도 할 수 있습니다. 이 경우에는 render
메소드 없이 state가 다시 계산됩니다.(컴포넌트가 아직 마운트되지 않았기 때문에 state를 알 수 없습니다).
공식 문서에서 다음과 같이 작성되어 있습니다:
componentWillMount()
는 마운트가 일어나기 직전에 호출된다.render()
전에 호출되기 때문에, 이 메소드의 state를 설정해도 리렌더링이 발생되지 않는다.
코드를 확인해 봅시다.
// \src\renderers\shared\stack\reconciler\ReactCompositeComponent.js #476
if (inst.componentWillMount) {
//..
inst.componentWillMount();
// 마운트 할 때,`componentWillMount`에 의한 `setState`호출은 리렌더링을 하지 않고,
// `this._pendingStateQueue`를 설정합니다.
if (this._pendingStateQueue) {
inst.state = this._processPendingState(inst.props, inst.context);
}
}
state
가 다시 계산 될 때 render
메소드를 호출합니다. 정확히는 사용자가 컴포넌트에서 지정하는 것입니다! 이제 한번 더 코드에 손대봅시다.
다음은 리엑트 컴포넌트 인스턴스를 만드는 것입니다. 또 하는것 같나요? 이미 this._instantiateReactComponent
(5) 호출을 본 것 같습니다. 맞나요? 사실이지만, 그때는 ExampleApplication
컴포넌트에 대해 ReactCompositeComponent
를 인스턴스화했습니다. 이제 render
메소드에서 얻은 엘리먼트를 기반으로 그 자식에 대한 VDOM 인스턴스를 생성 할 것입니다. 정확하게는 render 메서드는 div
를 반환하므로 VDOM 표현은 ReactDOMComponent
입니다. 인스턴스가 생성되면, ReactReconciler.mountComponent
를 다시 호출합니다. 하지만 이번에는 internalInstance
로 새로 생성 된 ReactDOMComponent
의 인스턴스를 전달합니다.
그리고,mountComponent
를 호출합니다.
좋습니다, 이제 우리는 파트 3를 끝냈습니다.
우리가 어떻게 여기까지 왔는지 다시 한번 살펴보도록 합시다. 스키마에서 덜 중요한 부분을 제거하면 다음과 같습니다.
3.1 간단히 보는 파트 3 (클릭 가능)
공백제거와 정렬을 통해 보기 좋게 수정했습니다.
3.2 간단히 보는 파트 3 리펙토링 버전 (클릭 가능)
좋습니다. 사실, 이것이 여기서 일어나는 일 전부입니다. 이제 파트 3의 핵심들을 가지고 최종 mounting
스키마에 사용할 수 있습니다.
3.3 파트 3의 핵심 (클릭 가능)
그리고 이제 우리는 해냈습니다!