본문 바로가기
항해99/실전 WIL | TIL

[TIL-022] React Lv4 과제(4) - useMemo를 사용해 유효성 검사하기

by junvely 2023. 5. 4.

Today목표 : 05/03일 React Lv4 과제(4) - useMemo 사용해보기 / 주의할점


JSON서버 사용시 문제점 

❗API 데이터 통신 시 id값을 비교하여 데이터를 가져올 때, 타입비교에 따른 에러 발생

문제상황

JSON 서버 DB에 저장된 id값이 문자열일경우 데이터를 찾아오지 못해 undefined가 발생했다. ===로 타입까지 비교하였을 때 발생한 문제였다. id값을 숫자타입으로 변경해 주면 문제가 없었다. 서버에서 같은 id를 가져와 비교하는데 왜 문제인지 이해가 안됐다.

const getPostAxios = async (id) => {
  try {
    const { data } = await Axios.get("/posts");
    const post = data.find((post) => post.id === parseInt(id));
    return post;
  } catch (error) {
    console.log("axios getPost Error :");
    throw error;
  }
};

해결방법

서버의 id값을 숫자값으로 변경하거나, 비교연산자를 ==으로 사용하면 정상적으로 처리 된다.

    const post = data.find((post) => post.id == id);

 

 

useMemo를 이용해 유효성 검사하기

먼저 나는 유효성 검사 로직을 이런식으로 진행하고자 하였다.

1. input에 값을 입력 시마다 state에 값을 저장

2. idMessage 함수에서 유효성검사 후 내보낼 메세지값을 return

3. idMessage 변수에 담긴 값을 input컴포넌트에 전달하여 input컴포넌트 내부에서 에러메세지를 띄움

  const [inputs, handleInputChange] = useInputs(initialState);

  const idMessage = () => {
    if (!inputs.id || inputs.id.length < 5 || inputs.id.length >= 10) {
      return "id를 확인해주세요";
    } else {
      return "통과";
    }
  }
  
  return(
  <LabelInput
            name="id"
            value={inputs.id}
            onChange={handleInputChange}
            message={idMessage()} // 주의할 점, 이 때는 화살표 함수이기 때문에 호출해줘야 함
          >

이 때, 페이지가 렌더링 되면서 message에 idMessage()함수의 결과값을 리턴한다. => 그 후 어떤 input이든 값을 입력할 때 마다 state가 변경되어 리렌더링이 되기 때문에 다시 idMessage()함수가 계속 호출되며 값을 계산하여 return하여 message에 전달해 준다.

즉, 리렌더링 시 마다 변수나 함수를 호출을 재실행 하여 값을 저장하기 때문에 내가 업데이트 하고자 하는 값이 아닌 다른 input을 입력하거나 다른 state가 변경될 때에도 리렌더링 되어 불필요하게 값이 계속해서 계산되고 return된다.

 

문제 상황

1. 내가 필요한 값이 업데이트될 필요가 없는데도 리렌더링에 의해 재 실행되어 값을 저장한다. 

2. 이때 만약 함수에서 무거운 로직을 수행 후 return한 변수 값을 사용할 경우, 리렌더링이 될 때마다 무거운 로직을 수행하게 되어 조금씩 딜레이가 생기게 된다.

 

해결 방법

❗이런 문제 때문에 useMemo를 이용하여 기존 값을 캐싱해놓고 불필요한 리렌더링에 의해 다시 값이 계산되는 것을 방지하고자 하였다. 이렇게 하면 첫 렌더링 이후(의존성 배열이 [ ] 빈 배열이라면) 부터는 값이 캐싱되어 리렌더링 시에도 함수를 재실행시키지 않고 캐싱된 값을 반환한다.

이 때 의존성 배열안에 값을 추가하여 그 값을 관찰하게 되면, 그 값이 변경될 때에만 업데이트가 일어난다. 즉 그 값만 관찰하여 변경시에만 해당 함수가 실행되어 return하면서 값을 업데이트 한다.

코드는 다음과 같다.

  const idMessage = useMemo(() => {
    if (!inputs.id || inputs.id.length < 5 || inputs.id.length >= 10) {
      return "id를 확인해주세요";
    } else {
      return "통과";
    }
  }, [inputs.id]);
  
  <LabelInput
            name="id"
            value={inputs.id}
            onChange={handleInputChange}
            message={idMessage} // ❗주의 이 때는 화살표 함수가 아니라 변수에 useMemo가 캐싱한 값을 담는 것이다.
          >

이때 주의할 점은 ❗이 전에는 화살표 함수를 호출했지만, useMemo를 사용하면 내부에서 그 캐싱된 값을 담는 것이기 때문에 변수로 호출해 주어야 한다! 이것 때문에 꽤 애먹었다...

그리고, 무분별하게 useMemo를 사용할 경우, 값을 캐싱하는 것이 메모리를 차지하는 것이므로 오히려 더 성능이 악화될 수 있다. 꼭 필요한 경우에만 사용하도록 한다.

지금까지는 내가 느끼기에 useMemo를 사용할 경우는

1. 리렌더링이 빈번하게 일어날 때, 어떤 함수의 return값을 사용해야 할 경우 => 유효성 검사

2. 무거운 로직을 수행하는 함수의 return값을 사용할 경우

등이라고 생각 된다. 프로젝트를 더 진행하고 최적화를 연습하면서 사용할 수 있는 부분이 더 있는지 찾아봐야 할 것 같다!