Мне нужно получить изображение в кодировке base64 в useEffect, а затем создать тег изображения на странице. Мой (упрощенный) код выглядит следующим образом:
const App => {
const [image, SetImage] = useState('');
useEffect(
async function fetchImage() {
//...
await response = fetch('API-to-get-base64image');
SetImage(response);
}, [])
return (
<div><img src = {image}/> </div>
)
}
Мне нужно запустить этот useEffect только один раз, потому что изображение большое, а его запуск дважды замедляет загрузку страницы. Но, как указано во многих сообщениях, подобных этому: Как вызвать функцию загрузки с помощью React useEffect только один раз, начиная с React 18, установка зависимости в виде пустого массива больше не дает такого эффекта. Интересно, какое новое решение позволяет этому useEffect запускаться только один раз?
У меня была такая же проблема, пока я не прочитал раздел «Глубокое погружение» в Извлечение данных с помощью эффектов в документации React.
Соответствующий бит:
Этот список недостатков не относится только к React. Это относится к получение данных при монтировании с помощью любой библиотеки. Как и в случае с маршрутизацией, данные извлечение не является тривиальной задачей, поэтому мы рекомендуем следующее подходы:
- Если вы используете фреймворк, используйте его встроенный механизм получения данных. Современные фреймворки React имеют интегрированные механизмы получения данных, которые эффективны и не страдают от вышеперечисленных недостатков.
- В противном случае рассмотрите возможность использования или создания кэша на стороне клиента. Популярные решения с открытым исходным кодом включают React Query, useSWR и React Router. 6,4+. Вы также можете создать свое собственное решение, и в этом случае вы будете использовать эффекты «под капотом», а также добавить логику для дедупликации запросов. кэширование ответов и избежание сетевых водопадов (путем предварительной загрузки данных или повышение требований к данным для маршрутов).
В моем случае useSWR уже был частью зависимостей проекта, и, судя по примеру, его довольно просто использовать:
import useSWR from 'swr'
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
Впоследствии я убедился, что Извлечение происходит только один раз, счастливых дней...
Итак, для вашего кода это будет что-то вроде:
import useSWR from 'swr'
const App => {
const [image, SetImage] = useState('');
async function fetchImage(url) {
//...
await response = fetch(url);
SetImage(response);
}
const { data, error, isLoading } = useSWR('API-to-get-base64image', fetchImage)
return (
<div><img src = {image}/> </div>
)
}
Я не уверен, что проверка состояния всегда будет работать. Если React попытается смонтировать компонент во второй раз, пока ваш запрос находится в работе (вероятно, это скорее проблема с медленным API, чем с изображением), он выдаст ошибку. второй запрос.
Что ж, в моем реальном и гораздо более сложном коде я бы присвоил значение другой переменной, прежде чем выполнять выборку. И что я на самом деле проверил, так это значение этой переменной. Поскольку это не выборка, она не будет «в полете». Да, я согласен с вами, что если бы это был код, который я разместил выше, возможно, он мог бы запуститься дважды. Однако в этом случае, я думаю, мы все равно можем установить дозорную переменную, чтобы предотвратить ее второй запуск. Возможно, это не самый достойный способ сделать это, но выполнить работу просто и быстро.
Спасибо за ваше решение. На самом деле я нашел очень простой способ сделать это. Просто проверьте, пусто ли изображение в первой строке внутри useEffect, и немедленно вернитесь, если оно уже имеет значение.