위클리 미션의 요구사항을 수행하던 중, 내가 작성한 코드가 내가 의도한 것과 다르게 동작한다는 것을 알고 그것을 해결하는 과정을 기록해보고자 했다.
요구사항
링크 검색바에 검색어를 입력하면 현재 폴더에 있는 링크들 중 “url”, “title”, “description” 중 하나에 검색어가 포함된 링크들만 필터된 상태로 볼 수 있나요?
위의 요구사항을 보고 생각했던 코드 흐름은
- SearchingBar 컴포넌트의 input에서 검색어를 받는다.
- 검색어를 입력하고 엔터를 누르면 A이벤트가 실행되어 검색어를 state 값으로 저장한다.
- 데이터를 Map으로 돌려서 컴포넌트에 전달하기 전에, filter을 통해 검색어를 거른 후 전달한다.
그리고, 이 흐름대로 코드를 작성해보았다.
// 검색어를 전달 받은 컴포넌트 (검색어를 저장하는 과정은 생략)
// 데이터를 받아오는 함수
const handleLoadFolder = async ({
folderId,
searchKeyWord, //검색어
}: LoadFolderDataProps) => {
const { data } = await getFolders({ folderId });
setFolder(data);
if (searchKeyWord) {
const filterData = folder.filter(
(link) =>
link.description?.includes(searchKeyWord) ||
link.url?.includes(searchKeyWord) ||
link.title?.includes(searchKeyWord)
); // 전달받은 검색어를 이용하여, filter함
setFolder(filterData); //filter된 데이터를 state값으로 저장
}
};
useEffect(() => {
handleLoadFolder({ folderId, searchKeyWord });
}, [folderId, searchKeyWord]); //searchKeyWord가 변경될 때마다 재렌더링 되도록 함
그런데 검색 기능이 40% 정도 부족하게 동작했다. (ㅋㅋ 40%?)
검색 기능 동작
검색은 검색어를 입력한 후, 엔터키를 누르는 것
- 페이지가 처음 로드되고, 검색 시 검색이 잘 됨
- 빈값으로 지우고 검색 시, 전체 데이터가 잘 나옴
- 검색한 후, 다른 키워드로 연달아 검색
- ' r ' 검색 후, ' d ' 추가해서 ' rd ' 검색하면 검색이 됨
- '코드잇' 검색 후, 지우고 '유병재' 검색 시 안됨 (빈 카드라고 뜸)
- 검색어 입력 후 검색 시, Network에서 요청은 잘 가고 있음
내가 원하는 동작은 검색 후, 지우고 새로운 검색어를 입력했을 때도 정상적으로 동작하는 것이다.
이렇게 동작하는 이유는 처음 검색하며 필터된 데이터 안에서 두 번째로 검색한 검색어를 찾기 때문이다.
원인을 대충 알았으니,
handleLoadFolder 안의 동작 순서를 유추해보자.
1. getFolders를 통해 데이터를 받아온다.
2. 페이지 처음 로드시에는 setFolder에 필터링 되지 않은 data 를 저장한다.
3. 첫 검색시, searchKeyWord를 이용하여 필터링된 데이터를 setFolder에 저장한다.
4. 두 번째 검색 시, useEffect에 의해서 handleLoadFolder 함수가 다시 렌더링 되지만 필터링 되지 않은 data를 저장하기 전에 if문이 동작하여 필터링한다.
=> handleLoadFolder의 내부 로직이 순차적으로 실행되지 않았다.
이를 해결하기 위해서, 함수형 업데이트를 사용하여 함수 안의 로직이 순차적으로 실행되도록 했다.
필터링 되지 않은 데이터를 먼저 state값에 넣고, 이 값에서 필터링되어야하기 때문이다.
const handleLoadFolder = async ({
folderId,
searchKeyWord,
}: LoadFolderDataProps) => {
const { data } = await getFolders({ folderId });
setFolder(data);
if (searchKeyWord) {
setFolder((prevFolder) => //함수형 업데이트로 이전 상태값을 참조
prevFolder.filter(
(link) =>
link.description?.includes(searchKeyWord) ||
link.url?.includes(searchKeyWord) ||
link.title?.includes(searchKeyWord)
)
);
}
};
위와 같이 코드를 수정하자, 정상적으로 작동했다!
동작 영상
배포 링크
https://velvety-madeleine-ad028f.netlify.app/
'💡뚝딱뚝딱 만들어보자 ~! :) > Linkbrary' 카테고리의 다른 글
[Refactoring] 모듈화 및 추상화를 통한 API함수 개선해보기 (0) | 2024.05.21 |
---|---|
[Refactoring] ContextAPI로 Modal 컴포넌트 개선하기 (0) | 2024.04.10 |
react-hook-form으로 로그인, 회원가입 기능 구현하기 (1) | 2024.04.06 |
커스텀 훅 도전기 (feat.Intersection Observer) (0) | 2024.04.01 |