[React] 배열 사용하기 3 - 데이터 수정

이재훈·2023년 6월 8일
0

React

목록 보기
11/27

목표

React에서 리스트 데이터 수정하기

  • 배열을 이용한 React의 List에 아이템을 동적으로 수정해보기
  • With 조건부 렌더링

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]);
  };

  const onRemove = (targetId) => {
    const newDirayList = data.filter((it) => it.id !== targetId);
    setData(newDirayList);
  };

  const onEdit = (targetId, newContent) => {
    setData(
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  };
  return (
    <div className="App">
      <DiaryEditor onCreate={onCreate} />
      <DiaryList onEdit={onEdit} onRemove={onRemove} diaryList={data} />
    </div>
  );
}

export default App;

App.js에는 onEdit 메서드를 만듭니다. id와 newContent를 받아서 map 메서드를 사용하여 targetId와 게시글 id가 같다면 update를 합니다. 그리고 props로 onEdit을 DiaryList로 전달합니다.

DiaryList.js

import DiaryItem from "./DiaryItem";

const DiaryList = ({ onEdit, onRemove, diaryList }) => {
  return (
    <div className="DiaryList">
      <h2>일기 리스트</h2>
      <h4>{diaryList.length}개의 일기가 존재합니다.</h4>
      <div>
        {diaryList.map((it) => (
          <DiaryItem key={it.id} {...it} onRemove={onRemove} onEdit={onEdit} />
        ))}
      </div>
    </div>
  );
};

DiaryList.defaultProps = {
  diaryList: [],
};

export default DiaryList;

DiaryList에서는 props로 onEdit을 DiaryItem에게 전달합니다.

DiaryItem.js

import { useRef, useState } from "react";

const DiaryItem = ({
  onEdit,
  onRemove,
  name,
  content,
  created_date,
  hungry,
  id,
}) => {
  const [isEdit, setisEdit] = useState(false);
  const toggleIsEdit = () => setisEdit(!isEdit);
  const [localContent, setLocalContent] = useState(content);
  const localContentInput = useRef();

  const handleRemove = () => {
    if (window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)) {
      onRemove(id);
    }
  };

  const handleQuitEdit = () => {
    setisEdit(false);
    setLocalContent(content);
  };

  const handleEdit = () => {
    if (localContent.localContent < 5) {
      localContentInput.current.focus();
      return;
    }

    if (window.confirm(`${id}번째 일기를 수정하시겠습니까?`)) {
      onEdit(id, localContent);
      toggleIsEdit();
    }
  };

  return (
    <div className="DiaryItem">
      <div className="info">
        <span>
          이름 : {name} | 배고픔 정도 : {hungry}
        </span>
        <br />
        <span className="date">{new Date(created_date).toLocaleString()}</span>
      </div>
      <div className="content">
        {isEdit ? (
          <>
            <textarea
              ref={localContentInput}
              value={localContent}
              onChange={(e) => setLocalContent(e.target.value)}
            />
          </>
        ) : (
          <>{content}</>
        )}
      </div>
      {isEdit ? (
        <>
          <button onClick={handleQuitEdit}>수정 취소</button>
          <button onClick={handleEdit}>수정 완료</button>
        </>
      ) : (
        <>
          <button onClick={handleRemove}>삭제</button>
          <button onClick={toggleIsEdit}>수정</button>
        </>
      )}
    </div>
  );
};

export default DiaryItem;

해당 코드는 변경된 내용이 꽤 있기 때문에 나눠서 정리해보도록 하겠습니다.

import { useRef, useState } from "react";
// ... 생략
  const [isEdit, setIsEdit] = useState(false);
  const toggleIsEdit = () => setIsEdit(!isEdit);
// ... 생략
if (window.confirm(`${id}번째 일기를 수정하시겠습니까?`)) {
  onEdit(id, localContent);
  toggleIsEdit();
}
// ... 생략
<div className="content">
        {isEdit ? (
          <>
            <textarea
              ref={localContentInput}
              value={localContent}
              onChange={(e) => setLocalContent(e.target.value)}
            />
          </>
        ) : (
          <>{content}</>
        )}
      </div>
      {isEdit ? (
        <>
          <button onClick={handleQuitEdit}>수정 취소</button>
          <button onClick={handleEdit}>수정 완료</button>
        </>
      ) : (
        <>
          <button onClick={handleRemove}>삭제</button>
          <button onClick={toggleIsEdit}>수정</button>
        </>
      )}
    </div>

isEdit를 useState를 사용하여 false or true에 따라서 보여지는 버튼이나, content가 수정가능, 불가능하게 코드가 작성되어 있습니다.

import { useRef, useState } from "react";
// ... 생략
const localContentInput = useRef();
// ... 생략
  const handleEdit = () => {
    if (localContent.localContent < 5) {
      localContentInput.current.focus();
      return;
    }
// ... 생략
  <textarea
    ref={localContentInput}
    value={localContent}
    onChange={(e) => setLocalContent(e.target.value)}
  />
// ... 생략

useRef를 사용하여 재작성한 content의 길이가 5보다 작게 되면 해당 태그에 focus를 하게 동작하는 코드입니다.

onEdit 역시 App에서 드릴링으로 DiaryItem에게 전달되고

저장 이벤트가 발생하게 되면 localContent가 App으로 전달되어 수정이 되는 구조 입니다.
게시글 수정하는 로직 구현을 완료하였습니다.


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

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

0개의 댓글