useEffect 활용 팁

이춘구·2022년 1월 27일
0

useEffect의 의존성 배열에는 비교연산자도 들어갈 수 있다.

의존성 배열에는 state 값을 넣고 state 값이 바뀔 때마다 useEffect가 실행되는 식으로 활용하는 줄만 알았는데 boolean 값으로 평가되는 비교식도 들어갈 수 있다는 걸 알게 됐다.

아래는 getWinNumbers()로 총 7개의 로또 번호를 뽑아 배열 winNumbers에 담아두고 1초에 하나씩 배열 winBalls에 담는 컴포넌트이다.

function App() {
  const lottoNumbers = useMemo(() => getWinNumbers(), []);
  const [winNumbers, setWinNumbers] = useState(lottoNumbers);
  const [winBalls, setWinBalls] = useState([]);
  const [bonus, setBonus] = useState(null);
  const [redo, setRedo] = useState(false);
  const timeouts = useRef([]);

  console.log("winBalls", winBalls);
  console.log("디펜던시 조건", winBalls.length === 3);

  useEffect(() => {
    console.log("useEffect 실행!");
    for (let i = 0; i < winNumbers.length - 1; i++) {
      timeouts.current[i] = setTimeout(() => {
        setWinBalls((prevBalls) => [...prevBalls, winNumbers[i]]);
      }, (i + 1) * 1000);
    }
    timeouts.current[6] = setTimeout(() => {
      setBonus(winNumbers[6]);
      setRedo(true);
    }, 7000);
    return () => {
      console.log("언마운트");
      timeouts.current.forEach((v) => {
        clearTimeout(v);
      });
    };
  }, [winBalls.length === 3]);

의존성 배열에 winBalls.length === 3가 들어가있는데,
곳곳에 console.log를 찍어두고 실행하면 아래의 결과가 나온다.

컴포넌트가 처음으로 Mount 되고 useEffect가 실행됐을 때, winBalls.length === 3은 false이고 winBalls에 숫자를 1초에 하나씩 담기 시작한다.
그러다 3개를 담았을 때 winBalls.length === 3가 true가 되고 이전 값(false)와 달라졌으니 컴포넌트가 unMount되고 다시 Mount되면서 useEffect가 두번째로 실행된다.
두번째 실행에서 winBalls 배열에 숫자가 하나 더 추가되어 length가 4가 되면, winBalls.length === 3은 false가 되고 이전 값(true)와 달라져서 컴포넌트가 unMount, 다시 Mount, useEffect가 실행된다.
그 뒤론 숫자가 추가되어도 winBalls.length === 3는 false이므로 useEffect는 다시 실행되지 않는다.

useEffect를 componentDidUpdate처럼 사용하기

useEffect는 컴포넌트가 componentDidMount일 때 실행되는 걸 막을 수는 없다.
그러니 첫 실행 때는 아무 것도 하지 않고 의존성 배열에 넣어둔 값이 바뀔 때만 동작을 실행하도록 하는 꼼수를 사용한다.

const mounted = useRef(false)  
useEffect(() => {
  if (!mounted.current) {
    mounted.current = true;
  } else {
    // 실행할 작업
  }
}, [바뀌는 값]);
profile
프런트엔드 개발자

0개의 댓글