📌 일기장 만들기 (4) - CREATE
☑️ CREATE
- Real 일기장 : 진짜로 리스트에 저장되는 작성폼
☑️ 컴포넌트 트리를 그려보기 (유연한 사고력의 증진)
- 설계 구조 : 부모인 App 컴포넌트 하위에 자식인 작성폼인 DiaryEditor 컴포넌트와 일기목록인 DiaryList 컴포넌트가 쌍둥이처럼 연결되있는 구조 (부모와 자식이 얽힌 계층구조 트리 형태)
- 같은 레벨끼리는 데이터 주고 받기가 안됨 (DiaryEditor에서 DiaryList로 동일 레벨에서는 데이터가 흐르지 않음)
- 리액트는 단방향 데이터 흐름 : 위에서 아래로만 데이터를 보낼 수 있음
- State 활용 : 공통 부모요소로 끌어 올려서 해결
- 부모인 App 컴포넌트가 배열 형식의 State 데이터를 갖고, data 상태의 값을 DiaryList에게 전달하면서 list를 렌더링하게 하고 이 data라는 상태를 변화시킬 수 있는 상태 변화함수인 setData를 DiaryEditor에게 prop으로 전달해주기만 하면 됨
- 예) item1 이라는 하나의 일기 데이터(배열)를 가진 상태 > 현재는 하나만 렌더링중일 것임
새로운 일기가 작성되면 App 컴포넌트가 prop으로 전달한 setData 함수를 호출 (data의 상태를 바꾸는 상태변화함수) > item2로 새로운 아이템 추가되면서 추가된 data가 DiaryList에 prop으로 내려가면서 리렌더링
📌 정리 : EVENT는 위로 DATA는 아래로 흐르는 패턴
- 데이터를 추가하는 로직을 시뮬레이션해보면 살펴볼 수 있는 사실은 리액트로 만든 컴포넌트들은 이런 식으로 트리 형태 구조를 띰
- 데이터는 위에서 아래로 움직이는 단방향 데이터 구조
- 추가/수정/삭제 같은 이벤트들은 이렇게 핸들링하는 setData 상태변화함수를 통해 props으로 전달
- 전달받은 이런 이벤트들은 아래에서 위로 올라간다 : 새로운 일기를 작성(create)할 경우 이벤트가 발생하고, 이 이벤트는 부모인 App 컴포넌트에서 전달한 setData 함수를 호출해서 데이터를 변화시킴
- 이 데이터가 변화하게 되면 다시 아래로 떨구기 때문에 아래로 흐르게 되는 패턴
- state 끌어올리기 : 이렇게 여러 개의 컴포넌트에 엮인 데이터를 공통 부모인 App 컴포넌트의 state로 설정하여 문제 해결하는 방법
☑️ src/App.js
import { useRef, useState } from "react";
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
function App() {
// 전역적으로 상태관리
// 일기데이터, 빈 배열로 시작 (일기가 없는 상태로 출발)
const [data, setData] = useState([]);
// 데이터가 하나씩 추가될 때마다 id가 1,2,3.. 이렇게 추가되도록
// 변수처럼 사용할 고유 id가 생성되도록 useRef를 통해 추가
// 0번 index부터 시작
const dataId = useRef(0);
// 새로운 일기를 추가하는 함수
// 파라미터로 값들을 받아온다
const onCreate = (author, content, emotion) => {
const created_date = new Date().getTime(); // 현재시간 구하기. 시간 객체
const newItem = { // 새로운 아이템
author,
content,
emotion,
created_date,
id: dataId.current // 어떤 DOM도 선택하지 않고 현재 0이란 값을 갖고 있음
};
dataId.current += 1; // 새 아이템을 만들고 0번은 1번으로 증가
// 원래 data를 spread연산자로 쓰고(원래 배열에 있던 data를 여기에)
// 새로운 아이템을 추가하고 원래 데이터를 이어붙이는 형태
setData([newItem, ...data]);
};
return (
<div className="App">
<DiaryEditor onCreate={onCreate} /> {/* 새 일기 추가를 prop으로 내려준다 */}
<DiaryList diaryList={data} /> {/* data를 prop으로 내려준다 */}
</div>
);
}
export default App;
☑️ src/DiaryEditor.js
import { useState, useRef } from "react";
// DiaryEditor로 내린 onCreate 함수를 prop으로 전달
const DiaryEditor = ({onCreate}) => {
const [state, setState] = useState({
author: "", content: "", emotion: 1,
});
const authorInput = useRef();
const contentInput = useRef();
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
const handleSubmit = () => {
if(state.author.length < 1) {
// alert("작성자는 최소 1글자 이상 입력해주세요.");
// focus
authorInput.current.focus();
return;
}
if(state.content.length < 5){
// alert("일기 본문은 최소 5글자 이상 입력해주세요.");
// focus
contentInput.current.focus();
return;
}
// props로 받은 onCreate 함수를 호출하기
onCreate(state.author, state.content, state.emotion);
alert("저장 성공");
// 저장 후 작성폼이 초기화되도록 setState 설정
// 일기를 한번 더 쓰면 원래 상태로 초기화
setState({
author: "", content: "", emotion: 1
});
};
return (
<div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input ref={authorInput} name="author" value={state.author} onChange={handleChangeState} />
<span className="notification">작성자명을 입력하세요 (최소 1글자 이상)</span>
</div>
<div>
<textarea ref={contentInput} name="content" value={state.content} onChange={handleChangeState} />
<span className="notification">일기 본문을 입력하세요 (최소 5글자 이상)</span>
</div>
<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>
<span className="notification">감정 점수를 선택하세요 (택 1)</span>
</div>
<div>
<button onClick={handleSubmit}>저장하기</button>
</div>
</div>
);
};
export default DiaryEditor;
📌 정리
- App 컴포넌트 : DiaryEditor 컴포넌트와 DiaryList 컴포넌트로 함께 사용할 일기 데이터 하나를 가지고 있음
- 초기 상태
state로 일기 데이터는 빈 배열로 시작 (처음엔 작성된 일기가 없으므로)
일기상태변화 함수 setData를 가지고 있음
이 상태에서는 DiaryList한테 현재 이 App 컴포넌트가 가진 일기 배열 데이터의 상태를 넘겨주기만 하면, DiaryList도 알아서 다시 렌터하고 추가하면 추가, 삭제하면 삭제 (상태 바뀜) - 상태 변화
DiaryEditor 컴포넌트가 일기를 저장해서 반영되면 App 컴포넌트 데이터의 상태가 변화가 일어남
(DiaryList 컴포넌트가 App 컴포넌트의 data state를 DiaryList로 사용하고 있기 때문) - onCreate 함수 : 새로운 일기 추가 (DiaryEditor 컴포넌트에 props으로 전달)
일기 저장이 일어날 때 onCreate 함수를 호출
(emotion data, 현재 시간 객체, id ref +1 증가 등등)
가장 최신 일기 작성 시 가장 위로 배열에 들어감 - 단방향 데이터 흐름 그리고 역방향 이벤트 흐름으로 state를 끌어올려서 화면에 렌더링
'React > React 공부' 카테고리의 다른 글
React 기본 - 일기장 만들기(6) [CRUD : UPDATE] (0) | 2023.02.09 |
---|---|
React 기본 - 일기장 만들기(5) [CRUD : DELETE] (0) | 2023.02.09 |
React 기본 - 일기장 만들기(3) [CRUD : READ] (0) | 2023.02.09 |
React 기본 - 일기장 만들기(2) [React에서 DOM 조작하기 : useRef] (0) | 2023.02.09 |
React 기본 - 일기장 만들기(1) [useState] (0) | 2023.02.09 |