6-13. 최적화 4(완) (프로젝트 최적화 완료)

2022. 7. 7. 16:18React/한입 크기로 잘라 먹는 리액트(React.js)

각 일기 하나씩을 삭제할때마다 모든 일기가 rerendering하는 것을 볼 수 있다.

현재는 text로만 이루어졌지만 이미지나 동영상으로 이루어질 경우 엄청난 시간이 소요될 것으로 예상이된다.

 

우선 DiaryItem를 React.memo로 감싸고,

useEffect로 렌더링할때마다 출력하도록하면 다음과같이 출력됨을 알수 있다.

더보기
import React, { useEffect, useRef, useState } from "react";
const DiaryItem = ({
  onEdit,
  onRemove,
  id,
  author,
  content,
  created_date,
  emotion,
}) => {
  useEffect(() => {
    console.log(`${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.length < 5) {
      localContentInput.current.focus();
      return;
    }
    if (window.confirm(`${id}번째 일기를 수정하시겠습니까?`)) {
      onEdit(id, localContent);
      toggleIsEdit();
    }
  };

  return (
    <div className="DiaryItem">
      <div className="info">
        <span className="author_info">
          작성자 : {author} | 감정: {emotion}
        </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 React.memo(DiaryItem);

DiaryItem은 React.memo로 감싼다고해서 최적화가 되지는 않는다.

onEdit과 onRemove는 onCreate처럼 데이터 state가 변화되면 rerendering할 수 밖에 없기 때문이다.

그래서 onCreate처럼 onEdit과 onRemove를 최적화 해보자.

onRemove

  const onRemove = (targetId) => {
    // filter 기능을 통해 그 부분만 빼고 출력 된다.
    const newDiaryList = data.filter((it) => it.id !== targetId);
    setData(newDiaryList);
  };

에서 아래와 같이 변환

  const onRemove = useCallback((targetId) => {
    // filter 기능을 통해 그 부분만 빼고 출력 된다.
    setData((data) => data.filter((it) => it.id !== targetId));
  }, []);

data 파라미터에 최신 데이터가 전달이 되기 때문에, 인자부분을 사용해아한다.

 

onEdit

  const onEdit = (targetId, newContent) => {
    setData(
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  };

에서 아래와 같이 변환

  const onEdit = useCallback((targetId, newContent) => {
    setData((data) =>
      data.map((it) =>
        it.id === targetId ? { ...it, content: newContent } : it
      )
    );
  }, []);

 

이렇게 진행하고 글을 삭제하면 rerendering되지 않아 console에 아무것도 찍히지 않게 된다.

이전에는 0부터 모든 컴포넌트가 rerendering되었었는데 아무것도 렌더링 되지 않는다.

 

글을 추가한다면 아래와 같이 추가된 부분만 console로 출력된다.