임도현의 성장
React Component와 props 본문
🧐Component란?
리액트는 화면에서 UI 요소를 구분할 때 컴포넌트라는 단위를 사용합니다. 쉽게 말하면 리액트에서 앱을 이루는 가장 작은 조각이라고 할 수 있고 레고 블록으로 집을 쌓게 된 경우 하나의 블록이 컴포넌트라고 할 수 있습니다.함수형 컴포넌트는 기본적으로 props를 통해 부모 컴포넌트에서 데이터를 전달받고, 필요하면 React Hooks를 사용해 state와 같은 추가적인 기능을 구현할 수 있습니다.
👪 Props란?
Props는 컴포넌트 간에 데이터를 전달하는 도구입니다. 실제 프로젝트에서는 Props를 활용하여 데이터를 컴포넌트 계층 구조에 따라 전달하며 이를 통해 앱의 UI를 동적으로 관리합니다. 부모 state를 자식에게 전달하는 기본 흐름은
- 부모 컴포넌트에서 state와 setState를 정의.
- 이를 자식 컴포넌트에 props로 전달
- 자식 컴포넌트는 전달받은 props로 부모의 state를 읽거나 업데이트를 가능하게 만듭니다.
👀예제 코드
내가 만든 TodoList이다. 하나에 페이지에 TodoList코드를 작성하면 너무 길어지기때문에 나중에 유지보수 하기가 어려워 진다. 벌써 프로젝트 생각하면 어디부터 손을 대야 할지 모르겠다.
import React, { useState } from 'react';
import './App.css';
function App() {
const [tasks, setTasks] = useState([]); // 할 일 목록
const [input, setInput] = useState(""); // 입력 필드 값
const addTodo = () =>{
setTasks([...tasks, { id: Date.now(), text: input, completed: false }]);
setInput('');
};
const toggleComplete = (id) => {
console.log('toggle = ' + id);
setTasks(
tasks.map((task) =>
task.id === id ? { ...task, completed: !task.completed } : task
)
);
}
const deleteTask = (id) => {
console.log('deldte = ' + id);
setTasks(tasks.filter((task) => task.id !== id));
}
return (
<div className='container'>
<div className='todoBlock'>
<div className='title'>
<h1>TodoList</h1>
</div>
<div style={{display:'flex', height:'35px'}}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
style={ {flex : '10', padding : '5'}}
placeholder='입력하세요'
/>
<button onClick={addTodo} style={ {flex : '1'}}>등록</button>
</div>
{tasks.map((data) => (
<div key={data.id} style={{ textDecoration: data.completed ? "line-through" : "none" }} className='aaa'>
<p>
<input type='checkbox' defaultChecked={false}
onChange={() => toggleComplete(data.id)}
/>
{''}{data.text}
<button onClick={() => deleteTask(data.id)} className='btn-cloes'>X</button>
</p>
</div>
))}
</div>
</div>
)
}
export default App;
📌Component 분리
밑에 완성된 TodoList를 보면 각자의 역할이 있는것이 보인다. Component 분리 기준은 재사용성, 단일 책임 원칙, 가독성, 상태와 라이프사이클 들을 고려해서 분리를 한다. 위 기준들을 생각하며 나는 TodoList 등록 폼 하고 리스트들을 분리 하기로 했다.
🥕App.js
컴포넌트들을 분리하니깐 코드의 가독성이 좋아졌으면 코드가 깔끔하게 작성되어 나중에 유지보수 할때 편리해 졌습니다. Form 컴포넌트와 List 컴포넌트 에서 할일 목록을 추가하고 리스트들을 보여줘야 하기 때문에 부모 컴포넌트에서 자식 컴포넌트로 전달 해야 합니다. React에서는 props를 통해 부모 상태를 자식에게 전달할 수 있습니다.
import React, { useState } from 'react';
import Form from './component/Form';
import List from './component/List';
function App() {
const [tasks, setTasks] = useState([]); // 할 일 목록
return (
<div className='container'>
<div className='todoBlock'>
<div className='title'>
<h1>TodoList</h1>
</div>
// 자식 컴포넌트에 props 전달
<Form tasks={tasks} setTasks={setTasks} />
<List tasks={tasks} setTasks={setTasks} />
</div>
</div>
)
}
export default App;
👏등록 폼 Component
부모 컴포넌트에서 받은 props을 받아서 부모 State를 변경 해주었습니다. React에서는 setState 함수가 부모의 상태를 변경할 수 있는 권한을 제공합니다. props로 전달되는 setState는 단순히 "수정 기능"을 가진 함수라고 생각하면 됩니다.
import React, { useState } from 'react';
const Form = ({ tasks, setTasks }) => { // 부모 props를 받음
const [input, setInput] = useState(""); // 입력 필드 값
const addTodo = () =>{
setTasks([...tasks, { id: Date.now(), text: input, completed: false }]);
setInput('');
};
return (
<div style={{display:'flex', height:'35px'}}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
style={ {flex : '10', padding : '5'}}
placeholder='입력하세요'
/>
<button onClick={addTodo} style={ {flex : '1'}}>등록</button>
</div>
);
};
export default Form;
👻리스트 Component
리스트 컴포넌트에서는 props를 받아서 부모의 tasks 상태값을 꺼내서 리스트를 보여주고 삭제 하기 위해서 setTasks를 이용해서 삭제해주어 부모 컴포넌트 state에 적용이 되었다.
import React from 'react';
const List = ({ tasks, setTasks }) => {// 부모 props를 받음
const toggleComplete = (id) => {
console.log('toggle = ' + id);
setTasks(
tasks.map((task) =>
task.id === id ? { ...task, completed: !task.completed } : task
)
);
};
const deleteTask = (id) => {
console.log('deldte = ' + id);
setTasks(tasks.filter((task) => task.id !== id));
};
return (
<div>
{tasks.map((data) => (
<div key={data.id} style={{ textDecoration: data.completed ? "line-through" : "none" }} className='aaa'>
<p>
<input type='checkbox' defaultChecked={false}
onChange={() => toggleComplete(data.id)}
/>
{''}{data.text}
<button onClick={() => deleteTask(data.id)} className='btn-cloes'>X</button>
</p>
</div>
))}
</div>
);
};
export default List;
🤔내 생각 정리
컴포넌트 덕분에 아주 길었던 코드들을 분리 해주어 가독성이 좋아졌고 분리한 컴포넌트들은 재사용을 할 수 있다는 장점이 있으며 컴포넌트는 역할과 책임을 명확히 분리하여 나중에 유지보수 할때도 간편하게 수정 할 수 있을거 같다. 나는 자바 스프링 부트를 공부하였기때문에 객체지향이 재밌는데 컴포넌트도 그런 느낌을 주는거 같아 재밌다.
'React' 카테고리의 다른 글
React State와 Virtual DOM (0) | 2024.12.29 |
---|