컴포넌트 합성은 여러 개의 작은 컴포넌트를 조합하여 더 큰 기능을 수행하는 컴포넌트를 만드는 방법을 의미한다. 분리된 컴포넌트를 사용하는 쪽에서 조합해서 사용하는 방법이다. 컴포넌트 합성을 통해서 코드의 재사용성을 높이고 유지보수를 용이하게 할 수 있다. 컴포넌트 합성 시에 중요한 것은 단일 책임 원칙, 즉 각 컴포넌트는 하나의 기능만을 담당해야한다.
컴포넌트 합성 예제
한 예시로 React로 TodoList를 구현한다고 했을 때,
- TodoInput이라는 컴포넌트는 등록을 하는 기능을 가지고 있고
- TodoItem은 각 Todo의 항목을 표시하고 수정 및 완료 버튼을 제공한다. 각 Todo항목을 관리하는 기능을 가지고 있다.
- TodoEdit는 TodoItem에서 Todo의 수정 기능을 가지고 있다.
- TodoInput과 TodoItem을 조합하여 TodoApp 전체를 구성하게 된다. TodoApp에서 상태를 관리하여 Todo 항목을 추가하고 삭제 및 완료하는 기능을 제공한다.
아래는 해당 내용에 관련된 리액트 코드이다.
1. TodoInput 컴포넌트 : 새로운 Todo 항목을 입력하고 해당 값을 전달하여 Todos에 추가하는 기능을 가지고 있다.
- 새로 추가되는 todo의 text state를 가지고 있고, 추가하는 기능을 props로 가져와 핸들링 한다.
import { useState } from "react";
export default function TodoInput({handleAddTodo}){
const [text, setText] = useState("");
const handleOnClick = () => {
handleAddTodo(text);
setText("")
}
return(
<div>
<input type="text" value={text} onChange={(e) => setText(e.target.value)}/>
<button onClick={handleOnClick}>추가</button>
</div>
)
}
2. TodoItem 컴포넌트 : 각 Todo 항목을 관리하는 컴포넌트로, 각 Todo와 관련된 기능(수정)은 해당 컴포넌트에 작성된다.
- TodoEdit의 부모 컴포넌트로, 수정과 관련된 state와 기능을 해당 컴포넌트에 작성하여 TodoEdit 컴포넌트에 props로 전달한다.
- Todos와 관련된 삭제 / 완료 / 수정과 관련된 기능을 부모 컴포넌트로 받아 해당 컴포넌트에서 핸들링 한다.
import { useState } from "react";
import TodoEdit from "./TodoEdit";
export default function TodoItem({ todo, index, handleDeleteTodo, handleCompleteTodo, handleEditTodo }) {
// 수정하는 내용에 대한 state를 갖는다.
const [isEditable, setIsEditable] = useState(false);
// 수정버튼을 클릭했을 시에 isEditable true로 변경
const toggleEdit = () => {
setIsEditable(true);
}
const handleEditSubmit = (editedText) => {
handleEditTodo(index, editedText);
setIsEditable(false);
};
return (
<div>
{/* isEditable이 true일 경우에는 TodoEdit 컴포넌트 호출*/}
{isEditable ?
<TodoEdit text={todo.text} onEditSubmit={handleEditSubmit} />
:
<>
{/* todo객체에 isCompleted가 true일 경우에는 중간줄 표시 */}
< h2 style={{ textDecoration: todo.isCompleted ? "line-through" : "none" }}>{todo.text}</h2>
<button onClick={toggleEdit}>수정</button>
{/* 완료버튼 클릭시에 completedTodo가 실행되어 todo 객체 안에 isCompleted가 true로 변경 */}
<button onClick={() => handleCompleteTodo(index)}>완료</button>
{/* 삭제버튼 클릭시에 deleteTodo가 실행되어 filter를 통해 해당 인덱스 삭제 */}
<button onClick={() => handleDeleteTodo(index)}>삭제</button>
</>
}
</div >
)
}
3. TodoEdit 컴포넌트 : TodoItem의 하위 컴포넌트로, 각 Todo의 수정과 관련된 기능은 해당 컴포넌트에 작성된다.
- 상위 컴포넌트에서 todo의 text와 수정과 관련된 기능을 props로 받아 수정 후에 function의 매개변수를 통해 전달한다.
import { useState } from "react";
export default function TodoEdit({ text, onEditSubmit }) {
const [editedText, setEditedText] = useState(text);
return (
<div>
<input
type="text"
value={editedText}
onChange={(e) => setEditedText(e.target.value)}
/>
<button onClick={() => onEditSubmit(editedText)}>수정완료</button>
</div>
);
}
4. TodoApp 컴포넌트 : 전체적인 Todos를 관리하는 컴포넌트로 Todos와 관련된 기능(추가, 삭제, 완료, 수정)들은 해당 컴포넌트에서 작성되어 하위 컴포넌트로 props를 통해 전달된다.
import { useState } from 'react';
import './App.css';
import TodoItem from './components/TodoItem';
import TodoInput from './components/TodoInput';
function App() {
// App에서는 Todo의 집합(todo의 내용과 수정여부)에 대한 state와, 각 Todo의 내용에 대한 state를 갖는다.
const [todos, setTodos] = useState([]);
// App에서는 Todo 항목을 추가 / 삭제 / 완료의 기능을 제공한다.
// 추가
const addTodo = (todoText) => {
setTodos([...todos, { text: todoText, isCompleted: false, isEditable: false}]);
}
//삭제
const deleteTodo = (index) => {
// todos의 각 아이템들의 인텍스와 비교해서, 인덱스가 다른 아이템들을 모아 새로운 배열로 생성한다.
setTodos(todos.filter((_, todoIdx) => todoIdx !== index));
}
//완료
const completeTodo = (index) => {
const newTodo = [...todos];
newTodo[index].isCompleted = true;
setTodos(newTodo);
}
// 수정
const editTodo = (index, newText) => {
const newTodos = [...todos];
newTodos[index].text = newText;
setTodos(newTodos);
};
return (
<>
{/* TodoInput에 보낼 props : addTodo */}
<TodoInput handleAddTodo={addTodo} />
{/* TodoItem에 보낼 props는 각 todo와 index, deleteTodo, completeTodo, editTodo */}
{todos.map((todo, index) => (
<TodoItem
key={index}
todo={todo}
index={index}
handleDeleteTodo={deleteTodo}
handleCompleteTodo={completeTodo}
handleEditTodo={editTodo}/>
))}
</>
);
}
export default App;
'Frontend > React' 카테고리의 다른 글
React : Lazy import을 통한 성능 개선 (0) | 2024.09.05 |
---|---|
React: useReducer에 대해서 (0) | 2024.09.05 |
React: React에서 Styled Component 사용하기 (0) | 2024.09.04 |
React: useEffect에 대해서 (1) | 2024.09.03 |
React에서 Web Component 사용하기 (0) | 2024.08.30 |
React: portal에 대해서 (0) | 2024.08.29 |
React : useRef에 대해서 (0) | 2024.08.29 |
React: 컴포넌트에 CSS 적용하기 (1) | 2024.08.28 |