본문 바로가기
Frontend/React

useEffect와 setState의 배치 처리

by 잘먹는 개발자 에단 2024. 12. 3.

사실 저번에도 올린 글이었는데, 다시 올린다.

 

 

리액트는 state가 바뀔 때마다 가상돔 비교를 통해서 화면을 다시 그린다. 

 

그렇다면 setState 될 때마다 화면이 다시 그려진다는 것인가? 그렇다.

 

그렇다면 setState가 많이 호출될 때마다 비효율적으로 동작할 수 있다는 건가? 그렇다.

 

하지만 꼭 필요한 setState는 당연히 써야겠지만, 대부분 아닌 경우가 많다. 

 

첫번째, 이벤트에 발생할 때 원하는 동작을 수행하게 하고 싶은 경우

때문에 예를 들어서 스크롤을 할때마다 어떠한 동작을 하고 싶다고 하면 

그냥 이벤트 리스너를 추가하는 것이 아니라, 꼭 '디바운싱' 처리를 해야한다.

 

디바운싱이란, N초 안에 1000번의 같은 이벤트가 발생하면, 해당 이벤트 리스너에 묶인 동작을 

1000번 실행하는 것이 아니라 1번으로 퉁치는 것이다. 

만약에 해당 동작이 state를 업데이트 하는 동작이라면, 화면을 쓸데 없이 999번 그리는 행동을 하게 되어

유저가 불편해질 것이다. 

 

 

그리고 다음과 같은 경우가 있다. 

a가 바뀌면 이를 바탕으로 b를 바꿔주거나 

b가 바뀌면 이후에 어떤 동작 a를 하고 바뀐 b를 바탕으로 새로운 b를 다시 업데이트 해주는 경우이다.

 

보통 로딩 중을 표시하기 위해서 이런 걸 많이 하고 하는데 예를 들어서 우리 이렇게 많이 하지 않능가?

const [isLoading, setIsLoading] = useState(false);

useEffect(()=>{
	if(isLoading){
    	// 로딩 중일 때 쏼라
    }else{
    	// 로딩이 끝났을 때 쏼라
    }
},[isLoading]);

 

이런식으로 처리를 하곤한다.

 

근데, 이게 이런 코드로 보면 간단하긴한데, 로딩을 한다는게 보통 어떤 api 엔드포인트에 요청하는 행위일 때가 많지 않능가? 때문에 이런 코드를 많이 쓰려고 시도한다. ( 나도 그랬다... )

 

export default function TestFunction(){
	const [isLoading, setIsLoading] = useState(false);
    const [data, setData] = useState(null);
    
    const fetchData = async() => {
    	try{
        	const axios 뭐시기 해서 가져왕
        }catch(ex){
        	~~~~~~
        }
    };
    
    useEffect(()=>{
    	setIsLoading(true);
        fetchDate();
        // 아앙 동기니까...
        setIsLoading(false);
        // 그 다음동작!
    },[]);
    
    return(
    	<div>
        	{isLoading&&<div>나 로딩중</div>}
            {data&&data.map~~~~~~}
        </div>
    );
}

 

뭐 이런 코드를 썼다고 하자. 그럼 원하는 동작은 처음에 페이지에 들어가면 

딱 한번 데이터를 가져오고 가져오기 전에 로딩 화면 보여주고, 그 이후에 로딩 끝나면 data map 돌리면서 보여주고

이거일테지만 그렇게 보이지 않는다. 

 

setState는 배치 처리를 하기 때문이다. 앞서 말했다 시피 모든 setState에 대응하면 브라우저는 계속 렌더링해줘야하고

계속 컴퓨팅 자원을 소모해야하기 때문에 비동기적으로 가장 마지막에 처리되어야 할 setState 동작을 수행한다.