12강. React component, element, instance 끝내기
Managing the Instances
기존 UI model(OOP)
class Form extends TraditionalObjectOrientedView {
render() {
// Read some data passed to the view
const { isSubmitted, buttonText } = this.attrs;
if (!isSubmitted && !this.button) {
// Form is not yet submitted. Create the button!
this.button = new Button({
children: buttonText,
color: 'blue'
});
this.el.appendChild(this.button.el);
}
if (this.button) {
// The button is visible. Update its text!
this.button.attrs.children = buttonText;
this.button.render();
}
if (isSubmitted && this.button) {
// Form was submitted. Destroy the button!
this.el.removeChild(this.button.el);
this.button.destroy();
}
if (isSubmitted && !this.message) {
// Form was submitted. Show the success message!
this.message = new Message({ text: 'Success!' });
this.el.appendChild(this.message.el);
}
}
}
- Button class component → instance(각자 local state, own properties 가짐)
- Form 이 render() 에서 new Button() 호출 instance 를 appendChild 호출하여 render
- isSubmitted 와 this.button, this.message 체크해서 각 children 을 create, update, destroy
한계점
각 component 는 DOM node 주소와, 자식 component 의 instance 주소를 보관해야하며, 시의 적절하게 각각을 create, update, desotry 해야 함
- 관리할 컴포넌트 늘어나면 component 코드의 복잡도 증가
- 자식 component 에게 부모 component 가 직접 접근하므로 decouple(=자식 컴포넌트와 부모 컴포넌트를 분리하는 작업이라 하는데.. 더 찾아봐야 할듯) 하기 어려움
Elements Describe the Trees
React 는 element 를 활용하는 것이 기존 UI model 과 차이점
Elements
- is plain object describing component instance, DOM node and its desired properties
- is not instance, just tell React what you want to see on the screen
- is immutable description object with two fields(type: string | ReactClass, props: object) => element가 생성되면 반드시 type(element 종류에 따라 string(React DOM Elements일때) 혹은 ReactClass(React Component Elements일때) 할당됨)과 props 두가지 속성을 가진 object로 생성됨.
React DOM elements
{
type: 'button', // type이 String
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
<button class='button button-blue'>
<b>
OK!
</b>
</button>
- type: string(tag name)
- props: tag’s attributes (DOM 트리에게 전달할 정보)
- just objects, so lighter than DOM elements(not objects)
- don’t need to be parsed, easy to traverse
React Component elements
{
type: Button, // React component 또는 Function
props: {
color: 'blue',
children: 'OK!'
}
}
- type: Function Or Class(React component)
- props: React component props (DOM 트리에 어떻게 보일지 묘사.)
An element describing a component is also an element, just like an element describing the DOM node. They can be nested and mixed with each other. (element 에 의해 기존의 DOM node 와 React component 를 mixed, nested 한 구조가 가능해짐)
→ 그 결과, component 끼리 decoupled 가 됨(컴포넌트끼리 is-a, has-a 관계로 표현 가능해짐)
const DeleteAccount = () => ({
// 2. 이렇게 element tree 형태로 DOM tree에 전달할 형태만 encapsulate 되어 있음.
type: 'div',
props: {
children: [{
type: 'p',
props: {
children: 'Are you sure?' // <p>Are you sure?</p>
}
}, {
type: DangerButton, // <DangerButton>Yep</DangerButton> => Html 태그 아님에도 Html 태그와 동일한 위계에서 관리 가능
props: {
children: 'Yep'
}
}, {
type: Button, // class 할당. 완전히 로직과 decoupling됨(언제 destroy 되야하는지 이런건 Button 클래스에 써짐. 여기는 UI만 있음)
props: {
color: 'blue',
children: 'Cancel' // <Button color='blue'>Cancel</Button>
}
}]
});
// 1. 이렇게 생간 element(객체)를 return할때는..
const DeleteAccount = () => (
<div>
<p>Are you sure?</p>
<DangerButton>Yep</DangerButton>
<Button color='blue'>Cancel</Button>
</div>
);
Components Encapsulate Element Trees
React 가 type 값이 class or functional 인 element(React component element)를 만나면
- type 값을 보고, 해당 component 함수에게 element 를 return 받는다
- return 받은 element 의 type 값이 tag name 인 element(DOM element)를 만날때까지 1번으로 돌아감
{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
} // React는 Button을 만나면 component에게 물어봐서 아래 DOM element 를 return 받음
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
React 는 모든 React Component elements가 React DOM elements 를 return 할때까지 위 과정 반복
모든 elements가 가진 DOM elements 를 알게 됨 → React 가 해당 DOM elements 들을 적절한 때에 create, update, destroy
따라서 기존에 Form UI modeling 을 아래와 같이 간단하게 구현할 수 있게 됨
const Form = ({ isSubmitted, buttonText }) => {
if (isSubmitted) {
// Form submitted! Return a message element.
return {
type: Message, // component element return
props: {
text: 'Success!'
}
};
} // Form is still visible! Return a button element.
return {
type: Button, // component element return
props: {
children: buttonText,
color: 'blue'
}
};
};
React functional component 는 Props 를 받아서 element 를 return 하는 javascript function
The returned element tree can contain both elements describing DOM nodes, and elements describing other components. This lets you compose independent parts of UI without relying on their internal DOM structure. (React element 를 활용하여, 기존에 DOM structure 을 모두 활용하지 않고, 필요한 정보만 독립적으로 UI 를 관리할 수 있게 됨)
Component 가 return 한 element 를 활용해서 DOM Trees 를 encapsulate
=> 결론: element는 DOM 트리에 전달할 정보를 가진 객체이고, 이 element가 이루는 element tree를 React가 알아서 create, update, destoy 할거다. 그러니까 UI는 위의 코드처럼 react component elements를 return 해주는 방식으로 Decouple 해줄 수 있다.
Components Can Be Classes or Functions
이 부분은 생략(hooks 추가되면서 Functional component 의 기능이 Class component 와 동등해짐)
Top-Down Reconciliation (Reconcilliation 개념 중요 => 나중에 따로 설명 주신다 함)
ReactDOM.render({
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}, document.getElementById('root'));
위 함수 호출 시, React 는 Form component 에게 props 를 전달하며 return element 를 요청
Form → Button(component element) → DOM node element(button) 순서로 return element 진행
// React: You told me this...
{
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}// React: ...And Form told me this...
{
type: Button,
props: {
children: 'OK!',
color: 'blue'
}
}// React: ...and Button told me this! I guess I'm done.
{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
- ReactDom.render(), setState() 호출 시 React call reconcilation
reconcilation 이 끝나면 React knows resulting DOM tree(element Tree)
renderer(e.g. react-dom) 는 필수적인 최소한의 변화를 DOM node 업데이트에 적용 - 위와 같은 점진적 변화 덕분에 쉽게 optimization 가능
props 가 immutable 이면 change 계산이 더 빨라짐 - React 가 class component 의 Instance 를 만들어줌(직접 new 이용해 생성 X)
Parent component instance 가 child component instance 에 직접 접근 하려면 ref 를 활용하는 방법이 있지만, 위 맥락에서 렌더링 최적화를 방해하기에 필수적인 상황(form item 에 focus 를 찾아야 한다거나 등) 제외하고 안하는게 좋음 - Instances 는 React 가 관리하므로, class component 구현시 OOP 스럽게 짜면 되는 정도(따로 instance 에 대해 신경 쓸 필요 X)
Summary
- element 는 DOM Tree 생성에 필요한 정보를 담은 object 다. React DOM node element, React Component element 두 종류. element 는 property 로 다른 element 를 가질 수 있다 → React Component는 element tree(React DOM node element)를 return한다. → DOM node 와 React component 를 mixed, nested 가능하게 함
- component 는 props → element 하는 function
- parent component 가 return 한 element 의 type 이 child component 이름일 때, props 는 해당 child component 의 input(props) 가 된다 → props 는 1 way flow
- instance 는 class component 에서의 this
- instance 를 직접 생성할 필요 X → React 가 해줌
- React.createElement(), JSX, React.createFactory() → return element
'개발 공부 > React' 카테고리의 다른 글
React 디자인패턴 공부 - 1. 컨테이너와 프리젠터 (0) | 2022.12.22 |
---|---|
가장 쉬운 리액트 11강 (0) | 2022.12.16 |
가장 쉬운 리액트 10강 (0) | 2022.12.16 |
가장 쉬운 리액트 9강 (0) | 2022.12.16 |
가장 쉬운 리액트 7~8강 (0) | 2022.12.15 |