본문 바로가기

React

[React 강의 노트(3)] Hook - useEffect, useMemo, userCallback, useReducer

반응형

react강의 노트 | Byte Degree [3주차]

 

useEffect

 

- component가 화면에 나타나게 될 때,  사라지게 될 때 등

- 첫번째 파라미터에는 함수, 두번째 파라미터에는 deps

- return 함수는 뒷정리? 함수이며 , 업데이트 직전에 호출된다

 

mount - component가 나타나게 될 때

unmount - 삭제될때

 

  useEffect(() => {
    //comopnent가 나타남
    console.log("컴포넌트가 화면에 나타남"); //
    return () => {
      //component가 사라짐
      console.log("컴포넌트가 사라짐");
    };
  }, []);

 

- deps(의존 되는 값)가 비워져 있는 경우 - component가 처음 화면에 나타날 때만 실행된다.

- 사라지는 경우는 함수를 그냥 반환하면 된다.

 

- mount시 주로 

props로 받은 값을  component state 값으로 설정하는 경우,

외부 API 요청하는 경우,

라이브러리 사용,

setInterval, setTimeout

 

- unmount시 주로 

setInterval, setTimeout 제거할 때 - clearInterval, clearTimeout

라이브러리 인스턴스 제거

 

 

 deps 배열 설정

 

 //deps 배열 설정한 경우
 //update 될때, 되기 전 모두 출력
  useEffect(() => {
    console.log("user 값이 업데이트됨");
    console.log(user);
    return () => {
      console.log("user 값이 업데이트 전");
      console.log(user);
    };
  }, [user]);
  
//user 값이 업데이트 전
//{id: 3, username: "ssdd", email: "ssdd@gmail.com", active: false}
//user 값이 업데이트 됨
//{id: 3, username: "ssdd", email: "ssdd@gmail.com", active: true}

---------------------------------------------

//deps 배열이 비워져 있는 경우
//component가 화면에 생길때, 제거될때 각각
  useEffect(() => {
    console.log("user 값이 설정");
    console.log(user);
    return () => {
      console.log("user 값이 삭제");
      console.log(user);
    };
  }, []);

//user 삭제
//{id: 3, username: "ssdd", email: "ssdd@gmail.com", active: false}

////user 설정
//{id: 4, username: "ssdd", email: "ssdd@gmail.com", active: false}

 

- 값이 바뀌기 전 값도 출력됨

- useEffect 사용시 해당 hook 내부에서 사용하고 있는 상태가 있다면 deps에 넣어줘야한다. (나중에 오류가 생길 수 있음)

 

 

useMemo

- 성능을 최적화해야하는 함수에서 사용

 

 

function countActiveUsers(users) {
  console.log("활성 사용자 수를 세는 중...");
  return users.filter((user) => user.active).length;
}

//active된 user count
const count = countActiveUsers(users); 
//onChange마다 console이 계속 찍힌다.-> 불필요

----------------- ↓ ------------------

//useMemo hook사용시
function countActiveUsers(users) {
  console.log("활성 사용자 수를 세는 중...");
  return users.filter((user) => user.active).length;
}

//active된 user count
const count = useMemo(() => countActiveUsers(users), [users]); 
//deps에 users를 넣으면  users가 변할만 함수가 실행된다.

 

- 위처럼 코드 작성시, user.active가 변화될 때만 console이 찍히지 않고,  onChange가 일어날때마다 활성화되어 불피요한 출력을 하게 된다.

-> 특정값이 바뀌었을 때만 특정 연산을 하게 되고 원하는 값이 바뀌지 않은 경우 이전에 만들어뒀던 값을 재사용한다.

- 첫번쨰 파라미터는 함수. 두번째 파라미터는 deps

- deps에 들어온 요소가 변할 때만 함수가 실행된다.

 

useCallback

- 최적화, 함수 재사용시 

- deps에 들어오는 요소가 바뀔때만 해당 함수가 실행, 그렇지 않으면 기존함수 재사용되는 hook

