본문 바로가기

Frontend/React

[React] useState 업데이트 값이 즉시 반영되지 않는 문제 (useState와 useRef)

반응형

1. 개요(문제)

  • 사용자의 현재 위치를 받아와 지도에 표시하고자 했다.
  • 초기 로직
    1. 위치 값 useState로 초기화하기
    2. navigator.geolocation.getCurrentPosition API를 통해 현재 위치 가져오기
    3. 받아온 값으로 state 업데이트하기
  • 하지만 useState 업데이트 값이 즉시 반영되지 않는 문제가 발생했다.
const Map = () => {
  const [curLoc, setCurLoc] = useState({lat: 0, lng: 0});

  const handleGeoSuccess = (pos) => {
    const lat = pos.coords.latitude;
    const lng = pos.coords.longitude;
    const coordsObj = {
      lat,
      lng,
    };
    setCurLoc(...coordsObj);
  };
  
  ...

  useEffect(() => {
    const getGeoLoc = () => {
      if (!navigator.geolocation) {
        alert('Geolocation is not supported by your browser');
      } else {
        navigator.geolocation.getCurrentPosition(
          handleGeoSuccess,
          handleGeoError
        );
      }
    };
    getGeoLoc();
  }, []);

  ...

  return (
  ...
      <GoogleMap
        mapContainerStyle={containerStyle}
        center={curLoc}
        zoom={10}
        onLoad={onLoad}
        onUnmount={onUnmount}
        onClick={() => setActiveMarker(null)}
      >
      </GoogleMap>
  ...
};

export default Map;

 

2. 원인

  • useState를 이용한 상태 업데이트는 비동기적이기 때문에 변경 사항이 즉시 반영되지 않는다.
  • useState의 업데이터는 이전 값을 기억(with 클로저)하고 있다가, 비동기 요청에서 사용 가능한 값으로 바꾼다.
  • 함수형 컴포넌트는 상태변경이 일어나면 함수를 다시 호출해 렌더링을 해야한다.
  • 즉, useState를 통해 업데이트할 때는 리렌더링이 필요하다.

 

3. 해결

  • useState 대신 useRef를 사용했다.
  • useRef업데이트 시 리렌더가 일어나지 않는 가변 값을 저장하는 데 사용할 수 있다.
const Map = () => {
  const centerRef = useRef({ lat: null, lng: null });

  const handleGeoSuccess = (pos) => {
    const lat = pos.coords.latitude;
    const lng = pos.coords.longitude;
    const coordsObj = {
      lat,
      lng,
    };
    centerRef.current = coordsObj;
    setIsGeoLoaded(true);
  };

  useEffect(() => {
    const getGeoLoc = () => {
      if (!navigator.geolocation) {
        alert('Geolocation is not supported by your browser');
      } else {
        navigator.geolocation.getCurrentPosition(
          handleGeoSuccess,
          handleGeoError
        );
      }
    };
    getGeoLoc();
  }, []);
  ...
  return (
  ...
      <GoogleMap
        mapContainerStyle={containerStyle}
        center={centerRef.current}
        zoom={10}
        onLoad={onLoad}
        onUnmount={onUnmount}
        onClick={() => setActiveMarker(null)}
      >
      </GoogleMap>
  ...
};

export default Map;

 

결과 이미지

사이트에 초기 접근 시 현재 위치인 K-SW Square가 바로 나오는 것을 확인할 수 있다.

 

 

참고) useRef

  • useRefJS DOM에 직접 접근이 가능하다. 따라서 특정 DOM을 가리킬 때 사용한다.
  • 주로 대상에 대한 포커스 설정, 특정 엘리먼트의 크기나 색상을 변경할 때 사용한다.
  • 즉, 리액트에서 컴포넌트의 특정 부분을 직접 선택할 수 있게 해주는 기능이다.

 

Reference

반응형

'Frontend > React' 카테고리의 다른 글

[React] CRA 프로젝트에 serviceWorker 적용하기  (0) 2021.08.30