[React] 배열 사용하기 2 - 데이터 추가

이재훈·2023년 6월 8일
0

React

목록 보기
9/27

목표

React에서 리스트 데이터 추가하기

  • 배열을 이용한 React의 List에 item 동적으로 추가하기
  • With React처럼 생각하기

현재 구현한 컴포넌트 & 데이터 구조


App 컴포넌트 아래 DiaryEditor와 DiaryList가 동일한 레벨의 컴포넌트로 존재하고 있습니다.
DiaryEditor에서 작성한 일기를 DiaryList에 일기 아이템 추가가 되어야 하지만 리액트에서는 같은 레벨끼리는 데이터를 주고 받을 수 없습니다.

리액트는 단방향으로만 데이터가 흐릅니다. 즉 위에서 아래로만 데이터를 보낼 수 있다는 의미입니다. 이것을 "단방향 데이터 흐름"이라고 합니다.

이 때는 어떻게 해야 할까요?

리액트의 상태인 State를 공통 부모 요소로 끌어 올려서 해결할 수 있습니다.
즉, DiaryEditor과 DiaryList의 부모 요소인 App이 일기 데이터를 State로 가지고 있고
DiaryList에게는 data를 주어 렌더링을 시키고 DiaryEditor에게는 setData를 prop으로 전달해주면 됩니다.

리액트로 만든 컴포넌트들은 트리형태의 구조를 띄고 데이터는 위에서 아래로만 움직이는 단방향 데이터 흐름이 되고 추가, 수정, 삭제 같은 setData 함수를 prps로 전달을 하여 event는 아래에서 위로 올라가는 구조입니다.

App.js

import { useRef, useState } from "react";
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";

function App() {
  const [data, setData] = useState([]);

  const dataId = useRef(0);
  const onCreate = (name, content, hungry) => {
    const created_date = new Date().getTime();
    const newItem = {
      name,
      content,
      hungry,
      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;

기존에 있던 더미 데이터를 지우고, useState를 사용하여 data는 DiaryList에게 props로 넘겨주고 onCreate 함수를 만들어서 새로운 게시글을 만들어서 저장을 합니다.

setData([newItem, ...data]);

newItem을 앞에 놓음으로써 새로운 아이템이 상단에 보일 수 있게 하였습니다. dataId는 시퀀스 역할을 하므로 useRef(0)을 사용하고 아이템 추가가 끝나면 +1 해주는 로직을 가지고 있습니다.
onCreate함수는 DiaryEditor에게 props로 전달을 해줍니다.

DiaryEditor.js

import { useRef, useState } from "react";

const DiaryEditor = ({ onCreate }) => {
  const nameInput = useRef();
  const contentInput = useRef();

  const [state, setState] = useState({
    name: "",
    content: "",
    hungry: 10,
  });

  const handleChangeState = (e) => {
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = () => {
    if (state.name.length < 1) {
      nameInput.current.focus();
      return;
    }

    if (state.content.length < 5) {
      contentInput.current.focus();
      return;
    }

    onCreate(state.name, state.content, state.hungry);
    
    setState({
      name: "",
      content: "",
      hungry: 10,
    });
  };

  return (
    <div className="DiaryEditor">
      <h2>오늘의 먹방 일기</h2>
      <div>
        이름
        <input
          ref={nameInput}
          name="name"
          value={state.name}
          onChange={handleChangeState}
        />
      </div>
      <div>
        내용
        <textarea
          ref={contentInput}
          name="content"
          value={state.content}
          onChange={handleChangeState}
        />
      </div>
      <div>
        배고픔 정도
        <select name="hungry" value={state.hungry} onChange={handleChangeState}>
          <option value={10}>10</option>
          <option value={20}>20</option>
          <option value={30}>30</option>
          <option value={40}>40</option>
          <option value={50}>50</option>
          <option value={60}>60</option>
          <option value={70}>70</option>
          <option value={80}>80</option>
          <option value={90}>90</option>
          <option value={100}>100</option>
        </select>
      </div>
      <div>
        <button onClick={handleSubmit}>일기 저장하기</button>
      </div>
    </div>
  );
};

export default DiaryEditor;

onCreate를 props로 받아서 onCreate 함수를 사용해줍니다.

onCreate(state.name, state.content, state.hungry);

setState({
	name: "",
	content: "",
	hungry: "",
});

setState로 저장이 성공하면 입력폼을 초기화 합니다.

이렇게 최신순 정렬로 저장이 잘 되는 것을 확인할 수 있습니다.


해당 게시글은 인프런 강의
"한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지(이정환)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.

profile
부족함을 인정하고 노력하자

0개의 댓글