생활코딩 React 2022년 개정판 강의(https://opentutorials.org/course/4900)를 듣고 개인 학습용으로 정리한 게시글입니다.
React를 이용하여 CRUD( Create, Read, Update, Delete )기능을 구현한 게시판이다.
예전에 Node.js로 같은 기능을 구현한 적이 있는데, React로 구현하니 더 깔끔한것 같다.
Node.js로 구현했던 CRUD 게시판은 아래 링크를 참고.
https://sirius7.tistory.com/48
React로 구현한 crud 게시판의 소스코드는 다음과 같다.
<App.js>
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';
function Header(props) {
return <header>
<h1><a href="/" onClick={(event)=>{
event.preventDefault();
props.onChangeMode();
}}>{props.title}</a></h1>
</header>
}
function Nav(props) {
const lis = [ ]
for (let i = 0; i < props.topics.length; i++) {
let t = props.topics[i];
lis.push(<li key={t.id}>
<a id={t.id} href={'/read'+t.id} onClick={event=>{
event.preventDefault();
props.onChangeMode(Number(event.target.id));
}}>{t.title}</a>
</li>)
}
return <nav>
<ol>
{lis}
</ol>
</nav>
}
function Article(props) {
return <article>
<h2>{props.title}</h2>
{props.body}
</article>
}
function Create(props) {
return <article>
<h2>글 작성</h2>
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onCreate(title,body)
}}>
<p>제목</p>
<p><input type="text" name="title" placeholder="title"/></p>
<p>내용</p>
<p><textarea name="body" placeholder="body"></textarea></p>
<p><input type="submit" value="작성 완료"/></p>
</form>
</article>
}
function Update(props) {
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>글 수정</h2>
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title,body)
}}>
<p>제목</p>
<p><input type="text" name="title" placeholder="title" value={title} onChange={event=>{
setTitle(event.target.value);
}}/></p>
<p>내용</p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=>{
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="수정 완료"/></p>
</form>
</article>
}
function App() {
const [mode, setMode] = useState('WELCOME');
const [id, setId] = useState(null);
const [nextId, setNextId] = useState(4);
const [topics,setTopics] = useState([
{id:1, title:'Apple', body:'사과'},
{id:2, title:'Banana', body:'맛있다'}
]);
let content = null;
let contextControl = null;
if(mode==="WELCOME"){
content = <Article title="Welcome" body="Hello, web"></Article>
contextControl = <>
<a class="btn" href="/create" onClick={event => {
event.preventDefault();
setMode('CREATE');
}}>글 작성</a>
</>
}
else if (mode === 'READ') {
let title, body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>
contextControl = <>
<a class="btn" href="/create" onClick={event => {
event.preventDefault();
setMode('CREATE');
}}>글 작성</a>
<a class="btn" href={'/update/' + id} onClick={event => {
event.preventDefault();
setMode('UPDATE');
}}>글 수정</a>
<input class="btn" type="button" value="글 삭제" onClick={() => {
const newTopics = []
for (let i = 0; i < topics.length; i++) {
if (topics[i].id !== id) {
newTopics.push(topics[i]);
}
}
setTopics(newTopics);
setMode('WELCOME');
}} />
</>
}
else if (mode === 'CREATE') {
content = <Create onCreate={(_title,_body)=>{
const newTopic = {id:nextId, title:_title,body:_body};
const newTopics = [...topics];
newTopics.push(newTopic);
setTopics(newTopics);
setMode('READ');
setId(nextId);
setNextId(nextId+1);
}}></Create>
}
else if (mode === 'UPDATE') {
let title, body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Update title={title} body={body} onUpdate={(title,body)=>{
const newTopics = [...topics]
const updatedTopic = {id:id, title:title, body:body}
for(let i=0;i<newTopics.length;i++){
if(newTopics[i].id===id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
setMode('READ');
}}></Update>
}
return (
<>
<Header title="React 게시판 구현" onChangeMode={() => {
setMode('WELCOME');
}}></Header>
<div class="background">
<div class="titlebar">글 목록</div>
<div class="content">
<Nav topics={topics} onChangeMode={(_id) => {
setMode('READ');
setId(_id);
}}></Nav>
</div>
<div class="titlebar">글 내용</div>
<div class="content">
{content}
<div class="btncover">
{contextControl}
</div>
</div>
</div>
</>
);
}
export default App;
<App.css>
body {
display: flex;
flex-direction: column;
align-items: center;
background-color: lightgray;
}
.background {
background-color: white;
height: auto;
width: 450px;
}
.titlebar {
background-color: #F9F9F9;
font-weight: 400;
border: none; border-bottom: 1px solid #CCCCCC;
padding: 18px;
}
.content {
padding: 20px;
max-height: max-content;
}
.btncover {
display: flex;
justify-content: center;
padding: 10px;
}
.btn {
font-size: 15px;
text-decoration: none;
text-align: center;
background-color: white;
color: black;
border: 1px solid lightgray;
padding: 5px 10px;
margin: 5px;
display: inline-block;
cursor: pointer;
border-radius: 3px;
}
h1{
text-align: center;
}
h1 a{
color:black;
text-decoration: none;
}
생활코딩 강의에서 나온 내용에서 디자인만 조금 수정한 코드이다.
만들면서 몇가지 주의해야할 점도 배웠다.
state에 저장된 값이 배열이나 객체일때는 다음과 같이 수정한다.
const newTopics = [...topics]
const updatedTopic = {id:id, title:title, body:body}
for(let i=0;i<newTopics.length;i++){
if(newTopics[i].id===id){
newTopics[i] = updatedTopic;
break;
}
}
setTopics(newTopics);
위와 같이, 저장된 값이 배열이나 객체인 경우에는
그 값을 복제한 다음, 복제한 데이터를 수정한다.
그런 다음, 복제한 데이터를 이용해서 값을 바꿔준다.
만약, 복제하지 않고 원래 state에 저장된 배열이나 객체를 수정한 다음
함수를 호출해서 값을 바꾸려고 하면 HTML이 자동으로 다시 랜더링되지 않는다.
객체를 복제하는 방법은 다음과 같다.
newValue = {...value}
배열은 다음과 같이 복제한다.
newValue = [...value]
또한, 이미 저장된 값을 변경할때의 주의사항이 있다.
props로 넘어온 데이터는 수정이 되지 않는다.
그래서 게시글을 수정하는 기능을 구현할 때에는,
props로 넘어온 데이터를 state로 변경한 다음, 아래와 같이 구현할 수 있다.
리액트에서는 값을 입력할때마다 onChange가 실행되기 때문에, 이를 이용한 구현이다.
function Update(props) {
const [title, setTitle] = useState(props.title);
const [body, setBody] = useState(props.body);
return <article>
<h2>글 수정</h2>
<form onSubmit={event=>{
event.preventDefault();
const title = event.target.title.value;
const body = event.target.body.value;
props.onUpdate(title,body)
}}>
<p>제목</p>
<p><input type="text" name="title" placeholder="title" value={title} onChange={event=>{
setTitle(event.target.value);
}}/></p>
<p>내용</p>
<p><textarea name="body" placeholder="body" value={body} onChange={event=>{
setBody(event.target.value);
}}></textarea></p>
<p><input type="submit" value="수정 완료"/></p>
</form>
</article>
}
'WEB > ⚛️ React' 카테고리의 다른 글
[React] 5. fetch 함수 (0) | 2023.02.22 |
---|---|
[React] 3. state (0) | 2023.02.11 |
[React] 2. 컴포넌트, props, event (0) | 2023.02.10 |
[React] 1. 시작하기 (리액트 소개, 설치, 수정, 배포) (0) | 2023.02.07 |