프리온보딩 사전 미션 (검색어와 일치하는 글자 하이라이트)
24년 8월 프리온보딩 사전미션
위 영상과 동일한 기능의 화면을 만들기를 한 기록
구현 내용
- Input 박스, 검색버튼
- 검색어를 입력했을 때 dummy data를 보여주기
- 검색어와 일치하는 dummy data text에 하이라이트하기
결과물
입력값이 없을 때
a를 입력했을 때
apple inc(특정 단어)를 입력했을 때
코드
1. Input 박스, 검색버튼 등 UI 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
return (
<>
<div id="main">
<form className="search-form">
<input
className="search-input"
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<button type="submit">검색</button>
</form>
<--- dummy data 내용 --->
</div>
</>
);
3. dummy data를 type을 기준으로 초기화하기
1
2
3
4
5
6
7
8
9
10
const categorized = dummy.reduce((acc: Categorized, item: DummyItem) => {
const { type } = item;
if (!acc[type]) {
acc[type] = [];
}
acc[type].push(item);
return acc;
}, []);
4. dummy data item의 text가 검색어와 일치하면 하이라이트하기
- 검색어(hightlight)를 기준으로 text을 나눔
- 검색어(hightlight)와 일치하는 문자는
<b>
태그를 사용해서 굵은 문자로 반환 - 일치하지 않는 문자는 그냥 리턴
1
2
3
4
5
6
const handleHighlightedText = (text: string, highlight: string) => {
const splitText = text.split(new RegExp(`(${highlight})`, "gi"));
return splitText.map((t, index) =>
t.toLowerCase() === highlight.toLowerCase() ? <b key={index}>{t}</b> : t
);
};
5. 위의 기능을 추가한 dummy data UI
- 검색어를 입력하지 않았을 때는 보여주지 않음
- dummy data의 type별로 내용을 구분해서 화면에 출력
handleHighlightedText
함수를 사용해서 검색어와 일치하는 내용 하이라이트 처리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
searchTerm.length > 0 && (
<div className="dummy-data-container">
{Object.keys(categorized).map((key) => (
<>
<div className="dummy-data-type">{key}</div>
<ul className="dummy-data-item-container">
{categorized[key].map((item: DummyItem) => (
<li key={item.key} className="dummy-data-item">
{handleHighlightedText(item.description, searchTerm)}
</li>
))}
</ul>
</>
))}
</div>
);
}
전체 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { useState } from "react";
import "./App.css";
// @ts-expect-error: TypeScript declaration file for 'data.js' is missing
import { dummy } from "./data.js";
interface DummyItem {
description: string;
key: string;
type: string;
}
interface Categorized {
[key: string]: DummyItem[];
}
function App() {
const [searchTerm, setSearchTerm] = useState < string > "";
const categorized = dummy.reduce((acc: Categorized, item: DummyItem) => {
const { type } = item;
if (!acc[type]) {
acc[type] = [];
}
acc[type].push(item);
return acc;
}, []);
const handleHighlightedText = (text: string, highlight: string) => {
const splitText = text.split(new RegExp(`(${highlight})`, "gi"));
return splitText.map((t, index) =>
t.toLowerCase() === highlight.toLowerCase() ? <b key={index}>{t}</b> : t
);
};
return (
<>
<div id="main">
<form className="search-form">
<input
className="search-input"
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<button type="submit">검색</button>
</form>
{searchTerm.length > 0 && (
<div className="dummy-data-container">
{Object.keys(categorized).map((key) => (
<>
<div className="dummy-data-type">{key}</div>
<ul className="dummy-data-item-container">
{categorized[key].map((item: DummyItem) => (
<li key={item.key} className="dummy-data-item">
{handleHighlightedText(item.description, searchTerm)}
</li>
))}
</ul>
</>
))}
</div>
)}
</div>
</>
);
}
export default App;
This post is licensed under CC BY 4.0 by the author.