클래스형 컴포넌트( comment 기능)
클래스형 컴포넌트는 React 16.8 이전에 사용했던 React 컴포넌트의 종류입니다. 클래스형 컴포넌트는 JavaScript 클래스를 사용하여 정의됩니다. 클래스형 컴포넌트는 다음과 같은 메서드와 속성을 제공합니다.
- constructor(): 컴포넌트가 생성될 때 호출됩니다.
- render(): 컴포넌트를 DOM에 렌더링합니다.
- setState(): 컴포넌트의 상태를 업데이트합니다.
- componentDidMount(): 컴포넌트가 DOM에 렌더링된 후 호출됩니다.
- componentDidUpdate(): 컴포넌트의 상태가 업데이트된 후 호출됩니다.
- componentWillUnmount(): 컴포넌트가 DOM에서 제거되기 전에 호출됩니다.
클래스형 컴포넌트는 React 16.8에서 도입된 함수형 컴포넌트로 대체되었습니다. 함수형 컴포넌트는 더 간단하고 이해하기 쉽고 성능이 더 뛰어납니다. 그러나 클래스형 컴포넌트는 여전히 유효한 컴포넌트 형식이며, 많은 React 프로젝트에서 계속 사용되고 있습니다.
클래스형 컴포넌트의 장점은 다음과 같습니다.
- 상태 관리가 쉽습니다.
- 이벤트 처리가 쉽습니다.
- 라이프사이클 메서드를 사용하여 컴포넌트의 상태를 추적하고 관리할 수 있습니다.
클래스형 컴포넌트의 단점은 다음과 같습니다.
- 코드가 길고 복잡합니다.
- 함수형 컴포넌트에 비해 성능이 떨어집니다.
클래스형 컴포넌트는 다음과 같은 상황에서 사용하기 좋습니다.
- 상태 관리가 복잡한 컴포넌트
- 이벤트 처리가 복잡한 컴포넌트
- 라이프사이클 메서드를 사용하여 컴포넌트의 상태를 추적하고 관리해야 하는 컴포넌트
※
React에서 component는 UI의 일부를 제어하는 재사용 가능한 코드입니다. 컴포넌트는 JavaScript에서 함수의 역할을 React에게서 담당하는 것과 같습니다. 애플리케이션을 논리적이고 재사용 가능한 부분으로 구성하는 데 도움을 줍니다.
React 컴포넌트는 다음과 같은 특징을 가지고 있습니다.
- 재사용 가능합니다. 한 번 만든 컴포넌트를 다른 곳에서 다시 사용할 수 있습니다.
- 상태를 가질 수 있습니다. 컴포넌트의 상태는 시간이 지남에 따라 변경될 수 있습니다.
- props를 받을 수 있습니다. props는 컴포넌트에게 전달되는 외부 데이터입니다.
React 컴포넌트를 사용하는 방법은 다음과 같습니다.
- React.Component 클래스를 상속받습니다.
- render() 메서드를 구현합니다. 이 메서드는 컴포넌트의 출력을 반환합니다.
- props 속성을 사용하여 외부 데이터를 받습니다.
다음은 간단한 React 컴포넌트의 예입니다.
ex.1
class Hello extends React.Component {
render() {
return (
<div>
Hello, world!
</div>
);
}
}
이 컴포넌트는 Hello, world!라는 텍스트를 표시합니다.
React 컴포넌트를 사용하면 애플리케이션을 더 쉽게 유지 관리하고 확장할 수 있습니다. 컴포넌트는 애플리케이션을 논리적이고 재사용 가능한 부분으로 구성하는 데 도움이 되며, 상태와 props를 사용하여 컴포넌트의 동작을 제어할 수 있습니다.
ex.2 기초적인 comment 기능
// index.html
<script src="./js/index.js" type="module"></script>
<div id="app"></div>
// index.js
import App from "./app.js";
const root = document.querySelector("#app");
new App(root);
import App from "./app.js";은 App 컴포넌트를 가져오는 코드입니다.
const root = document.querySelector("#app");은 App 컴포넌트가 렌더링될 DOM 노드를 가져오는 코드입니다.
new App(root);은 App 컴포넌트를 생성하고 렌더링하는 코드입니다.
// app.js
import Component from "./core/component.js";
import Comment from "./src/components/comments.js";
class App extends Component {
// constructor(target) {
// super(target);
// ...
// }
//없어도 실행된다
setup() {}
template() {
return `
<div>header</div>
<div>
<div data-component='comment'></div>
</div>
<div>footer</div>
`;
}
mounted() {
const commentTarget = document.querySelector(`[data-component="comment"]`);
new Comment(commentTarget);
}
setEvent() {}
}
export default App;
import Component from "./core/component.js";은 Component 클래스를 가져오는 코드이고
import Comment from "./src/components/comments.js";은 Comment 컴포넌트를 가져오는 코드입니다.
class App extends Component 은 App 컴포넌트가 Component 클래스를 상속받는다는 것을 나타냅니다.
template() 메서드는 App 컴포넌트의 렌더링된 HTML을 반환합니다.
mounted() 메서드는 App 컴포넌트가 렌더링된 후 호출됩니다. 이 메서드에서는 Comment 컴포넌트를 생성하고 렌더링합니다.
setEvent() 메서드는 App 컴포넌트의 이벤트 핸들러를 설정합니다.
export default App;은 App 컴포넌트를 내보냅니다.
해석을 자세하게 설명하자면,
- import App from "./app.js";은 App 컴포넌트를 가져오는 코드입니다. 이 코드는 App 컴포넌트의 코드를 브라우저로 가져옵니다.
- const root = document.querySelector("#app");은 App 컴포넌트가 렌더링될 DOM 노드를 가져오는 코드입니다. 이 코드는 #app이라는 ID를 가진 DOM 노드를 가져옵니다.
- new App(root);은 App 컴포넌트를 생성하고 렌더링하는 코드입니다. 이 코드는 App 컴포넌트를 생성하고 root DOM 노드에 렌더링합니다.
- class App extends Component {은 App 컴포넌트가 Component 클래스를 상속받는다는 것을 나타냅니다. Component 클래스는 React 컴포넌트의 기본 클래스입니다.
- template() 메서드는 App 컴포넌트의 렌더링된 HTML을 반환합니다. 이 메서드는 <div>header</div>, <div><div data-component="comment"></div></div>, <div>footer</div>라는 HTML을 반환합니다.
- mounted() 메서드는 App 컴포넌트가 렌더링된 후 호출됩니다. 이 메서드에서는 Comment 컴포넌트를 생성하고 렌더링합니다.
- setEvent() 메서드는 App 컴포넌트의 이벤트 핸들러를 설정합니다. 이 메서드는 현재로서는 아무런 작업을 수행하지 않습니다.
- export default App;은 App 컴포넌트를 내보냅니다. 이 코드는 App 컴포넌트를 다른 파일에서 사용할 수 있도록 합니다.
// component.js
class Component {
target;
props;
state = {};
constructor(target, props) {
this.target = target;
this.props = props;
this.setup();
this.setEvent();
this.render();
}
setup() {}
template() {
return "";
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.render();
}
mounted() {}
render() {
this.target.innerHTML = this.template();
this.mounted();
}
setEvent() {}
addEvent(eventType, selector, callback) {
this.target.addEventListener(eventType, (e) => {
if (!e.target.closest(selector)) return false;
callback(e);
});
}
}
export default Component;
이 클래스는 다음과 같은 속성과 메서드를 가지고 있습니다.
- target: 컴포넌트가 렌더링될 DOM 노드.
- props: 컴포넌트에 전달되는 데이터.
- state: 컴포넌트의 상태.
- constructor(): 컴포넌트가 생성될 때 호출되는 메서드.
- setup(): 컴포넌트가 생성된 후 호출되는 메서드.
- template(): 컴포넌트의 렌더링된 HTML을 반환하는 메서드.
- setState(): 컴포넌트의 상태를 업데이트하는 메서드.
- mounted(): 컴포넌트가 렌더링된 후 호출되는 메서드.
- render(): 컴포넌트를 렌더링하는 메서드.
- setEvent(): 컴포넌트의 이벤트 핸들러를 설정하는 메서드.
- addEvent(): 컴포넌트의 DOM 노드에 이벤트 핸들러를 추가하는 메서드.
React 컴포넌트는 Component 클래스를 상속받음으로써 이러한 속성과 메서드를 사용할 수 있습니다.
// form.js
import Component from "../../core/component.js";
class CommentForm extends Component {
setup() {
console.log(this.props.insertItem);
}
template() {
return `
<h4>
댓글쓰기
<span>${this.props.length}</span>
</h4>
<form action="" id="commentFrm" class="commentFrm">
<span class="ps_box">
<input type="text" placeholder="댓글 내용을 입력해주새요" />
</span>
<button type="submit" class="btn">등록</button>
</form>
`;
}
mounted() {}
handleSubmit(e) {
e.preventDefault();
console.log("submit 발동");
this.props.insertItem();
}
setEvent() {
const handleSubmit = this.handleSubmit.bind(this);
this.addEvent("submit", "#commentFrm", handleSubmit);
}
}
export default CommentForm;
위 코드는 다음과 같은 속성과 메서드를 가지고 있습니다.
- props: 컴포넌트에 전달되는 데이터
- insertItem: 댓글을 등록하는 함수
- length: 댓글의 개수
- handleSubmit(): 컴포넌트의 이벤트 핸들러를 설정하는 메서드
// item.js
import Component from "../../core/component.js";
class CommentItem extends Component {
setup() {}
template() {
const items = this.props.comments.map(
(item) => `
<ul class="comment-row" data-index="${item.id}">
<li>${item.userid}</li>
<li>
<span>${item.content}</span>
<span>❌</span>
</li>
<li>${item.date}</li>
</ul>`
);
return items.join("");
}
mounted() {}
setEvent() {}
}
export default CommentItem;
comments 속성으로 받은 댓글 목록을 map() 메서드를 사용하여 반복합니다. map() 메서드는 댓글 목록의 각 항목에 대해 template() 메서드를 호출하고, 그 결과를 배열로 반환합니다.
template() 메서드에서 반환한 배열의 join() 메서드를 사용하여 문자열로 변환합니다. join() 메서드는 배열의 각 항목 사이에 구분자를 삽입하고, 문자열을 반환합니다.
template() 메서드에서 반환한 문자열을 반환합니다.
mounted() 메서드는 컴포넌트가 렌더링된 후 호출됩니다. 이 메서드에서는 아무런 작업을 수행하지 않습니다.
setEvent() 메서드는 컴포넌트의 이벤트 핸들러를 설정합니다. 이 메서드 또한 아무런 작업을 수행하지 않습니다.
CommentItem 컴포넌트는 댓글 목록을 표시하는 컴포넌트입니다. CommentItem 컴포넌트는 comments 속성으로 받은 댓글 목록을 목록으로 표시합니다.
// comment.js
import Component from "../../core/component.js";
import CommentForm from "../contents/form.js";
import CommentItem from "../contents/items.js";
class Comment extends Component {
setup() {
this.state = {
comments: [
{ id: 1, userid: "sang969", content: "안녕하새요", date: "2023-10-7" },
{ id: 2, userid: "sang969", content: "안녕하새요", date: "2023-10-7" },
{ id: 3, userid: "sang969", content: "안녕하새요", date: "2023-10-7" },
],
};
}
template() {
return `
<ul class="comment">
<li class="comment-form">
</li>
<li class="comment-list">
</li>
</ul>
`;
}
insertItem() {
const newState = this.state.comments.push({
id: 4,
useid: "sang969",
content: "content",
date: "2023-10-16",
});
this.setState({ ...this.state, ...newState });
}
mounted() {
const { comments } = this.state;
const formTarget = document.querySelector(".comment-form");
const insertItem = this.insertItem.bind(this);
new CommentForm(formTarget, {
length: comments.length,
insertItem,
});
const itemTarget = document.querySelector(".comment-list");
new CommentItem(itemTarget, { comments });
}
setEvent() {}
}
export default Comment;
Comment 컴포넌트는 mounted() 메서드에서 CommentForm 컴포넌트와 CommentItem 컴포넌트를 생성하고 렌더링합니다.
- CommentForm 컴포넌트는 댓글 등록 폼을 제공하는 컴포넌트입니다.
- CommentItem 컴포넌트는 댓글 목록을 표시하는 컴포넌트입니다.
Comment 컴포넌트는 state의 comments 속성이 변경되면 CommentItem 컴포넌트를 다시 렌더링합니다.

코드 실행 과정
- 브라우저가 HTML 코드를 읽고 DOM 트리를 만듭니다.
- 브라우저가 JavaScript 코드를 읽고 실행합니다.
- App 클래스의 인스턴스가 생성되고 #app 요소에 렌더링됩니다.
- App 클래스의 template() 메서드가 호출되고 댓글 목록이 반환됩니다.
- App 클래스의 render() 메서드가 호출되고 댓글 목록이 #app 요소에 렌더링됩니다.
- #app_btn 버튼이 클릭될 때 App 클래스의 setEvent() 메서드가 호출되고 댓글 목록에 새로운 댓글이 추가됩니다.
App 클래스는 Component 클래스를 상속받습니다. App 클래스는 댓글 목록을 상태로 관리하고 있습니다. template() 메서드는 댓글 목록을 반환하고, setEvent() 메서드는 #app_btn 버튼이 클릭될 때 댓글 목록에 새로운 댓글을 추가하는 이벤트 리스너를 설정합니다.
const app = new App(document.querySelector("#app")); 코드는 App 클래스의 인스턴스를 생성하고 #app 요소에 렌더링합니다.
- Component 클래스의 setup() 메서드는 컴포넌트의 상태를 초기화합니다. App 클래스의 경우, setup() 메서드는 댓글 목록을 초기화합니다.
- Component 클래스의 template() 메서드는 컴포넌트의 HTML을 반환합니다. App 클래스의 경우, template() 메서드는 댓글 목록을 반환합니다.
- Component 클래스의 setState() 메서드는 컴포넌트의 상태를 업데이트합니다. App 클래스의 경우, setState() 메서드는 댓글 목록에 새로운 댓글을 추가합니다.
- Component 클래스의 render() 메서드는 컴포넌트를 DOM에 렌더링합니다. App 클래스의 경우, render() 메서드는 댓글 목록을 #app 요소에 렌더링합니다.