Skip to content

Commit 8829813

Browse files
committed
refactor: separate components to prevent unnecessary rerendering
1 parent 614631a commit 8829813

2 files changed

Lines changed: 54 additions & 40 deletions

File tree

src/components/icons-list.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use client'
2+
3+
import { useRef } from 'react'
4+
import { useVirtualizer } from '@tanstack/react-virtual'
5+
6+
import { AddIconButton } from '@/components/add-icon-button'
7+
import { icons } from '@/assets/icons'
8+
9+
function IconsList({ searchValue }: { searchValue: string }) {
10+
const parentRef = useRef<HTMLDivElement>(null)
11+
12+
const filteredIcons = Object.entries(icons).filter((icon) =>
13+
icon[1].title.toLowerCase().includes(searchValue),
14+
)
15+
16+
const rowVirtualizer = useVirtualizer({
17+
count: filteredIcons.length,
18+
getScrollElement: () => parentRef.current,
19+
estimateSize: () => 66,
20+
gap: 16,
21+
})
22+
23+
return (
24+
<div
25+
className="max-h-[calc(100dvh-512px)] min-h-96 overflow-auto"
26+
ref={parentRef}
27+
>
28+
<div
29+
className="relative w-full"
30+
style={{
31+
height: `${rowVirtualizer.getTotalSize()}px`,
32+
}}
33+
>
34+
{rowVirtualizer.getVirtualItems().map((virtualRow) => (
35+
<div
36+
key={virtualRow.key}
37+
className="absolute left-0 top-0 w-full"
38+
style={{
39+
height: `${virtualRow.size}px`,
40+
transform: `translateY(${virtualRow.start}px)`,
41+
}}
42+
>
43+
<AddIconButton icon={filteredIcons[virtualRow.index][1]} />
44+
</div>
45+
))}
46+
</div>
47+
</div>
48+
)
49+
}
50+
51+
export { IconsList }

src/components/search-icons.tsx

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,22 @@
11
'use client'
22

3-
import { useRef, useState } from 'react'
4-
import { useVirtualizer } from '@tanstack/react-virtual'
3+
import { useState } from 'react'
54

65
import { Input } from '@/components/ui/input'
7-
import { AddIconButton } from '@/components/add-icon-button'
8-
import { icons } from '@/assets/icons'
6+
import { IconsList } from './icons-list'
97

108
function SearchIcons() {
11-
const parentRef = useRef<HTMLDivElement>(null)
129
const [searchValue, setSearchValue] = useState('')
1310

1411
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
1512
setSearchValue(event.target.value.toLowerCase())
1613
}
1714

18-
const filteredIcons = Object.entries(icons).filter((icon) =>
19-
icon[1].title.toLowerCase().includes(searchValue),
20-
)
21-
22-
const rowVirtualizer = useVirtualizer({
23-
count: filteredIcons.length,
24-
getScrollElement: () => parentRef.current,
25-
estimateSize: () => 66,
26-
gap: 16,
27-
})
28-
2915
return (
3016
<>
3117
<h2 className="text-xl font-bold">Search</h2>
3218
<Input placeholder="Search Icons" onChange={handleSearch} />
33-
<div
34-
className="max-h-[calc(100dvh-512px)] min-h-96 overflow-auto"
35-
ref={parentRef}
36-
>
37-
<div
38-
className="relative w-full"
39-
style={{
40-
height: `${rowVirtualizer.getTotalSize()}px`,
41-
}}
42-
>
43-
{rowVirtualizer.getVirtualItems().map((virtualRow) => (
44-
<div
45-
key={virtualRow.key}
46-
className="absolute left-0 top-0 w-full"
47-
style={{
48-
height: `${virtualRow.size}px`,
49-
transform: `translateY(${virtualRow.start}px)`,
50-
}}
51-
>
52-
<AddIconButton icon={filteredIcons[virtualRow.index][1]} />
53-
</div>
54-
))}
55-
</div>
56-
</div>
19+
<IconsList searchValue={searchValue} />
5720
</>
5821
)
5922
}

0 commit comments

Comments
 (0)