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.js
import 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.js
import 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.js
import 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.js
import 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.jsx
import 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.jsx
import 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.jsx
import React from 'react'
import BlogForm from '../components/BlogForm'
function CreatePage() {
return (
<div>
<BlogForm />
</div>
)
}
export default CreatePage
App.js
수정src/App.js
import 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.js
import 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.js
import 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.js
import 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.jsx
import 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