Skip to content

Commit

Permalink
Optimize api calls (#310)
Browse files Browse the repository at this point in the history
* feat: add some prefetching

* feat: add some prefetching

* feat: prefetch links
  • Loading branch information
Jujulego authored Feb 8, 2025
1 parent 5f25d96 commit 5de1ab8
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 15 deletions.
4 changes: 4 additions & 0 deletions components/map/MapboxMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import { styled } from '@mui/material';
import type * as mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import { useEffect, useRef } from 'react';
import { preconnect, prefetchDNS } from 'react-dom';

// Component
preconnect('https://api.mapbox.com');
prefetchDNS('https://events.mapbox.com');

export interface MapboxMapProps {
readonly zoom: number;
readonly onMapCreated: (map: mapboxgl.Map) => void;
Expand Down
23 changes: 14 additions & 9 deletions components/search/AnimalSearchOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
import { SearchContext, useLoadingSearchOptions } from '@/components/search/search.context';
import SearchOption from '@/components/search/SearchOption';
import { fetchAnimalTracking } from '@/data/club-ocean';
import PetsIcon from '@mui/icons-material/Pets';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import PetsIcon from '@mui/icons-material/Pets';
import { use, useMemo } from 'react';
import useSWR from 'swr';
import { AnimatePresence } from 'motion/react';
import { use } from 'react';
import useSWR from 'swr';

// Component
export default function AnimalSearchOptions() {
const { inputValue } = use(SearchContext);

const isAnimal = useMemo(() => ANIMAL_RE.test(inputValue), [inputValue]);
const key = isAnimal ? `animal:${inputValue.toLowerCase()}` : null;

const { data, isValidating } = useSWR(key, { fetcher: animalFetcher });
const { data, isValidating } = useSWR(
ANIMAL_RE.test(inputValue)
? ['animal', inputValue.toLowerCase()]
: null,
{ fetcher: animalFetcher }
);
useLoadingSearchOptions(isValidating);

return (
Expand All @@ -36,6 +39,8 @@ export default function AnimalSearchOptions() {
// Utils
const ANIMAL_RE = /^[a-z]{3,}$/i;

function animalFetcher(key: string) {
return fetchAnimalTracking(key.slice(7));
type AnimalKey = readonly ['animal', string];

function animalFetcher([, name]: AnimalKey) {
return fetchAnimalTracking(name);
}
2 changes: 1 addition & 1 deletion components/search/DnsSearchOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function DnsSearchOptions() {
return (
<AnimatePresence>
{ ips.map((ip) => (
<SearchOption key={ip} href={`/ip/${ip}`}>
<SearchOption key={ip} href={`/ip/${encodeURIComponent(ip)}`}>
<ListItemIcon sx={{ minWidth: 40 }}>
<WebIcon color="inherit" />
</ListItemIcon>
Expand Down
11 changes: 10 additions & 1 deletion components/search/SearchListBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ export interface SearchListBoxProps {

export default function SearchListBox({ ref, listBoxId, children }: SearchListBoxProps) {
return (
<List id={listBoxId} ref={ref} role="listbox" disablePadding sx={{ maxHeight: 226, overflowY: 'auto' }}>
<List
id={listBoxId}
ref={ref}

disablePadding
sx={{ maxHeight: 226, overflowY: 'auto' }}

aria-label="Search"
role="listbox"
>
{ children }
</List>
);
Expand Down
13 changes: 10 additions & 3 deletions components/search/SearchOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { SearchContext } from '@/components/search/search.context';
import SearchListItem from '@/components/search/SearchListItem';
import ListItemButton from '@mui/material/ListItemButton';
import { AnimatePresence, usePresence } from 'motion/react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { type MouseEvent, type ReactNode, use, useCallback, useEffect, useId, useMemo } from 'react';

Expand All @@ -16,11 +17,16 @@ export default function SearchOption({ href, children }: SearchOptionProps) {
const id = useId();
const [isPresent, safeToRemove] = usePresence();

const { activeOption, isOpen, search, setActiveOption, registerOption, unregisterOption } = use(SearchContext);
const { activeOption, isOpen, inputValue, search, setActiveOption, registerOption, unregisterOption } = use(SearchContext);
const pathname = usePathname();
const isSelected = pathname === href;

const url = useMemo(() => new URL(href, location.origin + pathname), [href, pathname]);
const url = useMemo(() => {
const url = new URL(href, location.origin + pathname);
url.searchParams.set('search', inputValue);

return url;
}, [href, inputValue, pathname]);

useEffect(() => {
registerOption(id, url);
Expand All @@ -39,6 +45,7 @@ export default function SearchOption({ href, children }: SearchOptionProps) {
}, [id, setActiveOption]);

const handleClick = useCallback((event: MouseEvent) => {
event.preventDefault();
search(url);
}, [url, search]);

Expand All @@ -55,7 +62,7 @@ export default function SearchOption({ href, children }: SearchOptionProps) {
>
<ListItemButton
className={activeOption === id ? 'Mui-focusVisible' : ''}
component="a" href={url.toString()}
component={Link} href={url.toString()} prefetch
onClick={handleClick}
tabIndex={-1}
selected={isSelected}
Expand Down
9 changes: 8 additions & 1 deletion hooks/useDnsLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { DnsResponse } from '@/data/dns';
import { jsonFetch } from '@/utils/fetch';
import { filter$, map$, pipe$ } from 'kyrielle';
import { useMemo } from 'react';
import { preload } from 'react-dom';
import useSWR from 'swr';

export interface DnsLookupState {
Expand All @@ -27,7 +28,13 @@ export function useDnsLookup(name: string | null): DnsLookupState {
}

function useDnsQuery(name: string | null, type: number) {
return useSWR<DnsResponse>(name ? `https://dns.google.com/resolve?type=${type}&name=${name}` : null, jsonFetch);
const url = `https://dns.google.com/resolve?type=${type}&name=${name}`;

if (name) {
preload(url, { as: 'fetch', crossOrigin: 'anonymous' });
}

return useSWR<DnsResponse>(name ? url : null, jsonFetch);
}

function extractIps(type: number, data?: DnsResponse) {
Expand Down

0 comments on commit 5de1ab8

Please sign in to comment.