이번주는 React를 사용해서 간단한 일기장 구현 프로젝트가 진행된다
일기장 기능에는 CRUD 가 전부 포함되어 있기 때문에 이번 간단한 프로젝트에서 확실하게 배우면
나중에 더 크고 복잡한 프로젝트를 할 때 도움이 될 수 있을 것이다
기본기를 탄탄하게 잡고 시작한다는 느낌으로 이번 강의도 열심히 듣고 따라하고 정리해보겠다
# 프로젝트 소개
간단한 일기장 프로젝트를 통해 React의 사용법을 배워보자
Point 1. 사용자 입력 및 배열 리스트 처리하기
Point 2. React Lifecycle과 API
Point 3. React App 프로처럼 성능 최적화하기 with 도구 사용
Point 4. React 컴포넌트 트리에 전역 데이터 공급하기
# React 에서 사용자 입력 처리하기
npx create-react-app simplediary
로 새로운 리액트 프로젝트 생성하기
프로젝트 생성이 완료되면 필요없는 파일들은 삭제한다
다이어리를 입력할 수 있는 DiaryEditor 컴포넌트를 생성한 후 App.js 의 자식 컴포넌트로 위치시킨다
import "./App.css";
import DiaryEditor from "./DiaryEditor";
function App() {
return (
<div className="App">
<h2>일기장</h2>
<DiaryEditor />
</div>
);
}
export default App;
DiaryEditor 컴포넌트가 필요한 것은 다음과 같다
1. DiaryEditor에서 작성자를 입력받는 input 창 만들기
import React, { useState } from "react";
const DiaryEditor = () => {
//작성자 초기값 설정
const [author, setAuthor] = useState("");
return (
<div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input
value={author}
onChange={(e) => {
console.log(e);
}}
/>
</div>
</div>
);
};
export default DiaryEditor;
useState를 사용해서 초기값을 설정해준다
input 의 value로 author를 지정해주면 useState에 입력된 값이 author로 저장된다
지금 현재는 "" 로 설정해놓았기 때문에 입력이 되지 않는다
따라서 onChange 이벤트를 사용해서 값이 변경될 때마다 setAuthor 를 통해 author 값을 변경해주어야 한다
console.log(e) 로 화면 변화를 감지해보니 input 에 값이 입력될 때마다 다음과 같이 console 이 찍힌다
따라서 input 값이 변경될 때마다 setAuthor에 반영시켜주면 input 값이 변한다
<input
value={author}
onChange={(e) => {
setAuthor(e.target.value);
}}
/>
2. 본문을 입력받는 textarea 창 만들기
여러 줄을 입력받는 본문을 만들 때는 <textarea /> 태그를 사용하자
현재까지의 코드는 다음과 같다
import React, { useState } from "react";
const DiaryEditor = () => {
//작성자 초기값 설정
const [author, setAuthor] = useState("");
const [content, setContent] = useState("");
return (
<div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input
name="author"
value={author}
onChange={(e) => {
setAuthor(e.target.value);
}}
/>
</div>
<div>
<textarea
name="content"
value={content}
onChange={(e) => {
setContent(e.target.value);
}}
/>
</div>
</div>
);
};
export default DiaryEditor;
이렇게 동일한 state는 하나의 state로 묶어줄 수 있다
import React, { useState } from "react";
const DiaryEditor = () => {
//author과 content를 하나의 state로 묶기
const [state, setState] = useState({
author: "",
content: "",
});
return (
<div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input
name="author"
value={state.author}
onChange={(e) => {
setState({
author: e.target.value,
content: state.content,
});
}}
/>
</div>
<div>
<textarea
name="content"
value={state.content}
onChange={(e) => {
setState({
author: state.author,
content: e.target.value,
});
}}
/>
</div>
</div>
);
};
export default DiaryEditor;
만약 state의 개수가 들어난다면 spread 연산자를 사용하자
setState({
...state,
content: e.target.value,
});
반복되는 onChange 메소드도 하나로 합칠 수 있다
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
태그 내에서는 onChange={handleChangeState} 로 사용하자
3. 감정점수를 입력받는 select 만들기
1부터 5까지의 감정점수를 선택하는 select 태그 역시 useState를 사용해서 관리할 수 있다
//useState 구현 부분
const [state, setState] = useState({
author: "",
content: "",
emotion: 1,
});
//select 태그 구현 부분
<div>
<select
name="emotion"
value={state.emotion}
onChange={handleChangeState}
>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
<option value={4}>4</option>
<option value={5}>5</option>
</select>
</div>
# css 적용 후 최종 화면
# React에서 DOM 조작하기 - useRef
일기 저장 버튼 클릭 시 작성자와 일기가 정상적으로 입력되었는지 확인하고 아니라면 focus 하는 기능을 추가해보자
저장 버튼 클릭 시 내용이 입력되지 않았다면 alert 창을 띄우고 그 상태에서 더 이상 진행되지 않도록 해보자
const handleSubmit = () => {
if (state.author.length < 1) {
alert("작성자는 최소 1글자 이상 입력해주세요");
return;
}
if (state.content.length < 5) {
alert("일기 본문은 최소 5글자 이상 입력해주세요");
return;
}
alert("저장 성공!");
};
handleSubmit 함수를 다음과 같이 수정하고 내용을 입력하지 않고 저장 버튼을 누르니 다음과 같이 alert 창이 뜨는 것을 확인할 수 있다
하지만 요즘에는 alert 창을 잘 띄우지 않는다
사용자 경험에 좋지 않기 때문이다
따라서 alert 창을 띄우지 않고 해당 칸으로 focus 되도록 변경해보자
//useRef 생성
const authorInput = useRef();
const contentInput = useRef();
//handleSubmit 수정
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
const handleSubmit = () => {
if (state.author.length < 1) {
authorInput.current.focus();
return;
}
if (state.content.length < 5) {
contentInput.current.focus();
return;
}
alert("저장 성공!");
};
//태그 내에서 ref 추가
<div>
<input
ref={authorInput}
name="author"
value={state.author}
onChange={handleChangeState}
/>
</div>
<div>
<textarea
ref={contentInput}
name="content"
value={state.content}
onChange={handleChangeState}
/>
</div>
# React에서 배열 사용하기 1 - 리스트 렌더링(조회)
1. 배열을 이용하여 React에서 LIST를 렌더링하고 개별적인 컴포넌트로 만들기
DiaryList 컴포넌트를 생성하고 App.js에서 import 한다
dummyList를 만들고 해당 배열을 DiaryList에 Props로 전달하자
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
const dummyList = [
{
id: 1,
author: "정지은",
content: "방가방가방가워",
emotion: 5,
//현재 시간 기준 시간 객체 생성
created_date: new Date().getTime(),
},
{
id: 2,
author: "정정정",
content: "방가방가방가워1",
emotion: 3,
//현재 시간 기준 시간 객체 생성
created_date: new Date().getTime(),
},
{
id: 3,
author: "지지지",
content: "방가방가방가워2",
emotion: 4,
//현재 시간 기준 시간 객체 생성
created_date: new Date().getTime(),
},
];
function App() {
return (
<div className="App">
<DiaryEditor />
<DiaryList diaryList={dummyList} />
</div>
);
}
export default App;
DiaryList에서는 props로 전달 받은 dummyList를 map함수를 사용하여
각 배열을 하나 하나 화면에 렌더링 시켜줄 수 있다
map 함수를 사용할 때는 배열 요소들의 고유한 id 값을 같이 사용해주어야 에러가 발생하지 않는다
배열의 index로 id를 사용하지 말고 배열 요소의 고유한 id 값을 사용하자!
{diaryList.map((it) => (
<div key={it.id}>
<div> 작성자 : {it.author}</div>
<div> 내용 : {it.content}</div>
<div> 감정 : {it.emotion}</div>
<div> 작성시간(ms) : {it.created_date}</div>
</div>
))}
수정 및 삭제 기능을 고려하면 하나 하나를 div로 렌더링 하는 것은 좋지 않다
2. ListItem을 별도의 컴포넌트로 분리하기
map을 사용해서 렌더하는 ListItem을 별도의 컴포넌트로 분할하자!
DiaryListItem 컴포넌트를 생성하고 해당 컴포넌트를 DiaryList 컴포넌트에서 map 함수 내부에 넣자
//DiaryList 컴포넌트 map 구현
<div>
{diaryList.map((it) => (
<DiaryListItem key={it.id} {...it} />
))}
</div>
// DiaryListItem 컴포넌트
import React from "react";
import DiaryListItem from "./DiaryListItem";
const DiaryList = ({ diaryList }) => {
return (
<div className="DiaryList">
<h2>일기 리스트</h2>
<h4>{diaryList.length}개의 일기가 있습니다</h4>
<div>
{diaryList.map((it) => (
<DiaryListItem key={it.id} {...it} />
))}
</div>
</div>
);
};
DiaryList.defaultProps = {
diaryList: [],
};
export default DiaryList;
ms 로 표시되는 시간 객체를 new Date 객체에 넣고 toLocaleString 메소드를 사용하 인간이 알아볼 수 있는 시간으로 변경된다!
<span className="date">{new Date(created_date).toLocaleString}</span>
# 최종 완성된 일기 리스트 화면
# 새로 알게 된 점
리액트로 프로젝트를 여러 번 진행해보았지만 사실
useState, useRef, map 함수 등에 대한 이론을 제대로 공부해본 적이 없었다
이번 강의를 통해서 각각의 기능들에 대한 자세한 설명과 어떤 상황에서 사용하고 사용 방법은 어떻게 되는지 등과 같은
이론 및 실습을 진행하니까 정말 많이 복습이 되었다
또한 아무 생각 없이 사용하던 기능들을 더 유용하고 효율적인 코드로 작성하려면 어떻게 해야하는지에 대해 많이 배웠다
또한 리액트는 편리한 프레임워크라는 것을 다시 한번 느낄 수 있었다
'TIL > 프로그래머스 데브코스' 카테고리의 다른 글
클라우딩 어플리케이션 엔지니어링 TIL Day 30 - React 기본 간단한 일기장 만들기 (3) (1) | 2024.02.17 |
---|---|
클라우딩 어플리케이션 엔지니어링 TIL Day 29 - React 기본 간단한 일기장 프로젝트 (2) (1) | 2024.02.11 |
클라우딩 어플리케이션 엔지니어링 TIL Day 27 - React 기초 (1) | 2024.02.09 |
클라우딩 어플리케이션 엔지니어링 TIL Day 25 - 프로토타입 제작하기 (1) | 2024.02.09 |
클라우딩 어플리케이션 엔지니어링 TIL Day 26 - Node.js 기초 (0) | 2024.02.02 |