상태 끌어올리기는 자식 컴포넌트에서 어떤 부모 컴포넌트로 데이터를 이동해서,
거기서 사용하거나 또는 다른 자식 컴포넌트로 데이터를 전달하는 것
✔ 데이터는 위에서 아래로밖에 전달하지 못한다는 규칙이 있다.
(단방향 데이터 흐름 : React는 단반향으로만 데이터가 흐른다.)
✔ 반대로, 이벤트는 아래에서 위로 흐른다.(역방향 이벤트 흐름)
✔ DiaryEditor 컴포넌트에서 작성한 일기를 DiaryList 컴포넌트에 추가를 해주어야 한다.
(DiaryEditor 컴포넌트에서 생성된 데이터를 DiaryList 컴포넌트에서 필요로 한다.)
✔ DiaryEditor컴포넌트와 DiaryList컴포넌트는 형제 컴포넌트이다.
✔ 둘은 형제 컴포넌트이기 때문에 직접적으로 데이터를 넘겨줄 수 없다.
✔ 그래서 둘의 부모인 App컴포넌트를 통해서 데이터를 넘겨주어야 한다. 이것을 상태 끌어올리기라고 한다.
✔ DiaryEditor는 생성된 데이터를 상태 끌어올리기 해서 부모인 App 컴포넌트에 넘겨줘야 한다.
😎 일기를 작성하면 일기 리스트에 작성된 일기가 추가되는 것을 구현해보자!
App컴포넌트
import logo from './logo.svg';
import { useRef, useState} from 'react';
import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';
function App() {
//전역적으로 가장 위에서 데이터를 관리할 state
const [data, setData]= useState([]);
// 초기값은 일기 데이터를 배열을 저장할 것이기 떄문에 초기값을 빈배열로 둔다.
//일기 데이터로 추가되어야 하는 것에 id도 있다.
const dataId = useRef(0)
//처음에는 0번 인덱스부터 시작한다.
//App 컴포넌트에서 일기배열(data)에 새로운 일기를 추가하는 함수 작성
const onCreate =(author,content, emotion)=> {
const create_date = new Date().getTime()
//새로운 일기 데이터로 추가되어야 하는 것(newItem )
const newItem = {
author,
content,
emotion,
create_date,
id : dataId.current
//dataId.current의 현재 값은 0이라는 값을 가지고 있다.
}
//dateId가 지금 0번을 썼기 때문에 다음 일기 데이터의 id는 1이 추가된 값을 가져야 한다.
dataId.current +=1
// setData갱신함수를 사용하여 원래 있던 일기 데이터(...data)에 새로운 일기데이터(newItem)를 추가한다.
// 그리고 새로 만들어진 일기 데이터를 일기 리스트에서 제일 윗쪽에 배치하고 싶다.
//그래서 새로운 일기데이터 다음으로 전의 일기 데이터가 나오게 배치해준다.
setData([newItem, ...data])
};
return (
<div className="App">
<DiaryEditor onCreate = {onCreate}/>
{/* 일기 데이터를 추가하는 함수(onCreate)를 DiaryEditor에 prop으로 내려준다 */}
<DiaryList diaryList ={data}/>
{/* DiaryList컴포넌트에 App컴포넌트가 가진 일기배열데이터의 현재값(data)만 넘겨주기만 하면 된다. */}
{/* App컴포넌트에서 data의 stata가 바뀌면 DiaryList컴포넌트에 저절로 전달이 된다. */}
</div>
);
}
export default App;
DiaryEditor 컴포넌트
import React, {useRef, useState} from "react";
const DiaryEditor = ({onCreate}) =>{
//일기 데이터를 추가하는 함수(onCreate)를 DiaryEditor에 prop으로 넣어준다.
const contentInput = useRef()
const authorInput = useRef();
const [state , setState] = useState({
author : "",
content : "",
emotion : 1
})
const handleChangeState = (e)=> {
console.log(e.target.name);
console.log(e.target.value)
setState({
...state,
[e.target.name] : e.target.value
})
}
// 저장버튼 onclick함수
const handleSubmit = () => {
if(state.author.length<1){
authorInput.current.focus()
return
}
if(state.content.length<5){
contentInput.current.focus()
return
}
//handleSubmit 함수는 위의 조건을 모두 충족하면 일기를 저장한다.
//위 조건이 충족하면 저장된 일기 데이터들을 App컴포넌트에 있는 onCreate함수의 인자로 넣어준다.
onCreate(state.author, state.content, state.emotion)
alert("저장성공")
// 일기를 쓰고 저장하여 일기리스트에 출력되었으면
// input창과 textarea창을 초기화해줘야한다.
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 ={contentInput}
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;
결과값