- deps에 참조하고 있는 요소 넣기

 

//리렌더링 되는 함수 useCallback hook으로 감싸서 최적화 하기
const onRemove = useCallback(
  (id) => {
    setUsers(users.filter((user) => user.id !== id));
  },
  [users] //참조할 
);

const onToggle = useCallback(
  (id) => {
    setUsers(
      users.map(
        (user) => (user.id === id ? { ...user, active: !user.active } : user)
        //클릭 한 기존 객체 user를 가져와서 user.active의 상태를 반대로 변화 (true, false)
        //클릭 하지 않은 user은 그대로
      )
    );
  },
  [users]
);

 

- 어떤 함수가 리렌더링 되는지 알 수 있는 'react devtools' 사용하기

'react devtools' 의 ' Highlight updates when components render.'를 체크하여 렌더링 되고 있는 component 확인하기

- 간단하게 console로도 확인가능

 

↓ + 더 최적화하기 deps 사용 주의

 

 

+) Read.memo

- component 리렌더링 방지 (최적화)

 

export default React.memo(CreateUser); 
//React.memo - props가 바뀌었을 때만 리렌더링 해줌(최적화)

const User = React.memo(function User({~}){
})

 

//배열 삭제
const onRemove = useCallback((id) => {
  setUsers((users) => users.filter((user) => user.id !== id));
}, []);
//deps 배열을 비우고 (기존 users 참조하지말기) useState의 함수형 업데이트를 하기
//-> setUsers에서 최신 users를 조회하게 하기
  

//toggle
const onToggle = useCallback((id) => {
  setUsers((users) =>
    users.map(
      (user) => (user.id === id ? { ...user, active: !user.active } : user)
      //클릭 한 기존 객체 user를 가져와서 user.active의 상태를 반대로 변화 (true, false)
      //클릭 하지 않은 user은 그대로
    )
  );
}, []);
//deps 배열을 비우고 (기존 users 참조하지말기) useState의 함수형 업데이트를 하기
//-> setUsers에서 최신 users를 조회하게 하기

 

- 두번째 파라미터에 propsAreEqual 사용할 수 있다.

 

 

- 연산된 값을 재사용하기 위해서는 useMemo

- 특정함수를 재사용하기 위해서는 useCallback

- component 렌더링된 결과물을 재사용하기 위해서는 React.Memo

=> 성능 최적화 할 수 있겠다,  필요하겠다 싶을 때 사용하기. 그렇지 않으면 코드만 더 길어짐

 

 

useReducer

 

- useState 처럼 상태를 업데이트 할 수 있는 hook

- 차이점

useState - 설정하고 싶은 다음 상태를 직접 지정해주는 방식 (setValue(5))

useReducer - action이라는 객체를 기반으로 상태를 업데이트 한다. (dispatch({type: 'INCREMENT'}))

- 상태 업데이트 로직을 컴포넌트 밖으로 분리 가능

(action = 업데이트할때 참조한는 객체, dispatch = action을 발생시키는 함수)

- reducer : 상태를 업데이트하는 함수

- 첫번째 파라미터 reducer함수, 두번째 기본값

 

//useReducer
import { render } from "@testing-library/react";
import React, { useReducer } from "react";

//reducer함수 생성
function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
    //throw new Error('Unhandled action'); 둘 다 무관
  }
}

function Counter() {
  const [number, dispatch] = useReducer(reducer, 0); //첫번째 reducer함수, 두번쨰 초기값

  const onIncrease = () => {
    dispatch({
      type: "INCREMENT",
    });
  };

  const onDecrease = () => {
    dispatch({
      type: "DECREMENT",
    });
  };

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

 

 

+ App에서 useReducer 사용하기

- app에서 useState로 구현한 것을 useReducer로 구현해보기

- app component에서 사용할 초기상태를 component 밖에서 선언해주기

 

언제 사용하면 될까?

간단 - useState

복잡 - useReducer