CREATE
1. React에서 리스트 데이터 추가하기
세부 목표)
- 배열을 이용한 React 의 List 에 아이템을 동적으로 추가해보기.
- With React 처럼 생각하기
* 컴포넌트 & 데이터 구조 생각해보기
리액트는 같은 레벨 간의 컴포넌트끼리 데이터를 주고 받는 일이 불가능하다. 윗 계층에서 아래 계층으로만 데이터를 보낼 수 있다. 즉 React 는 단방향으로만 데이터가 흐른다.
같은 계층으로 데이터를 주고받으려면, 각 컴포넌트의 state 를 공통 부모요소로 끌어올려 해결 가능하다.
일기장 프로젝트에 적용하면, App.js(부모 컴포넌트)에서 배열형식의 state 를 가지고 있고, props 로 각 자식컴포넌트인 DiaryList 와 DiaryEditor 에 데이터를 전달한다. DiaryList 에게 data 를 전달하여 List 형태로 데이터를 출력하고, DiaryEditor 에 setData 상태 변화 함수를 전달하여 새로운 일기를 작성하도록 한다. 이 때 추가된 data 가 EventList 에 props 으로 내려가며 리랜더링이 되어 추가된 리스트를 보여준다.
리액트로 만든 컴포넌트들은 트리 형태의 구조를 띄며 data 는 위에서 아래로만 움직이는 단방향 데이터 흐름이다. 추가, 수정, 삭제 등의 event 들은 데이터를 핸들링 하는 함수를 props 로 전달하여 아래에서 위로 올라가는 구조다.
여러개의 컴포넌트로 엮인 data 를 공통 부모 컴포넌트의 state 로 설정하여 문제 해결하는 방법을 state 끌어올리기 라고 할 수 있다.
state 끌어올리기, 단방향 data 흐름, 역방향 event 흐름을 활용해본다.
- App.js
import { useRef, useState } from 'react';
import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';
// 임시 배열 데이터
/*
const dummyList = [
{
id: 1
, author: '송진성'
, content: '하이 1'
, emotion: 5
, created_date: new Date().getTime() // 현재 시간 기준 생성됨, getTime() : 시간을 밀리세컨트로 돌려줌
}
, {
id: 2
, author: '홍길동'
, content: '하이 2'
, emotion: 2
, created_date: new Date().getTime()
}
, {
id: 3
, author: '아무개'
, content: '하이 3'
, emotion: 1
, created_date: new Date().getTime()
}
]
*/
function App() {
const [data, setData] = useState([]); // 빈 배열로 시작 (일기가 없는 상태로 시작)
const dataId = useRef(0);
const onCreate = (author, content, emotion) => {
const created_date = new Date().getDate();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current
}
dataId.current += 1;
setData([newItem, ...data]); // 위에서 부터 출력하기 위해 newItem, ...data 순서로 작성
}
console.log(typeof data);
console.log(data);
return (
<div className="App">
<DiaryEditor onCreate={onCreate}/>
<DiaryList diaryList={data} />
</div>
);
}
export default App;
부모 컴포넌트에 state 배열을 만들고 각 자식 컴포넌트에게 props 를 전달한다. DiaryEditor 컴포넌트엔 onCreate 함수를(event), DiaryList 컴포넌트엔 data 를 전달한다.
- DiaryEditor.js
import { useState, useRef } from "react";
const DiaryEditor = ({ onCreate }) => {
// DOM Element 접근
const authorInput = useRef();
const contentInput = useRef();
// state 기본값 설정
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) {
// alert('작성자는 최소 1글자 이상 입력해주세요.');
// focus
authorInput.current.focus();
return;
}
if (state.content.length < 5) {
// alert('일기 본문은 최소 5글자 이상 입력해주세요.');
// focus
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}
/>
</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;
onCreate 함수를 props 로 전달받아 매개변수로 넣어준다. 이후 일기장 입력폼을 초기화 한다.
참고강의 : https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8#
한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 강의 - 인프런
개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응용은 길게 17시간 분량의 All-in-one 강의!, 리액트, 한 강의로 끝장낼 수 있어요.
www.inflearn.com
'강의 실습 > 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지' 카테고리의 다른 글
React에서 배열 사용하기 4 - 데이터 수정하기 (0) | 2024.01.18 |
---|---|
React에서 배열 사용하기 3 - 데이터 삭제하기 (0) | 2024.01.17 |
React에서 배열 사용하기 1 - 리스트 렌더링 (조회) (1) | 2024.01.15 |
React에서 DOM 조작하기 - useRef (0) | 2024.01.14 |
React에서 사용자 입력 처리하기 (2) | 2024.01.13 |
댓글