프로그래밍/Web(React, javascript)

[React] useEffect에서 클린업 함수

Hithero 2021. 11. 20. 00:03

요약 : useEffect에서 클린업 함수를 사용하고자한다면 useRef 함수를 이용해 최신 값을 가지고 있자!

useEffect 함수에서 클린업 함수(return시 사용하는 함수) 호출시, 초기값을 가지고 있는 문제가 있었다.

프로젝트를 진행하던 중, setState로 저장하고 있는 변수(A라고 하자)가 웹페이지에서 변경되고 있다가, 컴포넌트가 사라질 때(다른 페이지/컴포넌트로 랜더링될 때) 클린업 함수로 업데이트된 A변수를 DB에 저장하려고 했었다.

그런데 문제는 A변수가 처음값(처음 랜더링되었을 때 값)으로 출력이 된다는 것이다. (아래 예시)

const PageContentsList = () => {
  const [A, setA] = useState([]);

  const Update = async () => {
    	const updateList = [];
      	if (data.modified === true) { // 업데이트된 정보를 modified 가 true인데 바뀌지 않았다!
        	updateList.push({ _id: data.id, B: data.B });
      	}
    	});

    if (updateList.length > 0) {
      await fetch("/contents/update", {
        method: "PATCH",
        body: JSON.stringify(updateList),
        headers: {
          "Content-Type": "application/json",
        },
      });
    }
   };
  useEffect(() => {
    	fetchData();
    	return Update; // 클린업 함수 
        				// 참고 : 여기서 return Update() 로 하면, fetchData()와 같이 실행된다.
  }, []);
    
    ....
    
 }

처음에는 useState()의 비동기적 업데이트가 문제인 줄 알았다. 하지만 친구와의 1시간 넘는 토론끝에 useEffect가 동작하는 방식을 온전히 이해하고 있지 못해서 생기는 문제였던 것이다.

React Hooks에서는 useEffect가 componentDidMount, componentDidUpdate, componentWillUnmount를 대체하는데, 

useEffect(() => {
    "처음 렌더링시 & 의존성 deps가 변경될 때 실행되는 부분"
    return "unmount 될때 실행되는 부분 & 이전 이펙트 클린업 부분(의존성 deps가 변경될때) "
}, ["의존성 deps"])

익숙하지 않으면 간단하게 생각하자. 뒤에 ["의존성 deps"]은 변수가 들어간다.

예시로, useEffect(() => something(), [변수A]) 라고하면, 변수A가 변경될 떄 마다 useEffect는 실행된다. 변수A가 변경되면, 이전의 변수A 값을 가지고 return 함수가 실행된다.

ex) 변수A =1 ->2 변경되는 시점에서 , useEffect()에서 return 외에는 변수A는 2이고, return 상황에서는 변수A는 1이다.

뒤에 ["의존성 deps"]에 아무것도 없다면( ex) [] ) 첫 랜더링시에 실행되고, return은 컴포넌트 unmount시 실행된다.

https://www.stevy.dev/910cc101-c2ba-49d0-91ef-a562de43c5d6

 

useEffect 완벽 가이드 정리

Stevy의 개발 블로그 입니다

www.stevy.dev

useEffect에 관해 위의 링크에서 완벽하게 정리해준다. 궁금하다면 자세히 읽어보자. 내가 이해한 바를 말하자면, 

useEffect는 결과물이 중요하고, 과정을 따라가다보면 동기화에 실패한다.

useEffect 에서 return할때 (내 경우에는 unmount시) useState를 쓰는 변수는 최신의 값을 가지고 있지 않다. (-> 내가 하는 것에서 가장 중요한 부분이었다.)

그런데 해당 부분을 어떻게 해결하느냐? -> useRef로 최신의 값을 가지고 있는 것이었다.

const PageContentsList = () => {
  const [A, setAs] = useState([]);
  const latestA = useRef();			  // 최신의 값 가지고 있을 변수
    const newArr = A.map((data) => {
      if (data.id === targetId) {
        const { id, date, B } = data;
        return {
          id,
          date,
          B: B + 1,
          modified: true,
        };
      } // else
      return data;
    });
    latestA.current = newArr; 			// 최신의 state값을 업데이트!!
    
// 클린업 함수부분				// 최신 state값인 latestA를 사용한다.
  const Update = async () => {
    const updateList = [];
    if (latestA.current === undefined) return; // nothing to update
    latestA.current.forEach((data) => {
      if (data.modified === true) {
        updateList.push({ _id: data.id, B: data.B });
      }
    });
    
    ...
    
 }

 

Reference

https://www.stevy.dev/910cc101-c2ba-49d0-91ef-a562de43c5d6

https://velog.io/@dongha1992/React-useEffect-%EB%B6%80%EC%88%98%EA%B8%B0

https://killu.tistory.com/44

728x90
반응형