[간단 일기장] 최적화3.useCallback

미아·2023년 1월 6일
0

REACT

목록 보기
22/41

with. devtools(component보면서 할거다!)

  • 현재 상황에서는 삭제하기를 하면 => DiaryEditor도 깜빡이는걸 볼수있다(최적화해야함!)



=> 여기서의 onCreate 함수는 다시 생성이 되어도 똑같음
🙋‍♀️why? 비원시타입의 자료형 비교(객체등) 얕은 비교로 일어나기때문에 결론적으로 prop으로 받고있는 onCreate 함수는 랜더링 될때마다 계속 다시 만들어져서 onCreate를 prop으로 전달함

=> 즉 우리가 해야할거: onCreate함수가 재생성되지 않아야한다.

🙋‍♀️useMemo 써서 두번째 인자에 원하는 시점 값을 넣어서 사용하면 안되나?
=> 안됨!

usememo는 함수 반환이 아니라, 값을 반환해서 onCreate함수를 원본 그대로 보내주는게 안됨!!

useCallback


=> 값 반환이 아니라 메모이제이션된 콜백을 반환!

App.js에


=> 빈 배열을 넣으면 나오는 문제: 일기 저장하기 누르면 하나만 저장됨

🙋‍♀️onCreate는 컴포넌트가 마운트되는 시점 한번만! 수행하기때문에 처음값만 들어가는것임

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

function App() {
  // app -> editor 적용할 데이터
  //랜더링 두번 일어나는 이유: 1️⃣ 초기값은 빈 배열
  const [data, setData] = useState([]); // 빈 배열, 앞으로 채워넣을것임
  const dataId = useRef(0);

  const getData = async () => {
    const url = "https://jsonplaceholder.typicode.com/comments";
    const res = await fetch(url).then((res) => res.json());
    //json값만 뽑아오는것(promise객체로 리턴하면서 resolve값을 json()사용해서 변수 res에 담아라!), then은 무조건 들어야하는것임
    // console.log(res);
    /* 이렇게도 쓸수있음 */
    // const url = "https://jsonplaceholder.typicode.com/comments";
    // const res2 = await fetch(url);
    // const response = await res2.json();

    const initData = res.slice(0, 20).map((it) => {
      return {
        author: it.email,
        content: it.body,
        emotion: Math.floor(Math.random() * 5) + 1,
        created_date: new Date().getTime(),
        //return바로 되어서 후에 +1할수없으니까
        id: dataId.current++,
      };
    });
    //res배열 500개여서 20개만 자른다(0~19) - slice
    //Math.random() * 5 => 0~4까지 랜덤난수 생성 , floor이용해서 내림 +1 (1~5까지)
    setData(initData); //3️⃣완성된 결과 setData에 저장, dataState바뀜(두번 랜더링)
  };

  //실행할 시점: app 컴포넌트가 마운트 되자마자!
  useEffect(() => {
    getData(); //2️⃣마운팅 일어난 시점, 데이터 만들고
  }, []);

  // 전달해줄 함수 onCreate
  const onCreate = useCallback((author, content, emotion) => {
    const created_date = new Date().getTime();
    const newItem = {
      author, // 비구조화 할당맞다, 키랑 이름 맞추면 그대로 들어감
      content,
      emotion,
      created_date,
      id: dataId.current,
    };
    dataId.current += 1; //current에 1 더해줘야함
    setData((data) => [newItem, ...data]); //
  }, []); // 빈배열말고 데이터들을 다 넣어줘야함, 그러면 값은 다 나오지만 계속 랜더링은됨(그럼 setData에 콜백함수를 전달하고 뎁스 비우기)

  // 삭제해줄 함수 onRemove , 어떤 아이디를 갖고있는 애를 지우면 됨!
  const onRemove = (targetId) => {
    const newDiaryList = data.filter((it) => it.id !== targetId); //다른것만 뉴배열에 넣어라~
    console.log(newDiaryList); // 기억하기!! setData함수 안쓰면 삭제는 진행 안됨!
    setData(newDiaryList);
  }; // 얘를 지우려면, DiaryItem에 가서 지워야함(컴포넌트 전달은 부모인 DiaryList에게!)

  // 수정해줄 함수 onEdit
  const onEdit = (targetId, newContent) => {
    //targetId, newContent 받아가지고와서 => 그 아이디 일치하는 애만 바꿔주면됨
    //데이터 바꾸려면 ? setData()사용~
    //새로운 데이터를 넘겨줘야함!
    setData(
      data.map(
        (it) => (it.id === targetId ? { ...it, content: newContent } : it)
        // ...it 들어온 데이터 뿌려주고, content만 새로운 content로!
      )
    );
  };

  // useMemo실습: 좋은감정, 안좋은감정 나누기
  const getDiaryAnalysis = useMemo(() => {
    //좋은 일기 개수
    const goodCount = data.filter((it) => it.emotion >= 3).length;
    //안좋은 일기 개수
    const badCount = data.length - goodCount;
    //좋은 일기 비율
    const goodCountRatio = (goodCount / data.length) * 100;
    //전체일기를 화면에 찍어줄것임 => return필요, 여러개니까 객체로 리턴
    return { goodCount, badCount, goodCountRatio };
  }, [data.length]); //두번째 인자 배열에 전달한 값이 바뀔때만 다시 수행함!
  const { goodCount, badCount, goodCountRatio } = getDiaryAnalysis; //비구조화할당 이용해서 리턴값 변수에 담아주고(키로 구분), 함수 호출
  return (
    <div className="App">
      <DiaryEditor onCreate={onCreate} />
      {/* 4️⃣ 부모가 랜더링 되기때문에 , onCreate함수도 컴포넌트가 랜더링되면서 계속 다시 생성*/}
      <div>전체일기:{data.length}</div>
      <div>기분 좋은 일기 개수:{goodCount}</div>
      <div>기분 나쁜 일기 개수:{badCount}</div>
      <div>기분 좋은 일기 비율:{goodCountRatio}</div>
      <DiaryList onRemove={onRemove} diaryList={data} onEdit={onEdit} />
      {/* prop으로 전달함!(부모=> 자식컴포넌트로 데이터 전달!) */}
    </div>
  );
}

export default App;
profile
새로운 것은 언제나 재밌어 🎶

0개의 댓글