1. 배열을 이용한 React의 List에 아이템을 동적으로 추가해보기
리액트에서는 같은 레벨간의 데이터를 주고 받는 일이 불가능하다.
→ React는 단방향으로만 데이터가 흐른다. ( 단방향 데이터 흐름 )
작성한 컴포넌트를 같은 레벨의 컴포넌트에 추가를 해주기 위해서는 리액트의 상태인 state를 컴포넌트의 공통
부모 요소인 컴포넌트로 끌어올려서 해결할 수 있다.


부모 요소인 <App/>이 일기 데이터를 배열 형식의 state를 가지고 있고 데이터 state의 값을 <DiaryList/>에 전달을
하면서 리스트를 랜더링하게 하고 데이터 state를 변화시킬 수 있는 상태 변화 함수인 setData를 <DiaryEditor/>에게
prop으로 전달해준다면 된다.
data state가 하나의 요소를 가지고 있는 배열일 경우, data를 prop으로 전달받은 <DiaryList/> 컴포넌트는 요소
하나만 랜더링을 하고 있다. 일기 작성 폼인 <DiaryEditor/>에서 새로운 일기 데이터가 생성이 된다면 <App/>에서
<DiaryEditor/>에게 prop으로 전달한 setData 함수를 호출하게 된다. setData 함수는 데이터의 값을 바꾸는
상태 변화 함수 이므로 data state 배열에 새로 생성된 일기 데이터를 추가해 data state 값을 변경한다.
data state가 변경이 되면 <DiaryList/>에는 추가된 데이터까지 포함이 되서 새로운 데이터가 prop으로 내려가게 된다.
<DiaryList/> 컴포넌트는 전달받은 prop이 변경되었기 때문에 ReRendering이 된다.

리액트로 만든 컴포넌트는 트리 형태의 구조를 띄며 데이터는 위에서 아래로만 움직이게 되는 단방향 데이터 흐름이
되고 추가, 수정, 삭제같은 이벤트는 setData 같은 함수를 props로 전달해서 이벤트들은 아래에서 위로 움직이게
되는 구조로 작동하게 된다.
<DiaryEditor/>가 새로운 일기 데이터를 생성한다면 create 이벤트가 발생하게 된다. 이벤트는 부모 컴포넌트인
<App/>에서 전달하는 setData라는 상태 변화 함수를 호출해서 <App/>에 존재하는 data 배열을 변화시킴으로써
이뤄지기 때문에 이벤트는 위쪽으로 발생하게 되고, 데이터가 변화하게 되면 <DiaryList/>로 이동하게 되면서
아래로 발생하게 된다.
여러 개의 컴포넌트에 엮인 data 배열을 그들의 공통 부모인 컴포넌트의 state로 설정해서 문제를 해결하는 방식을
state 끌어올리기라고 한다.
App.js
import { useRef, useState } from 'react';
import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';
function App() {
const [data, setData] = useState([]);
// data state는 일기 데이터 배열을 저장하기 때문에 빈 배열로 초기값을 만들어준다.
const dataId = useRef(0); // ID는 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; // 데이터가 하나씩 추가될 때마다 증가한다.
setData([newItem, ...data]); // 기존에 존재하던 데이터에 새로운 일기를 추가
};
return (
<div className='App'>
<DiaryEditor onCreate={onCreate}/>
<DiaryList diaryList={data}/>
</div>
);
}
export default App;
onCreate 함수는 author, content, emotion을 모두 받아 setData 상태 변화 함수를 이용해서 data에 업데이트
시킨다.
DiaryEditor.js
import { useRef, useState} from "react";
const DiaryEditor = ({onCreate}) => {
const [state, setState] = useState({
author : "",
content : "",
emotion : 1
});
const handleChangeState = (e) => {
setState({
...state,
[e.target.name] : e.target.value
})
}
const authorInput = useRef();
const contentInput = useRef();
const handleSubmit = () => {
if(state.author.length < 1){
authorInput.current.focus();
return ;
}
if(state.content.length < 1){
contentInput.current.focus();
return ;
}
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}></input>
</div>
<div>
<textarea ref={contentInput} name="content" value={state.content} onChange={handleChangeState}></textarea>
</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;
DiaryEditor 컴포넌트는 onCreate 함수를 props으로 전달을 받는다. handleSubmit()에서 2가지 조건을 통과하면
일기를 저장할 수 있기 때문에 props로 받은 onCreate를 호출하면서 새로 작성하는 데이터 state의
author, content, emotion을 전달해주면 된다.
방금 작성한 일기 데이터가 그대로 입력하는 곳에 남아있다. 왜냐하면 작성한 데이터들은 DiaryEditor 컴포넌트의
state에 맵핑이 되어있기 때문이다. 그래서 일기를 정상적으로 저장을 했다면 setState를 통해서 일기 작성폼의
데이터를 기본 값으로 초기화 시켜줄 필요가 있다.
App 컴포넌트는 DiaryEditor 컴포넌트와 DiaryList 컴포넌트가 함께 사용할 일기 데이터를 state로 가지고 있다.
state는 빈 배열인 상태로 시작을 한다. 일기 데이터 상태 변화 함수는 setData이다.
DiaryList 컴포넌트에게는 현재 App 컴포넌트가 가진 일기 배열 데이터의 state를 넘겨주기만 하면 된다.
그러면 App 컴포넌트가 가진 일기 데이터의 state가 바뀌게 된다면 DiaryList도 알아서 다시 랜더가 된다.
DiaryEditor 컴포넌트가 일기를 생성할 경우 DiaryList에 반영을 하기 위해서는 App 컴포넌트의 data의
상태를 변화시키면 된다. DiaryList 컴포넌트는 App 컴포넌트의 data state를 diaryList로 사용하고 있기 때문이다.
App 컴포넌트의 onCreate 함수를 통해서 새로운 일기를 추가할 수 있다. author, content, emotion을 전달을
받는다.
DiaryEditor 컴포넌트는 onCreate 함수를 App 컴포넌트로부터 prop으로 전달을 받아 일기 저장이 일어났을 때
onCreate함수를 호출한다. 그러면서 현재 컴포넌트가 가지고 있는 author, content, emotion 데이터를
App 컴포넌트로 전달을 해주게 된다.
그러면 App 컴포넌트에서는 전달받은 author, content, emotion 데이터를 받아서 newItem 객체를 생성하고
setData 함수를 호출해서 새로 생성한 일기 데이터와 기존에 존재하던 데이터를 하나의 배열로 합치게 된다.
합쳐진 일기 데이터인 data은 DiaryList 컴포넌트에 prop으로 전달이 된다.
'Front-End > React' 카테고리의 다른 글
| [ React ] React 기본 ③ React에서 배열 사용하기 - 4. 리스트 데이터 수정하기 (0) | 2022.10.01 |
|---|---|
| [ React ] React 기본 ③ React에서 배열 사용하기 - 3. 리스트 데이터 삭제하기 (0) | 2022.10.01 |
| [ React ] React 기본 ③ React에서 배열 사용하기 - 1. 리스트 랜더링 ( 조회 ) (0) | 2022.09.28 |
| [ React ] React 기본 ② React에서 DOM 조작하기 (0) | 2022.09.28 |
| [ React ] React 기본 ① 사용자 입력 처리하기 (0) | 2022.09.19 |