안녕하세요. 각성한 데브키라입니다. 리액트를 활용하여 동적으로 글을 생성하고 관리하는 기능을 구현하는 것은 매우 유용한 작업입니다. 특히, 사용자가 직접 글을 입력하고 이를 편집하거나 삭제할 수 있는 기능은 다양한 웹 애플리케이션에서 필수적인 요소입니다. 이번 포스트에서는 글 생성 기능을 구현하는 방법을 단계별로 설명하고, 이를 통해 리액트의 상태 관리와 컴포넌트 구성에 대해 이해해보겠습니다.
Step 1. 글생성버튼 클릭 - App.js
먼저, 글 생성 버튼을 클릭하면 `mode` 상태가 `CREATE`로 변경되도록 설정합니다. 이는 `App.js` 파일에서 구현됩니다. 링크를 클릭했을 때, `setMode` 함수를 호출하여 `CREATE` 상태로 변경합니다.
<a class="action-link" href="/create" onClick={event=>{
event.preventDefault();
setMode('CREATE');
}}>추가</a>
Step 2. 별도로 분리된 Create컴포넌트
다음으로, 글을 생성할 때 사용되는 Create 컴포넌트를 작성합니다. 이 컴포넌트는 사용자가 입력한 제목과 본문을 받아서 처리하는 폼을 포함합니다. 폼이 제출되면 props로 전달된 onCreate 함수를 호출하여 글을 생성합니다.
function Create(props){
return <article>
<h2>Create</h2>
<form onSubmit={e=>{
e.preventDefault();
const title = e.target.title.value;
const body = e.target.body.value;
props.onCreate(title, body);
}}>
<p><input type='text' name='title' placeholder='title'/></p>
<p><textarea name='body' placeholder='body'/></p>
<p><input type='submit' value='전송'/></p>
</form>
</article>
}
Step 3. 글생성 이벤트를 받아서 처리
- CREATE 상태로 변경된 후, App 컴포넌트가 다시 렌더링됩니다.
- mode가 CREATE일 때, Create 컴포넌트를 화면에 표시합니다.
- 사용자가 글을 입력하고 전송 버튼을 클릭하면 onCreate 이벤트가 발생합니다.
- onCreate 함수에서 새로운 글을 생성하고, topics 상태에 추가합니다.
- 글이 추가된 후, mode를 READ로 변경하여 새로 추가된 글의 상세 페이지를 표시합니다.
중요: 아래 소스코드의 const list = [...topics];부분 처럼 상태 변수를 다룰 때, 변수의 값이 객체 형태일 경우 ...을 사용하여 복제본을 만들어 할당하는 것이 권장됩니다.
이러한 방식을 사용하는 이유는 상태 값을 직접 수정하지 않고 새로운 값을 생성하여 업데이트함으로써, 리액트의 불변성 원칙을 준수할 수 있기 때문입니다. 불변성 원칙을 지키면 리액트가 상태 변경을 감지하고 컴포넌트를 올바르게 리렌더링하는 데 도움이 됩니다. 이 방법은 특히 상태 관리에서 예상치 못한 버그를 방지하고, 성능 최적화에 크게 기여할 수 있습니다.
}else if(mode === "CREATE"){
content = <Create onCreate={(title, body)=>{
const newId = topics.length;
const item = {id:newId, title:title, body:body};
const list = [...topics];
list.push(item);
setTopics(list);
setId(newId);//상세정보출력을 위해서 새로추가되는 글의 id가 무엇인지 알려줍니다.
setMode("READ");//목록이 추가되고 추가된 내용의 상세페이지를 보여주기 위해서 READ모드로 변경
}}></Create>
}
Step 4: 최종 코드 정리
다음은 App.js전체 코드를 정리한 예제입니다. 이를 통해 글 생성 기능을 완전히 구현할 수 있습니다.
import './App.css';
import {useState} from 'react';
function Header(props){
console.log(props);
console.log(props.title);
return(
<header>
<h1>
<a href="/" onClick={(e)=>{
e.preventDefault();//기본 이벤트의 동작을 막아줌
props.onChangeMode();
}}>
{props.title}
</a>
</h1>
</header>
)
}
function Article(porps){
return <article>
<h2>[ {porps.title} ]</h2>
<p>{porps.id}</p>
<p>{porps.title}</p>
<p>{porps.body}</p>
</article>
}
function Nav(props){
const list = [];
for(let i=0; i < props.topics.length; i++){
console.log(props.topics[i].title, props.topics[i].id);
let t = props.topics[i];
list.push(<li key={t.id}>
<a id={t.id} href={'/read/'+t.id} onClick={e=>{
e.preventDefault();
props.onChangeMode(Number(e.target.id));
}}>{t.title} (id:{t.id})</a>
</li>)
}
return <nav>
<ol>
{list}
</ol>
</nav>
}
function Create(props){
return <article>
<h2>Create</h2>
<form onSubmit={e=>{
e.preventDefault();
const title = e.target.title.value;
const body = e.target.body.value;
props.onCreate(title, body);
}}>
<p><input type='text' name='title' placeholder='title'/></p>
<p><textarea name='body' placeholder='body'/></p>
<p><input type='submit' value='전송'/></p>
</form>
</article>
}
function App() {
const [mode, setMode] = useState('WELCOME');
const [id, setId] = useState(null);
const [topics, setTopics] = useState([
{id: 0, "title":"블랙핑크", body:"블랙핑크 good!"},
{id: 1, "title":"아이브", body:"아이브 good!"},
{id: 2, "title":"르세라핌", body:"르세라핌 good!"},
{id: 3, "title":"뉴진스", body:"뉴진스 good!"},
{id: 4, "title":"트와이스", body:"트와이스 good!"},
{id: 5, "title":"레드벨벳", body:"레드벨벳 good!"},
{id: 6, "title":"에스파", body:"에스파 good!"}
]);
let content = null;
if(mode === "WELCOME"){
content = <Article title="Welcome" body="Hello, WEB"></Article>
}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 id={id} title={title} body={body}></Article>
}else if(mode === "CREATE"){
content = <Create onCreate={(title, body)=>{
const newId = topics.length;
const item = {id:newId, title:title, body:body};
const list = [...topics];
list.push(item);
setTopics(list);
setId(newId);//상세정보출력을 위해서 새로추가되는 글의 id가 무엇인지 알려줍니다.
setMode("READ");//목록이 추가되고 추가된 내용의 상세페이지를 보여주기 위해서 READ모드로 변경
}}></Create>
}
return (
<div>
<Header title="WEB" onChangeMode={()=>{
setMode("WELCOME");
}}></Header>
<Nav topics={topics} onChangeMode={(id)=>{
setMode("READ");
setId(id);
}}></Nav>
{content}
<br/>
<a class="action-link" href="/create" onClick={event=>{
event.preventDefault();
setMode('CREATE');
}}>추가</a>
</div>
);
}
export default App;
이처럼 리액트를 활용하여 동적으로 글을 생성하는 기능을 구현하는 과정에서 상태 관리와 컴포넌트 간의 데이터 전달 방식을 이해할 수 있습니다. 이러한 기초적인 기능 구현을 통해 더 복잡한 애플리케이션을 개발하는 데 필요한 기초를 다질 수 있습니다. 앞으로 리액트를 사용하여 다양한 기능을 구현해보세요.
[ 리액트 입문강좌 시리즈 ]
01. React 설치와 초기화면 출력
02. 리액트 배포본 생성을 위한 npm run build
03. 리액트의 꽃 사용자정의 태그
04. 컴포넌트의 섬세한 활용을 위한 props속성 사용
05. 리스트데이터의 활용 topics변수 사용
06.사용자 정의 이벤트 구현
07.리스트 형태의 사용자 정의 이벤트 구현
08. React useState훅을 이용한 상태에 따른 UI표현
09. 리액트 토픽변수를 useState 훅을 이용한 글입력
10. 리액트에서 동적으로 글 생성하기
11. 리액트에서 동적으로 글 수정하기
12. 리액트에서 동적으로 글 삭제하기 삭제버튼
'REACT' 카테고리의 다른 글
리액트 12: 리액트에서 동적으로 글 삭제하기 (75) | 2024.05.29 |
---|---|
리액트 11: 리액트에서 동적으로 글 수정하기 (2) | 2024.05.29 |
리액트 09: 리액트 토픽변수를 useState 훅을 이용한 글입력 (106) | 2024.05.19 |
리액트 08: React useState훅을 이용한 상태에 반응하는 UI표현 (1) | 2024.05.19 |
리액트 07: 리스트 형태의 사용자 정의 이벤트 구현 (2) | 2024.05.19 |