React Hooks

kyuu·2021년 12월 17일
0

1. useEffect()

<마운트 / 언마운트 실행>

deps를 빈 배열로 설정 시 Clean up 함수를 호출해 Unmount시 실행
Callback function으로 Mount시 실행.

함수형 컴포넌트에서 componentDidMount(), componentWillUnmount() 등의 역할을 수행하기 위해 사용한다.

deps를 특정 state 값으로 설정하게 되면, 그 상태 값이 변경될 때 마다 콜백 함수를 실행한다.

useEffect() { () => {
    console.log("Mounted"); // Mount되었을 때 실행
    return () => { // Clean Up 함수, 언마운트 시 실행된다.
      console.log("Unmounted");
    };
  }
  ,[] // 마운트 / 언마운트시 deps는 비워둔다.
};

2. useRef()

useRef는 간단하게, ref 객체를 생성하는 훅이다. useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환하며 컴포넌트의 전 생애주기를 통해 유지된다.

const refContainer = useRef(initialValue);

이는 왜사용하며, useState 훅으로 생성한 상태값이랑 무엇이 다른가?

아래는 간단한 카운터 예제이며, useEffect 훅을 통해, setInterval 내장 함수가 실행되며, 이 내장 함수는 1,000ms마다 counter 상태 값을 1씩 올린다.
컴포넌트가 unmount되면, clearInterval 내장 함수로, 만든 timer 인터벌 객체를 제거하고 counter 상태값을 alert로 띄운다.
하지만 이렇게 작성하게되면, alert되는 값은 counter의 상태 값이 아니라, 0으로 뜨게 되는데, 이는 useEffect 훅이 컴포넌트가 마운트 될 때 단 한번 실행되기 때문이다.

한 단어로 정리하면, 자바스크립트의 closure 개념과 연관되어 있으며, 컴포넌트가 마운트 될 때 정의된 return function이, useEffect 훅 외부에서 정의된 counter 변수를 참조하는데, 이는 본래 외부 함수가 사라지며 counter 변수가 제거되어 return function이 호출될 때 참조할 수 없어야 한다.

“A closure is the combination of a function and the lexical environment within which that function was declared.”
클로저는 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합이다.
Closure 개념

하지만 자바스크립트의 closure 특성으로 인해 내부에서 정의된 함수가 외부 함수보다 오래 유지될 때, 외부 함수에서 정의된 지역 변수를 참조할 수 있다는 것인데.. 문제는 useState로 변경된 상태 값을 가져오는 것이 아니라, 초반에 정의된 Initial Value를 참조하는 것이다.

즉 간단하게 말하면, useState의 상태 값의 변화는, closure 내부 함수의 값까지 업데이트 해 줄 수 없다는 것이다.

function Counter() {
  const [counter, setCounter] = useState(0);
  useEffect(() => {
    const timer = setInterval(() => {
      setCounter(counter => counter + 1);
    }, 1000);
    return () => {
      clearInterval(timer);
      alert(counter);
    };
  }, []);
  return (
    <div>
      <p>{counter}</p>
    </div>
  );
}

이를 해결하기 위해 useRef로 만든 객체로 counter 변수를 바꿔보자.

function Counter() {
  const counterRef = useRef(0);
  const [counter, setCount] = useState(counterRef.current);

  useEffect(() => {
    const timer = setInterval(() => {
      setCounter(counter => counter + 1);
    }, 1000);
    return () => {
      clearInterval(timer);
      alert(counter);
    };
  }, []);
  return (
    <div>
      <p>{counter}</p> // 만약 counterRef로 바꾸면, 랜더링이 다시 되지 않는다. (0으로 유지)
    </div>
  );
}

위와 같이, 초기 값을 counterRef.current로 참조하게 되면, counter 값이 바뀔 때 마다 리랜더링되며, 언마운트 될 때 참조값도 제대로 받아올 수 있다.

중요한점이, useRef의 값은 상태가 아니며, 값의 변화가 리랜더링을 유도하지 않는다는 것이다.

useRef는 리액트 도큐먼테이션에 아래 세가지 경우에 사용할 것을 권장한다.
<추후 정리>
포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.
애니메이션을 직접적으로 실행시킬 때.
서드 파티 DOM 라이브러리를 React와 같이 사용할 때.

3. useMemo()

어떤 변수가, 다른 상태 값에 의존성을 가지고 그 상태값이 변경될 때 마다 계산되는 값을 가지게 하고 싶을 때 사용한다. 중요한 점은 변화하는 값이라는 것이 아니고, 변화 후 갖는 타입이 함수형이 아닌 특정 값의 타입으로 남는 다는 것이 중요한 것 같다.

아래는 useMemo()를 사용하여, 상태 값이 모두 입력되게 되면 true값을 갖게 하는 과정을 코드로 나타낸 것이다.

// 확인 해야 할 4가지 상태값
const largeBuildingType = myUseSelector((state) => state.registerRoom.largeBuildingType);
const buildingType = myUseSelector((state) => state.registerRoom.buildingType);
const roomType = myUseSelector((state) => (state.registerRoom.roomType));
const isSetUpForGuest = myUseSelector((state) => (state.registerRoom.isSetUpForGuest));

// isValid는 함수가 아닌 bool형 변수가 되며, 각 상태값이 바뀔 때 마다 검사하는 과정을 거친다.
const isValid = useMemo(() => {
        if(!largeBuildingType || !buildingType || !roomType || !isSetUpForGuest===null) {
            console.log("false");
            return false;
        }
        console.log("true");
        return true;
    }, [largeBuildingType, buildingType, roomType, isSetUpForGuest]);

/*
radio tag 밑 여러 입력을 통해 각 상태값이 업데이트 된다.
*/

// 계산된 형태는 React Component에 값의 형태로 넘겨줄 수 있음.
<RegisterRoomFooter isValid={isValid} prevHref="/" nextHref="/room/register/bedrooms"/>

위 예시와 같이 특정 태그에 변화하는 상태에 따른 check value로서 사용할 수 있는 것이다.

profile
!..!

0개의 댓글