Как отображать большие данные в nextjs в области просмотра?
Я хочу сделать раскрывающийся список, в котором пользователь может выбрать токен erc20 из списка токенов в Nextjs.
Я попробовал обычную функцию сопоставления в списке токенов, но тогда сайт не отвечает и работает очень медленно, потому что файл tokenlist.json . Я хотел бы отображать данные в окне просмотра. Как я могу этого добиться?
Я хотел бы сделать это быстро, как в модальном окне выбора токена в Uniswap.
Я использовал изображение nextjs, и это загружает изображение токена, когда оно находится в поле зрения, но оно все еще медленно, потому что ему нужно отобразить имя и символ токена.
Вот как я получаю список токенов и отображаю его:
import { Fragment, useEffect, useState } from 'react';
import { Combobox, Transition } from '@headlessui/react';
import { CheckIcon, SelectorIcon } from '@heroicons/react/solid';
import { PlusSmIcon } from '@heroicons/react/outline';
import axios from 'axios';
import tokensJson from '../web3/tokens.json';
import Image from 'next/image';
export default function SelectErc20() {
const [selected, setSelected] = useState(tokensJson.tokens[0]);
const [tokenlist, setTokenlist] = useState([]);
const [query, setQuery] = useState('');
const filteredTokens =
query === ''
? tokenlist
: tokenlist.filter((token) =>
token.name
.toLowerCase()
.replace(/\s+/g, '')
.includes(query.toLowerCase().replace(/\s+/g, ''))
);
useEffect(() => {
axios
.get('https://tokens.coingecko.com/uniswap/all.json')
.then((res) => {
setTokenlist(res.data.tokens);
})
.catch(setTokenlist(tokensJson.tokens));
}, []);
return (
<div className="flex items-center space-x-3">
<img src={selected.logoURI} alt="token" className="h-6 w-6" />
<div className="w-64">
<Combobox value={selected} onChange={setSelected}>
<div className="relative mt-1">
<div className="relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left shadow-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-300 sm:text-sm">
<Combobox.Input
className="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:ring-0"
displayValue={(token) => token.name}
onChange={(event) => setQuery(event.target.value)}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
<SelectorIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</Combobox.Button>
</div>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Combobox.Options className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
<a
href="#"
className="relative mb-3 flex select-none items-center space-x-3 py-2 px-4 text-gray-700 hover:bg-neutral-100"
>
<PlusSmIcon className="h-5 w-5" />
<span>Add custom token</span>
</a>
{filteredTokens.length === 0 && query !== '' ? (
<div className="relative select-none py-2 px-4 text-gray-700">
<span>Nothing found..</span>
</div>
) : (
filteredTokens.map((token) => (
<Combobox.Option
key={token.address}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? 'bg-emerald-600 text-white' : 'text-gray-900'
}`
}
value={token}
>
{({ selected, active }) => (
<div className="flex items-center justify-between">
<div className="flex items-center truncate">
<Image
src={token.logoURI}
alt={token.name}
width="24"
height="24"
className="mr-3"
/>
<span
className={`block truncate ${
selected ? 'font-medium' : 'font-normal'
}`}
>
{token.name}
</span>
</div>
<span
className={`block text-xs text-gray-400 ${
selected ? 'font-medium' : 'font-normal'
} ${active ? 'text-white' : null}`}
>
{token.symbol}
</span>
{selected ? (
<span
className={`absolute inset-y-0 left-0 flex items-center pl-3 ${
active ? 'text-white' : 'text-emerald-600'
}`}
>
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</div>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Transition>
</div>
</Combobox>
</div>
</div>
);
}
1 ответ
Это потому, что вы визуализируете слишком много узлов HTML, и ваш навигатор не может их нарисовать.
Чтобы сделать то, что вам нужно, вы должны использовать то, что мы называем «виртуальным списком».
Библиотек для виртуализации мало, вы не первый.
Посмотрите, например, React Window