💡 해당 글은 유튜브 "가장 쉬운 웹개발 with Boaz"의 "React component, element, instance 끝내기"를 보고 정리한 글입니다. 문제 시 삭제합니다!
React component, element, instance 끝내기
🌟 Component, Element, Instance가 각각 무엇인지 정확하게 알고 있는 것이 중요하다!
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를 가짐)isSubmitted
와 this.button
, this.message
체크해서 각 children
을 create, update, destory!✔️ 한계점
appendChild()
, removeChild()
하는 코드를 계속 써주어야 함Form
Component 가 직접 button
Component를 생성하고 있기 때문에, 두 Component는 서로 Decoupling 하기가 어렵다!→ 이를 극복하기 위해 나온 게 Element!!
type
와 props
라는 프로퍼티를 가짐type
: string | ReactClass, props
: object)type
이 string일지 ReactClass일지는 Element 종류에 따라 달라짐{
type: 'button',
props: {
className: 'button button-blue',
children: {
type: 'b',
props: {
children: 'OK!'
}
}
}
}
<button class='button button-blue'>
<b>
OK!
</b>
</button>
type
으로 지정된 'button'은 HTML 태그의 이름type
이 string 값으로 들어감{
type: Button,
props: {
color: 'blue',
children: 'OK!'
}
}
즉,
DOM element
면type
이 string이고,
Component element
면type
이 ReactClass
Q. 그래서 이렇게 도입한 element로 어떻게 기존의 UI 모델링의 한계를 극복했는가?
const DeleteAccount = () => ({
type: 'div',
props: {
children: [{
type: 'p',
props: {
children: 'Are you sure?'
}
}, {
type: DangerButton,
props: {
children: 'Yep'
}
}, {
type: Button,
props: {
color: 'blue',
children: 'Cancel'
}
}]
}
})
const DeleteAccount = () => (
<div>
<p>Are you sure?</p>
<DangerButton>Yep</DangerButton>
<Button color='blue'>Cancel</Button>
</div>
);
p
, DangerButton
, Button
이 서로 완전히 decoupled가 가능해짐div
태그 아래에 있는 type
이 Button
인 객체에는 어떻게 create/update/destroy 되어야 하는지에 대한 정보 없음Button
Component 내부에 가지고 있는 것!!{
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!'
}
}
}
}
const Form = ({ isSubmitted, buttonText }) => {
if (isSubmitted) {
// Form submitted! Return a message element.
return {
type: Message,
props: {
text: 'Success!'
}
};
}
// Form is still visible! Return a button element.
return {
type: Button,
props: {
children: buttonText,
color: 'blue'
}
};
};
🌟 Reconciliation은 다른 영상에서 더 자세히 다뤄주신다고... 여기서는 그냥 "리액트 컴포넌트에서 props나 state가 변경될 때, 직전에 렌더링된 element와 새로 반환된 element를 비교하여 실제 DOM을 업데이트 할지 말지 결정하게 되는데, 이때 두 element가 일치하지 않으면 새로운 요소로 DOM을 업데이트 하는 것" 정도로 이해하고 넘어가면 될듯...
ReactDOM.render({
type: Form,
props: {
isSubmitted: false,
buttonText: 'OK!'
}
}, document.getElementById('root'));
// 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 reconciliation