Title과 Content를 작성할 수 있는 간단한 폼을 만들고 DB에 저장해보자.
사용하는 패키지
- bootstrap 5.3.0
- react-router-dom v6
- axios
- json-server
title과 setTitle이라는 두 가지 변수를 useState 훅을 사용하여 선언title은 현재 입력된 글의 제목을 저장하는 상태setTitle은 title 상태를 업데이트하는 함수input 요소를 생성value 속성을 통해 title 상태를 입력값으로 설정onChange 이벤트 핸들러를 통해 입력 값이 변경될 때마다 setTitle 함수를 호출하여 title 상태를 업데이트src/App.jsimport React from 'react'
import { useState } from 'react';
function App() {
const [title, setTitle] = useState('');
return (
<div className='container'>
<div className='mb-3'>
<label className='form-label'>Title</label>
<input
className='form-control'
value={title}
onChange={(event) => {
setTitle(event.target.value)
}}
/>
</div>
<button className='btn btn-primary'>Post</button>
</div>
)
}
export default App;
src/App.jsimport React from 'react'
import { useState } from 'react';
function App() {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
return (
<div className='container'>
<div className='mb-3'>
<label className='form-label'>Title</label>
<input
className='form-control'
value={title}
onChange={(event) => {
setTitle(event.target.value)
}}
/>
</div>
<div className='mb-3'>
<label className='form-label'>Body</label>
<textarea
className='form-control'
value={body}
onChange={(event) => {
setBody(event.target.value)
}}
/>
</div>
<button className='btn btn-primary'>Post</button>
</div>
)
}
export default App;
src/App.jsimport React from 'react'
import { useState } from 'react';
function App() {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const onSubmit = () => {
console.log(title, body)
}
return (
<div className='container'>
<div className='mb-3'>
<label className='form-label'>Title</label>
<input
className='form-control'
value={title}
onChange={(event) => {
setTitle(event.target.value)
}}
/>
</div>
<div className='mb-3'>
<label className='form-label'>Body</label>
<textarea
className='form-control'
value={body}
onChange={(event) => {
setBody(event.target.value)
}}
rows={20}
/>
</div>
<button
className='btn btn-primary'
onClick={onSubmit}
>Post</button>
</div>
)
}
export default App;
npm install -g json-server
설치 확인

프로젝트 루트 폴더에 db.json 파일 생성하기

db.json
오류 시 관리자 버전으로 다시 설치 후 실행할 것
sudo npm install -g json-server
json-server --watch db.json --port 3001

$ npm install axios
src/App.jsimport React from 'react'
import { useState } from 'react';
import axios from 'axios';
function App() {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const onSubmit = () => {
axios.post('http://localhost:3001/posts', {
title: title,
body: body
})
}
return (
<div className='container'>
<div className='mb-3'>
<label className='form-label'>Title</label>
<input
className='form-control'
value={title}
onChange={(event) => {
setTitle(event.target.value)
}}
/>
</div>
<div className='mb-3'>
<label className='form-label'>Body</label>
<textarea
className='form-control'
value={body}
onChange={(event) => {
setBody(event.target.value)
}}
rows={20}
/>
</div>
<button
className='btn btn-primary'
onClick={onSubmit}
>Post</button>
</div>
)
}
export default App;



참고할만한 링크
json-server --watch db.json --port 3001
package.json 파일의 scripts 항목에 db라는 이름으로 명령어를 넣는다.
npm run db
npm install react-router-dom

