일기장을 <DiaryEditor/>
자식 컴포넌트(작성폼)에서 작성한 일기데이터를 저장하면 <DiaryList/>
자식 컴포넌트(일기리스트)가 렌더링하고있는 일기리스트 배열에 추가해주고싶은데, React에서 같은레벨끼리는 데이터를 주고받을 수 없다.
그래서 State끌어올리기를 이용하여 적용할것이다.
State끌어올리기,단방향 데이터 흐름,역방향 이벤트 흐름을 이용해서
DiaryEditor에 배열을 이용한 리액트의 List에 아이템(=일기)을 동적으로 추가하는 예제를 다뤄볼 것이다.
1. 부모컴포넌트인 App.js에 가서 useState를 써야한다.
2. 상태변화함수(setState)는 작성폼인 DiaryEditor.js에 가서 줘야한다.
3. state는 일기리스트인 DiaryList.js에 줘야한다.
그럼 DiaryEditor.js에서 새로운 일기가 작성되면 상태변화함수가 부모컴포넌트로 전달되어 새로운 state를 DiaryList.js에 추가되어 렌더링이 된다.
(전에 썼던 dummyList는 지워주고, React의 useState기능을 쓴다.
= 상단에 import { useState } from 'react';
를 꼭 명시해야한다는 말)
import { useRef, useState } from 'react';
//리액트의 useRef, useState기능을 쓸거에요
import './App.css'; //css를 입히려면 App.css파일로 연동
import DiaryEditor from "./DiaryEditor"; //DiaryEditor 자식요소를 쓸거에요
import DiaryList from "./DiaryList" //DiaryList 자식요소를 쓸거에요
const App = () => {
const [data,setData] = useState([]);
const dataId = useState(0);
const onCreate = (author,content,emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id : dataId.current
};
dataId.current += 1;
//dataId.current는 0이라는 값을 가짐, 값을 한번쓰면 1씩 아이디가 증가
setData([newItem, ...data])
//원래배열에 있던 데이터를 스트레드연산자로 쓰고, 새로운데이터를 newItem을 앞에 추가
};
return (
<div className="App">
<DiaryEditor onCreate={onCreate} />
<DiaryList diaryList={data} />
</div>
);
}
export default App;
1) const [data,setData] = useState([]);
= (전역) 나는 일기배열을 저장할것이므로 배열[]로 초기값을 저장함.
(*왜 배열이냐하면 = 일기에는 작성자,내용,감정점수 등 여러 리스트가 있으므로 하나의 배열로 묶여서 [{작성자:@@@},{내용:@@@},{감정점수:@@@},{날짜:@@@},{id:@@}] 이렇게 저장이되어야한다.)
2) const dataId = useRef(0);
= 앞서 map()에서 Key가 필요한 이유를 배웠다. 그럼 하나의 배열에는 하나의 고유한 id가 있어야하므로 id를 초기값0부터 부여한다.
변수처럼 사용해야하기때문에 useRef를 사용해서 만들어주었다.
(=React기능이므로 상단에 import { useRef } from "react";
명시할것)
👉🏻[내생각]
고유한key는 마치 사람으로따지면 주민번호같은 존재이고, 50명의 사람(배열들)에게 배식을 하려고하면(=추가,삭제,수정) 제대로 배식이이루어졌는지 주민번호(key)로 확인하는 느낌으로 와닿는다.
3) const onCreate = (author,content,emotion) => {
const created_date = new Date().getTime();
const newItem = {author, content, emotion, created_date, id : dataId.current
};
dataId.current += 1;
setData([newItem, ...data])
};
=일기배열에 새로운 data(일기배열)를 추가할 onCreate를 만든다.
작성폼에 작성할 author,content,emotion을 onCreate함수가 받아서 1)의 data에 업데이트시키는 로직을 setData를 이용해서 onCreate함수 안에 작성한것
= onCreate는 파라미터로 (author,content,emotion)를 받고, 현재시간은 만들어주고, 새로운아이템으로 추가되어야할값은 {author, content, emotion, created_date, id : dataId.current
}
이다.
(*dataId.current는 2번의 초기값인 0을 가지고있다.)
newItem으로 추가될 값을 다 명시하고 중괄호를 닫은 다음 생각을해보면, dataId에 +1을 시행하지않으면 dataId는 항상0이되므로 고유한값이 아니게된다.
그래서 dataId.current += 1;
을 수행하게 해준다.
결과적으로 onCreate가 시행이되면 마지막에 dataId +1을 해주므로 고유한값이 되게 된다.
setData로 [새로추가 = newItem, 원래있던 data들=...data]상태변화를 명시해준다.
(만약 새로추가될 일기를 끝에 추가하고싶으면 두개의 자리를바꾸면된다.)
4) <DiaryEditor onCreate={onCreate} />
= 3번의 일기데이터를 추가 할 수 있는 함수를 DiaryEditor(작성폼)에 prop으로 전달한다.
5) <DiaryList diaryList={data} />
= 1번의 기존데이터를 DiaryList(일기리스트)에 prop으로 전달한다. (=렌더링)
import { useRef, useState } from "react";
const DiaryEditor = ({onCreate}) => {
const [state, setState] = useState({
author : "",
content : "",
emotion : 1,
});
const authorInput = useRef();
const contentTextarea = useRef();
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){
contentTextarea.current.focus();
return;
}
//props로 받은 onCreate를 호출 (저장될 내용들)
onCreate(state.author, state.content, state.emotion);
alert("저장성공");
//저장이되면 상태는 초기값으로 재설정함
setState({
author: "",
content: "",
emotion: 1,
});
};
return <div className="DiaryEditor">
<h2>오늘의 일기</h2>
<div>
<input
ref={authorInput}
name="author"
value={state.author}
onChange={handleChangeState}
/>
</div>
<div>
<textarea
ref={contentTextarea}
name="content"
value={state.content}
onChange={handleChangeState}
/>
</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>
</div>
<div>
<button onClick={handleSubmit}>저장하기</button>
</div>
</div>
};
export default DiaryEditor;
1)const DiaryEditor = ({onCreate}) => { const [state, setState] = useState({ author : "", content : "", emotion : 1, });
=App.js에서 onCreate를 prop으로 내려줬으니까, prop으로 전달받아야한다.
(모르겠으면 [React] State, Props)
2)const handleSubmit = ()=>{
onCreate(state.author, state.content, state.emotion);
alert("저장성공");
setState({author: "", content: "", emotion: 1});
};
= props로 받은 onCreate를 호출하고, 작성폼에서 저장될 내용들(state.author, state.content, state.emotion)을 넣어준다.
if문에 성립하여 저장이되면, 알림을 띄워준 후 setState를 이용해서 상태는 초기값으로 재설정한다.
(made by.hyun👩🏻💻)
작성 안한상태
작성 후 저장하기 누른상태
일기리스트에 추가된 상태