
๐ฏ React ๊ด๋ จ ๊ฐ๋ (์ปดํฌ๋ํธ, ์ํ, ํ ๋ฑ)์ ์ ๋ฆฌํฉ๋๋ค.
์ฌ์ฌ์ฉ ๊ฐ๋ฅํ UI(User Interface) ์กฐ๊ฐ์ ๋๋ค.
React์์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ์์ ๋ ๊ฐ์ง๊ฐ ์์ต๋๋ค. ํ๋๋ ํด๋์คํ ์ปดํฌ๋ํธ, ๋ค๋ฅธ ํ๋๋ ํจ์ํ ์ปดํฌ๋ํธ์ ๋๋ค.
โน๏ธ ์ปดํฌ๋ํธ๋ ์ด๋ฆ์ ๋ฐ๋์ PascalCase๋ก ์์ฑํด์ผ ํฉ๋๋ค. ๋ง์ฝ ์๋ฌธ์๋ก ์์ํ๋ฉด <div>์ฒ๋ผ HTML ํ๊ทธ๋ก ์ฐฉ๊ฐํ ์ ์๊ธฐ ๋๋ฌธ์ ์ฃผ์๊ฐ ํ์ํฉ๋๋ค.

์ถ์ฒ: React ๊ณต์ ๋ฌธ์
ํด๋์คํ ์ปดํฌ๋ํธ๋ ES6์ ํด๋์ค ๋ฌธ๋ฒ์ ์ฌ์ฉํ์ฌ ์์ฑํ๋ฉฐ, ๋ฐ๋์ render() ๋ฉ์๋๋ฅผ ํฌํจํด์ผ ํฉ๋๋ค. ์ด ๋ฉ์๋ ์์์ UI๋ฅผ JSX๋ก ๋ฐํํฉ๋๋ค.
import { Component } from 'react';
class ClassCom extends Component {
render() {
return <div>ํด๋์คํ ์ปดํฌ๋ํธ</div>;
}
}
export default ClassCom;
ํด๋์คํ ์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ์์์ ๋๋ค.
import ClassCom from './ClassCom';
function App() {
let name = '๋ฆฌ์กํธ';
return (
<div>
<ClassCom></ClassCom>
</div>
);
}
export default App;
ES6์ ํ์ดํ ํจ์๋ ์ผ๋ฐ ํจ์๋ก ์ ์ํ๋ฉฐ, return ๋ฌธ์ผ๋ก JSX๋ฅผ ๋ฐํํฉ๋๋ค.
์ต๊ทผ์๋ React Hooks์ ๋ฑ์ฅ์ผ๋ก ํจ์ํ ์ปดํฌ๋ํธ๊ฐ ํ์ค์ฒ๋ผ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
function FuncCom() {
return <div>ํจ์ํ ์ปดํฌ๋ํธ</div>;
}
export default FuncCom;
ํจ์ํ ์ปดํฌ๋ํธ๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ์์์ ๋๋ค.
import FuncCom from './FuncCom';
function App() {
return (
<div>
<FuncCom></FuncCom>
</div>
);
}
export default App;
state ์ฌ์ฉํ๊ธฐReact์์๋ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๋ฐ๋ ์ ์๋ ๋ฐ์ดํฐ๋ฅผ state๋ผ๊ณ ํฉ๋๋ค.
useState๋ React์์ ์ ๊ณตํ๋ ํ
(hook) ์ค ํ๋๋ก, ๊ฐ์ ์ ์ฅํ ์ ์๋ ๋ณ์ ํ๋์ ๊ทธ ๊ฐ์ ๋ฐ๊พธ๋ ํจ์ ํ๋๋ฅผ ํจ๊ป ๋ฐํํด์ค๋๋ค.
๐ค ํ (Hook)์ด๋?
Hook์ React ๊ธฐ๋ฅ์ ํจ์ํ ์ปดํฌ๋ํธ์์ ์ธ ์ ์๊ฒ ํด์ฃผ๋ ํน๋ณํ ํจ์์ ๋๋ค. React์ ๊ธฐ๋ฅ์ ํจ์ ๋ด๋ถ์ "๊ฑธ์ด์ค๋ค(hook into)"๋ ์๋ฏธ์์ ๋ถ์ฌ์ง ์ด๋ฆ์ ๋๋ค.
useState ์ฌ์ฉ ์์ import React, { useState } from 'react';
const Counter: React.FC = () => {
const [count, setCount] = useState<number>(0);
return (
<div>
<p>ํ์ฌ ์นด์ดํธ: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};
export default Counter;
const [count, setCount] = useState<number>(0) : count๋ ํ์ฌ ์ํ๊ฐ์ ๋ํ๋ด๊ณ , setCount๋ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์์
๋๋ค.
state๊ฐ ๋ฐ๋๋ฉด โ React๊ฐ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์๋์ผ๋ก ๋ค์ ๋ ๋๋งํฉ๋๋ค.onClick={() => setCount(count + 1)} : ๋ฒํผ์ ํด๋ฆญํ ๋๋ง๋ค count ๊ฐ์ 1์ฉ ์ฆ๊ฐ์ํต๋๋ค.
โ ๏ธ
state๋ ์ง์ ์์ ํ์ง ์๊ณ , ๋ฐ๋์setํจ์๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
count = count + 1โ โsetCount(count + 1)โ
[โจ ์ถ๊ฐ ๊ฐ๋ ]
setState์ฌ๋ฌ ๋ฒ ์จ๋ ์ ์ฉ๋์ง ์๋ ์ด์React์์ ์ฑ๋ฅ์ ๋์ด๊ธฐ ์ํด ์ํ ์ ๋ฐ์ดํธ ์์ฒญ๋ค์ ํ์ ๋ชจ์๋๊ณ ํ ๋ฒ์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ 1๋ฒ๋ง ์ ์ฉ์ด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
[์ฝ๋ ์์]
ํด๋น ์ฝ๋๋
+3์ด ๋ ๊ฑฐ ๊ฐ์ง๋ง ์ค์ ๋ก๋+1๋ง ์ํ๋ฉ๋๋ค.const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); setCount(count + 1); setCount(count + 1); }์ด๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์๋ ์ด์ ์ํ์์ ์ ๋ฐ์ดํธํ๋ ํ์์ผ๋ก ๋ฐ๊พธ์ด์ผ ํฉ๋๋ค.
function handleClick() { setCount(prev => prev + 1); setCount(prev => prev + 1); setCount(prev => prev + 1); }๐ ์ฐธ๊ณ ๊ณต์ ๋ฌธ์
import { useState } from 'react';
import { Button } from 'react-bootstrap';
type Todo = {
id: number;
text: string;
isChecked: boolean;
};
const TodoList: React.FC = () => {
const title: string = '์ค๋ ํ ์ผ';
// ํ ์ผ ๋ชฉ๋ก ์ํ๊ฐ (์ด๊ธฐ๊ฐ 3๊ฐ๋ก ์์)
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: '๊ณต๋ถํ๊ธฐ', isChecked: false },
{ id: 2, text: '์ ์๊ธฐ', isChecked: false },
{ id: 3, text: '๋ฏธํ
ํ๊ธฐ', isChecked: false },
]);
const [newTodo, setNewTodo] = useState<string>('');
const [showDetail, setShowDetail] = useState<boolean>(false);
const [selectedTodo, setSelectedTodo] = useState<Todo | null>(null);
// ์ฒดํฌ๋ฐ์ค ์ํ๋ฅผ ํ ๊ธํ๋ ํจ์
const handleCheckedChange = (itemId: number) => {
setTodos((preItems) =>
preItems.map((item) =>
item.id === itemId ? { ...item, isChecked: !item.isChecked } : item
)
);
};
// ์ ํ ์ผ์ ์ถ๊ฐํ๋ ํจ์
const addTodo = () => {
if (newTodo.trim() !== '') {
setTodos([
...todos,
{
id: Date.now(),
text: newTodo,
isChecked: false,
},
]);
setNewTodo('');
}
};
// ํ ์ผ์ ์ญ์ ํ๋ ํจ์
const removeTodo = (id: number) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
// ํ ์ผ ํด๋ฆญ ์ ์์ธ๋ณด๊ธฐ ์ํ ์ค์
const handleTodoClick = (todo: Todo) => {
setShowDetail(true);
setSelectedTodo(todo);
};
// ์์ธ๋ณด๊ธฐ ๋ซ๊ธฐ
const handleCloseDetail = () => {
setShowDetail(false);
};
return (
<div>
<h1>{title}</h1>
<div className='container'>
{/* ์
๋ ฅ์ฐฝ + ์ถ๊ฐ ๋ฒํผ */}
<div>
<input
type='text'
placeholder='ํ ์ผ ์
๋ ฅ'
style={{ marginRight: '10px', writingMode: 'horizontal-tb' }}
onChange={(e) => {
setNewTodo(e.target.value);
}}
/>
<Button variant='success' onClick={addTodo}>
์ถ๊ฐ
</Button>
</div>
{/* ํ ์ผ ๋ฆฌ์คํธ */}
<div className='board'>
<ul>
{todos.map((todo, index) => (
<li key={todo.id}>
<input
type='checkbox'
onChange={() => {
handleCheckedChange(todo.id);
}}
/>
<span onClick={() => handleTodoClick(todo)}>
{todo.isChecked ? <del>{todo.text}</del> : todo.text}
</span>
<button
onClick={() => removeTodo(todo.id)}
className='delbutton'
>
์ญ์
</button>
</li>
))}
</ul>
</div>
</div>
</div>
);
};
export default TodoList;
ํ ์ผ ์ฒดํฌ๋ฐ์ค(handleCheckedChange)
isChecked์ ๊ฐ์ ๋
ผ๋ฆฌ๊ฐ์ ๋ฐ์ ํด์ค๋๋ค. ํ ์ผ ์ถ๊ฐ(addTodo)
์
๋ ฅ๊ฐ์ด ๋น์ด์์ง ์์ผ๋ฉด, ์ ํญ๋ชฉ์ todos ๋ฐฐ์ด์ ์ถ๊ฐํฉ๋๋ค
trim()์ ํตํด ๊ณต๋ฐฑ๋ง ์
๋ ฅ๋ ๊ฒฝ์ฐ๊น์ง ์ ํํฉ๋๋ค.
showDetail/ selecyedTodo) ์ถํ์ ๊ตฌํํฉ๋๋ค.๐ ๋ฆฌ์กํธ ๋ถํธ์คํธ๋ฉ getting started

1๏ธโฃ npm์ผ๋ก react-bootstrap์ ์ค์นํฉ๋๋ค.
npm install react-bootstrap bootstrap
2๏ธโฃ index.tsx ํ์ผ์ css๋ฅผ ๋ถ๋ฌ์ต๋๋ค
import 'bootstrap/dist/css/bootstrap.min.css';
๋๋ CDN์ผ๋ก ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/>
import { Form, Button } from 'react-bootstrap';
<Form>
<Form.Group className="mb-3" controlId="todoInput">
<Form.Label>ํ ์ผ ์
๋ ฅ</Form.Label>
<Form.Control type="text" placeholder="ํ ์ผ์ ์
๋ ฅํ์ธ์" />
</Form.Group>
<Button variant="success">์ถ๊ฐ</Button>
</Form>
React์ ํ ์ ๋ํด์ ์์ง์ ๋ฏ์ค์ด์ ๊ณ์ ์ ์ด๋ณด๋ฉด์ ์ฐ์ตํด์ผ๊ฒ ๋ค.
