원글 페이지 : 바로가기
프로젝트를 진행하며 콘솔로 받아온 데이터를 확인하는데 계속 두번 씩 데이터를 받아오는 것을 발견했다. 현재 프로젝트의 규모가 작아 당장은 상관 없으나, 나중에 서버와 연결했을 경우 정확한 원인을 알 수 없으니 메모리 누수가 생길 수도 있는 점을 고려하지 않을 수 없었다. 그래서 오늘은 그에 대한 트러블 슈팅 기록을 하고자 한다. 😇 너 뭔데 왜 2번씩 출력되는데 // SearchInput.tsx
const enterKeyHandler: KeyboardEventHandler
const locationInfo = filteredTitle(inputSearch);
if (e.key === “Enter” && locationInfo.length !== 0) {
api(setData, locationInfo); // 유저가 엔터키 이벤트를 발생시켰을 때, data state를 업데이트(데이터를 받아옴)하고, location에 담긴 title을 필터된 변수를 api 함수로 호출한다.
setIsSearchToggle(false);
} else if (e.key === “Enter” && locationInfo.length === 0) {
alert(“일치하는 도시를 찾을 수 없습니다! 😢”);
setInputSearch(“”);
}
} 사용자가 검색창(input)에 값을 입력하고 엔터키로 이벤트가 발생하였을 때 api가 호출될 수 있도록 하였다. 리액트를 사용하고 있기 때문에 onKeyDown(js는 keydown) 이벤트를 연결해주었다. 그런데 계속 데이터가 두번씩 받아와지는게 아닌가..? (당황) 그 말인 즉슨, 똑같은 이벤트가 2번 발생된다는 얘기이다. 처음에는 핸들링 함수 내에서 잘못 조작하고 있거나 api 함수 내에서 중복으로 호출하고 있는 것이라고 생각했다. // api.ts
export default function api(
setFn: React.Dispatch
locationInfo: locationInfo[]
) {
const API_KEY = process.env.REACT_APP_API_KEY;
const API_URL = process.env.REACT_APP_API_URL;
const BASE_DATE = year + month + day;
const BASE_TIME = hours + String(Number(minutes) – 30);
const LOCATION = locationInfo;
const url = `${API_URL}?serviceKey=${API_KEY}&numOfRows=60&pageNo=1&base_date=${BASE_DATE}&base_time=${BASE_TIME}&nx=${LOCATION?.[0]?.nx}&ny=${LOCATION?.[0]?.ny}&dataType=json`;
fetch(url)
.then((res) => res.json())
.then((res) => {
setFn(res.response.body.items.item);
})
.catch((err) => console.log(“error:”, err));
} 문제는 없어보였다.. 이때부터 왜이러는지 이유를 몰라 멘붕 그잡채..살려줘.. 구글링을 해보니 React Strict mode 때문에 이중으로 호출될 수 있다고 한다. Strict 모드 – React A JavaScript library for building user interfaces ko.legacy.reactjs.org Strict 모드가 자동으로 부작용을 찾아주는 것은 불가능합니다. 하지만, 조금 더 예측할 수 있게끔 만들어서 문제가 되는 부분을 발견할 수 있게 도와줍니다. 이는 아래의 함수를 의도적으로 이중으로 호출하여 찾을 수 있습니다. – 클래스 컴포넌트의 constructor, render 그리고 shouldComponentUpdate 메서드 – 클래스 컴포넌트의 getDerivedStateFromProps static 메서드 – 함수 컴포넌트 바디 – State updater 함수 (setState의 첫 번째 인자) – useState, useMemo 그리고 useReducer에 전달되는 함수 ⚠️ 주의 – 개발 모드에서만 적용됩니다. 생명주기 메서드들은 프로덕션 모드에서 이중으로 호출되지 않습니다. 하지만 프로젝트를 시작하면서
const enterKeyHandler: KeyboardEventHandler
const locationInfo = filteredTitle(inputSearch);
if (e.nativeEvent.isComposing) return; // composition 단계일 때(한글일 때) return하도록 코드 추가
if (e.key === “Enter” && locationInfo.length !== 0) {
api(setData, locationInfo);
setIsSearchToggle(false);
} else if (e.key === “Enter” && locationInfo.length === 0) {
alert(“일치하는 도시를 찾을 수 없습니다! 😢”);
setInputSearch(“”);
}
} 이제 정상적으로 1번만 호출된다!! ⭐️ TL;DR 트러블 슈팅 input value 입력값으로 키보드 이벤트(keydown) 발생 시 api가 이중 호출되는 문제 해결방법 React Strict Mode로 설정되어 있는지 확인 후 해제 keyup, keydown 이벤트를 keypress 이벤트로 변경 MDN Deprecated event.isComposing === true 일 때 return; (React에서는 event.nativeEvent.isComposing 값을 참조) https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event https://ko.legacy.reactjs.org/docs/strict-mode.html https://www.inflearn.com/questions/9010/%ED%95%9C%EA%B8%80-%EC%9E%85%EB%A0%A5%EC%8B%9C-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EA%B0%80-%EB%91%90%EB%B2%88-%EB%B0%9C%EC%83%9D%EB%90%A9%EB%8B%88%EB%8B%A4 https://velog.io/@dosomething/React-%ED%95%9C%EA%B8%80-%EC%9E%85%EB%A0%A5%EC%8B%9C-keydown-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%A4%91%EB%B3%B5-%EB%B0%9C%EC%83%9D-%ED%98%84%EC%83%81 https://levelup.gitconnected.com/javascript-events-handlers-keyboard-and-load-events-1b3e46a6b0c3