BlogForm이라는 컴포넌트로 따로 빼서 작성src/components/BlogForm.jsximport React from 'react'
import { useState } from 'react';
import axios from 'axios';
function BlogForm() {
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const onSubmit = () => {
axios.post('http://localhost:3001/posts', {
title: title,
body: body
})
}
return (
<div>
<h1>Create a blog post</h1>
<div className='mb-3'>
<label className='form-label'>Title</label>
<input
className='form-control'
value={title}
onChange={(event) => {
setTitle(event.target.value)
}}
/>
</div>
<div className='mb-3'>
<label className='form-label'>Body</label>
<textarea
className='form-control'
value={body}
onChange={(event) => {
setBody(event.target.value)
}}
rows={20}
/>
</div>
<button
className='btn btn-primary'
onClick={onSubmit}
>Post</button>
</div>
)
}
export default BlogForm
src/components/Navbar.jsximport React from 'react'
import {Link} from 'react-router-dom';
function NavBar() {
return (
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<Link className="navbar-brand" to="/">Home</Link>
<ul className="navbar-nav">
<li className="nav-item">
</li>
</ul>
</div>
</nav>
)
}
export default NavBar
CreatePage에는 위에서 만든 BlogForm 컴포넌트 넣기src/pages/CreatePage.jsximport React from 'react'
import BlogForm from '../components/BlogForm'
function CreatePage() {
return (
<div>
<BlogForm />
</div>
)
}
export default CreatePage
App.js 수정src/App.jsimport React from 'react'
import {
BrowserRouter as Router,
Routes,
Route,
Link
} from 'react-router-dom';
// components
import NavBar from './components/NavBar';
// pages
import HomePage from './pages/HomePage';
import CreatePage from './pages/CreatePage';
import EditPage from './pages/EditPage';
import ListPage from './pages/ListPage';
function App() {
return (
<Router>
<NavBar/>
<div className='container'>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/blogs" element={<ListPage />} />
<Route path="/blogs/create" element={<CreatePage />} />
<Route path="/blogs/edit" element={<EditPage />} />
</Routes>
</div>
</Router>
)
}
export default App;
routes.js 파일을 만들어 라우트 정보들을 담은 파일 따로 만들고,App.js 에서는 map 함수를 이용하여 routes 파일의 route 들을 하나씩 불러와서 Route 컴포넌트 출력src/routes.jsimport HomePage from './pages/HomePage';
import CreatePage from './pages/CreatePage';
import EditPage from './pages/EditPage';
import ListPage from './pages/ListPage';
const routes = [
{
path:'/',
element: <HomePage />
},
{
path:'/blogs',
element: <ListPage />
},
{
path:'/blogs/create',
element: <CreatePage />
},
{
path:'/blogs/edit',
element: <EditPage />
},
]
export default routes;
src/App.jsimport React from 'react'
import {
BrowserRouter as Router,
Routes,
Route,
Link
} from 'react-router-dom';
// components
import NavBar from './components/NavBar';
// pages
import HomePage from './pages/HomePage';
import CreatePage from './pages/CreatePage';
import EditPage from './pages/EditPage';
import ListPage from './pages/ListPage';
// routes
import routes from './routes';
function App() {
return (
<Router>
<NavBar/>
<div className='container'>
<Routes>
{routes.map((route) => {
return <Route path={route.path} element={route.element} />
})}
</Routes>
</div>
</Router>
)
}
export default App;

src/App.jsimport React from 'react'
import {
BrowserRouter as Router,
Routes,
Route,
Link
} from 'react-router-dom';
// components
import NavBar from './components/NavBar';
// pages
import HomePage from './pages/HomePage';
import CreatePage from './pages/CreatePage';
import EditPage from './pages/EditPage';
import ListPage from './pages/ListPage';
// routes
import routes from './routes';
function App() {
return (
<Router>
<NavBar/>
<div className='container'>
<Routes>
{routes.map((route) => {
return <Route key={route.path} path={route.path} element={route.element} />
})}
</Routes>
</div>
</Router>
)
}
export default App;

src/components/NavBar.jsximport React from 'react'
import {Link, NavLink} from 'react-router-dom';
function NavBar() {
return (
<nav className="navbar navbar-dark bg-dark">
<div className="container">
<Link className="navbar-brand" to="/">Home</Link>
<ul className="navbar-nav">
<li className="nav-item">
<NavLink
className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
aria-current="page"
to="/blogs">
Blogs</NavLink>
</li>
<li className="nav-item">
<NavLink
className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
aria-current="page"
to="/blogs/create">
Create</NavLink>
</li>
</ul>
</div>
</nav>
)
}
export default NavBar
