검색을 하면 결과 테이블에 검색 단어에 대한 강조 스타일을 주고 싶다는 요구사항이 있어서 뚝딱 만들어 봤당
실제 서비스 개발을 하니까 포트폴리오 할 때랑은 다른 여러가지 구현을 도전할 수 있어서 재밌다!.!
const [searchTerm, setSearchTerm] = useState(searchParam || '');
const searchInputRef = useRef<HTMLInputElement>(null);
searchTerm
: 현재 검색어를 저장하는 statesearchInputRef
: 검색 input 요소를 참조하기 위한 refsearchParam
)가 있으면 초기값으로 사용const handleSearchInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(e.target.value);
const searchParams = new URLSearchParams(window.location.search);
searchParams.set('page', '1');
navigate(`?${searchParams.toString()}`);
};
const handleSearch = (e: FormEvent) => {
e.preventDefault();
const query = searchInputRef.current?.value || '';
const searchParams = new URLSearchParams(window.location.search);
if (query) {
searchParams.set('search', query);
searchParams.set('page', '1');
} else {
searchParams.delete('search');
searchParams.set('page', '1');
}
navigate(`?${searchParams.toString()}`);
};
handleSearchInputChange
: 입력값이 변경될 때마다 실시간으로 searchTerm
업데이트handleSearch
: 검색 폼 제출 시 URL의 검색 파라미터 업데이트⚠️ 1페이지가 아닌 다른 페이지에서 검색어를 입력해서 새로 데이터를 렌더링 하면 검색이 제대로 되지 않아서 검색 동작 시엔 페이지를 무조건 1페이지로 보내고 검색하도록 page 관련 코드 추가
const filteredData = tableData.filter(row => {
const matchesFilter =
filterType === '전체' || row.방문유형 === (filterType === '개인' ? 1 : 2);
const matchesSearch = searchTerm
? [row.체험자, row.체험학교, row.전화번호].some(field =>
field?.toString().toLowerCase().includes(searchTerm.toLowerCase())
)
: true;
return matchesFilter && matchesSearch;
});
const highlightText = (text: string) => {
if (!searchTerm?.trim() || !text) return <>{text}</>;
const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');
const regex = new RegExp(`(${escapedSearchTerm})`, 'gi');
const parts = text.split(regex);
return (
<>
{parts.map((part, index) => {
if (part.toLowerCase() === searchTerm.toLowerCase()) {
return <em key={index}>{part}</em>;
}
return part;
})}
</>
);
};
<em>
태그로 감싸서 하이라이트📌
/[.*+?^${}()|[\]\\]/g
[]
: 문자 클래스를 정의. 이 안에 있는 문자들 중 하나와 매칭- 특수문자들:
.*+?^${}()|[\]\
.
: 모든 문자와 매칭- ``: 0회 이상 반복
+
: 1회 이상 반복?
: 0회 또는 1회 매칭^
: 문자열의 시작$
: 문자열의 끝{}
: 반복 횟수 지정()
: 그룹화|
: OR 연산[]
: 문자 클래스\
: 이스케이프 문자g
: 전역 검색 (모든 매칭을 찾음)\\$&
\\
: 백슬래시를 이스케이프$&
: 매칭된 전체 문자열을 참조gi
: 전역(g)과 대소문자 구분 없이(i) 검색()
: 매칭된 부분을 그룹화하여 split 결과에 포함
<td>{highlightText(row.체험자)}</td>
<td>{highlightText(row.체험학교)}</td>
<td>{highlightText(row.전화번호)}</td>
각 셀에 highlightText
함수를 적용하여 검색어와 일치하는 부분 하이라이트
짜잔