코드가 1탄부터 이어지기 때문에 1탄부터 보고 오셔야 합니다~!
1탄
https://dev-ini.tistory.com/73
2탄
https://dev-ini.tistory.com/75
3탄
https://dev-ini.tistory.com/77
컴포넌트&데이터 구조 생각해보기
1. 리액트는 기본적으로 트리구조이다.
- <App />에서 <DiaryEditor />와 <DiaryList />를 렌더링 한다.
- <DiaryEditor />에서 새로운 일기를 작성한다.
- <DiaryList />에서 일기 리스트들을 보여준다.
2. 리액트에서는 같은 레벨 끼리는 데이터를 주고 받을 수 없다.
- <DiaryEditor />에서 작성된 일기 아이템이 <DiaryList />로 바로 추가 될 수는 없다.
- 위에서 아래로만 데이터를 보낼 수가 있다. (단방향 데이터 흐름)
3. 해결책은 state를 <DiaryEditor />와 <DiaryList />의 공통부모 요소로 끌어올리는 것이다.
- "state 끌어올리기" : 공통부모인 컴포넌트인 <App />에 state를 설정하여 문제를 해결한다.
- <App />이 일기데이터를 배열 형식의 state를 가지고 있게끔 한다.
- state인 data 값을 <DiaryList />에 전달하면서 리스트를 렌더링한다.
- 그리고, (state를 변화시킬수 있는 상태변환함수인) setdata를 <DiaryEditor />에 props로 전달한다.
4. <DiaryEditor />에서 새로운 일기를 작성 하면 setData를 호출한다.
- setData는 새로운 item을 추가할 수 있도록 data의 값을 바꾼다.
- <DiaryList />에 props로 추가된 data까지 포함한 새로운 data가 내려간다.
- <DiaryList />는 전달받은 props가 바껴서 리렌더링된다.
- 결론적으로 [item1, item2] 리스트를 렌더링하게된다.
5. Event와 Data의 흐름
< Event의 흐름 >
- 추가, 수정, 삭제와 같은 이벤트들은 setData 같은 함수를 props로 전달해서 아래에서 위로 올라가는 구조이다.
- <DiaryEditor />에서 새로운 일기를 작성하면 "생성"이라는 이벤트가 발생한다.
- 이벤트는 <App />에서 전달한 상태변화함수(setData)를 호출해서 data를 변화시킴으로써 이뤄진다.
< Data의 흐름 >
- data는 위에서 아래로만 움직인다.
- data가 변화하게 되면 다시 아래로 떨군다.
위의 설명을 토대로 일기장 리스트 추가 기능 구현해보기
App.js
import './App.css';
import DiaryEditor from './DiaryEditor/DiaryEditor';
import DiaryList from './DiaryList';
import { useRef, useState } from 'react';
function App() {
const [data, setData] = useState([]); // (1) 상태변화함수 만들기, 빈배열로 시작 (일기 없는 상태로 출발)
const dataId = useRef(0); // (7) id 인덱스 추가-> 변수 처럼 사용 필요 -> useRef 사용
const onCreate = (author, content, emotion) => {; // (3) data를 새로 생성하는 함수 만들기 - 새로운 일기 추가하는 함수
const created_date = new Date().getTime(); // (5) 현재시간
const newItem = { // (6) 새로운 일기 아이템으로 추가돼야하는것
author,
content,
emotion,
created_date,
id: dataId.current
};
dataId.current += 1; // (8) 하나 만들면 id가 +1 증가해야함
setData([newItem,...data]); // (9) 원래 아이템에서 맨 위에 새로운 일기 올라오게 하기
}
return (
<div className="App">
<DiaryEditor onCreate={onCreate}/> {/* (4) (글쓰기로 data 업데이트, 생성) */}
<DiaryList diaryList={data} /> {/* (2) 리스트에 data 상태 전달 */}
</div>
);
};
export default App;
DiaryEditor.js
import {useState} from "react";
import {useRef} from "react";
import './DiaryEditor.css';
const DiaryEditor = ({onCreate}) => { // (10) onCreate 함수를 props로 받음
const authorInput = useRef();
const contentInput = useRef();
const [state, setState] = useState({
author: "",
content: "",
emotion: 1,
});
const handleChangeState = (e) => {
setState({
...state,
[e.target.name]: e.target.value,
});
};
// 입력 강제하기
const handleSubmit = ()=>{
if(state.author.length < 1){
// focus
authorInput.current.focus();
return;
}
if(state.content.length < 5){
contentInput.current.focus();
// focus
return;
}
onCreate(state.author, state.content, state.emotion); // (11) 일기 저장이 발생했을때 onCreate 함수 호출
alert("저장성공");
setState({ // (12) 기본값으로 초기화
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;
정리
(1) <App />가 <DiaryEditor />와 <DiaryList />가 함께 사용할 일기데이터를 state로 가지고 있다.
(2) 일기데이터는 빈배열로 시작한다. (일기가 없는 상태로 시작)
(3) 상태변화함수인 setData도 있다.
(4) <DiaryList />한테는 <App />가 가진 state를 넘겨주기만 하면 된다.
(5) state가 바뀌면 리렌더링이 된다. (추가, 삭제 등)
(6) <DiaryEditor />에서 일기를 저장했을 때 일기 리스트에 반영되게 만들려면,
<App />의 data의 상태를 변화시키면 된다. (<DiaryList />가 일기장 리스트로 <App />의 state를 사용하고 있기 때문이다.)
(7) <App />에 onCreate라는 함수를 만든다. (onCreate는 새로운 일기를 추가하는 함수)
(8) 이 onCreate함수는 작성자, 내용, 감정 점수를 전달 받는다.
(9) <DiaryEditor />에서는< App />로부터 onCreate라는 함수를 props로 받아서, 일기 저장이 일어났을때 onCreate함수를 호출한다.
(10) 동시에 현재 컴포넌트가 가지고 있는 작성자, 내용, 감정 점수 데이터를 < App />으로 전달한다.
(11) < App />이 받아서 가지고 오면, setData 함수를 호출해서 "원래있던 데이터+새로운 데이터"를 리스트 렌더링한다.
완성본
'Libraries > React' 카테고리의 다른 글
[React] 데이터 수정하기 (일기장 만들기 6탄) (0) | 2023.09.12 |
---|---|
[React] 데이터 삭제하기 (일기장 만들기 5탄) (0) | 2023.09.12 |
[React] 데이터 리스트 렌더링 (조회) (일기장 만들기 3탄) (0) | 2023.09.04 |
[React] useRef로 DOM 조작하기 (일기장 만들기 2탄) (0) | 2023.08.08 |
[React] useState로 사용자의 입력 처리하기: input, button에 이벤트 달기 (일기장 만들기 1탄) (1) | 2023.08.08 |