Develop+

AddEventListener 를 useCallback으로 감싸보자! (feat. Lexical scope) 본문

React

AddEventListener 를 useCallback으로 감싸보자! (feat. Lexical scope)

Sunny Buddy 2023. 1. 26. 19:07
728x90

Naver Map api 를 사용해 맵을 클릭 할 때마다 해당 범위를 선택해 표시해주는 프로그램을 구현 중이었다. 

naver map에서 제공하는 addListener로 생성한 map 객체와 click에 addHex라는 함수를 추가해주는데
이 addHex라는 함수 내에서는 외부 변수인 data와 hexList라는 변수를 참조한다. 

컴포넌트가 생성되는 시점에 addEventListener을 해주니 data 에 값이 들어온 이후 시점에도 컴포넌트 생성 당시의 data값을 가지고 온다.

 

이거 이론으로만 들어봤던 Lexical scope 인 거 같다!

Lexical Scope
렉시컬 스코프는 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정된다.
출처: https://poiemaweb.com/js-scope

그래서 useEffect를 사용해 data와 hexList에 의존성을 부여한 후 addEventListener를 추가하고 return 에 removeEventListenr을 해주었다. 

useEffect(()=>{
	const event = naver.maps.Event.addListener(map, "click", addHex);

        return () => {
            naver.maps.Event.removeListener(event);
        }
},[data, hexList])

이렇게 하니 data와 hexList의 의존성에 의해 addHex가 할당되는 시점의 data, hexList를 참조할 수 있게 되었고 remove도 깔끔하게 되었다. 

이거보다 더 깔끔하게 리스너를 적용해보자!

이벤트 리스너를 위한 훅 만들기

function useListenerEvent(
    target: any,
    eventType: string,
    listener: any,
) {
    useEffect(() => {
        const event = target && naver.maps.Event.addListener(target, eventType, listener);

        return () => {
            naver.maps.Event.removeListener(event);
        }
    }, [target, listener])
}

 

일단 useEffect에 listener을 의존성에 주입해 리스너가 변경될 때마다 이벤트를 할당하는 이벤트 리스너 훅을 만들어보았다.

map(target)이 생성되는 시점과 리스너가 새로 들어올 때 실행된다.

addHex는 항상 같은 로직인데 계속 새로운 함수처럼 할당이 되고 있는데,  좀더 나은 코드로 발전시켜볼 수는 없을까?

addHex를 useCallback으로 감싸보려고 한다.

 

useCallback이란 리액트의 메모라이제인션 훅이다. 

같은 함수인데 state 값이 변경되거나 props값이 변경되어 컴포넌트가 재생성될 때 함수가 재 할당 되는 것이 방지할 수 있다. 

클릭을 할 때마다 addHex가 새로 할당되니 이 부분에서 useCallback을 사용해보려고 한다.

 

위에서 만든 리스너 훅에 마지막 인자인 listener를 useCallback으로 넣어주었다. 

useListenerEvent(map, "click", useCallback(addHex, [hexList, data]));

 

addHex 함수는 data와 hexList가 변경될 때에만 변경되면 되기 때문에 의존성에 data와 hexList를 넣어주었다. 

이제 addHex리스너는 data와 hexList 값이 변경될 경우에만 새로 만들어 지게 된다. 

 

function useListenerEvent(){
    .....이벤트 리스너 훅
}

const App () => {
	useListenerEvent(map, "click", useCallback(addHex, [hexList, data]));

	const addHex = () => {
		... 로직
	}

	return (<div></div>)
}

 

 

useCallback을 사용해보았는데 아직 익숙하지 않아 더 효율적으로 사용하고 싶은 마음이 크다. 

또 비용이 많이 드는 함수에 쓰는 것이 적합하다고 하니 남용할 수는 없고, 좋은 예제가 있다면 찾아서 적용해 보고싶다.


혹시나 더 나은 방법이나 수정해야 하는 부분이 있다면 댓글 남겨주세요!


728x90