Я изучаю React и сейчас работаю над простым приложением о погоде в качестве способа попрактиковаться. Он работает нормально, но я уже давно застрял в проблеме.
Приложение имеет 2 страницы (с использованием реакции-маршрутизатора-dom), домашнюю страницу с формой ввода для поиска города (с использованием api.mapbox.com). При выборе города в списке результатов появляется предварительный просмотр погоды в городе (api.openweathermap.org), затем пользователь может нажать кнопку +, чтобы сохранить этот город (используя локальное хранилище). Сохраненные города отображаются в виде карточек на главной странице. Удалить город из сохраненных городов можно с помощью кнопки внизу страницы погоды. Он просто удаляет город из массива, хранящегося в локальном хранилище, а затем перенаправляет на домашнюю страницу.
Проблема в том, что после перенаправления я все еще вижу «удаленную» карту города. Мне приходится обновить страницу, чтобы увидеть ее удаленной. Я думаю, мне нужно использовать перехватчик useEffect для повторной визуализации списка городов после удаления города, но я не могу заставить его работать. Я что-то упускаю, но не могу понять что. Ниже приведен мой компонент CityList.jsx, который отображает сохраненные города на домашней странице:
import { CityListCard } from "./CityListCard";
let savedCities
const getCities = async () => {
if (localStorage.getItem('savedCities')) {
savedCities = JSON.parse(localStorage.getItem('savedCities'))
const OWMAppId = 'xxxxxxxxxxxxxxxxxxxxx'
const units = 'metric'
const langapi = 'en'
savedCities.map(async (city, index) => {
const response = await fetch(`https://api.openweathermap.org/data/3.0/onecall?lat=${city.coords.lat}&lon=${city.coords.lng}&exclude = {part}&appid=${OWMAppId}&units=${units}&lang=${langapi}`, {
headers: {
'Accept': 'application/json; charset=UTF-8'
}
})
const data = await response.json()
savedCities[index].weather = data
})
}
}
await getCities()
export function CityList() {
return <div className = "flex flex-col gap-4">
{savedCities &&
savedCities.map(city => (
<CityListCard key = {city.id} city = {city} />
))
}
</div>
}
Я думаю, мне нужно добавить useEffect с зависимостью от saveCities, но поскольку хук не может находиться внутри функции, я не знаю, как заставить его работать.
Любая помощь приветствуется
В вашем коде есть несколько ошибок (ну, не совсем неправильно, но это не «реактивный» способ сделать это).
Чтобы исправить ваш компонент, вам нужно узнать, как React ожидает написания ваших компонентов, в основном понимать использование хуков, двумя основными из которых являются useState
и useEffect
.
Переменные обновления, которые были объявлены с помощью useState
, сообщат реакции на повторную отрисовку каждый раз, когда они обнаруживают изменение в этой переменной.
useEffect
в основном используется для побочных эффектов, то есть любых операций или поведения, которые происходят в компоненте после рендеринга и не влияют напрямую на текущий цикл рендеринга компонента. Эти побочные эффекты могут включать в себя такие задачи, как получение данных, подписки, ручное изменение DOM или другие взаимодействия с внешним миром.
Подробнее о них можно прочитать на сайте React — https://react.dev/reference/react/hooks
Теперь исправляем ваш компонент, он должен выглядеть примерно так, может не совсем работать, но вы получите четкое представление.
import { CityListCard } from "./CityListCard";
import { useState, useEffect } from "react";
const getCities = async () => {
if (localStorage.getItem('savedCities')) {
const savedCities = JSON.parse(localStorage.getItem('savedCities') || '[]')
const OWMAppId = 'xxxxxxxxxxxxxxxxxxxxx'
const units = 'metric'
const langapi = 'en'
savedCities.map(async (city, index) => {
const response = await fetch(`https://api.openweathermap.org/data/3.0/onecall?lat=${city.coords.lat}&lon=${city.coords.lng}&exclude = {part}&appid=${OWMAppId}&units=${units}&lang=${langapi}`, {
headers: {
'Accept': 'application/json; charset=UTF-8'
}
})
const data = await response.json()
savedCities[index].weather = data
})
}
}
export function CityList() {
const [cities, setCities] = useState([]);
useEffect(() => {
// make the API call here and set the state
getCities().then((data) => {
setCities(data);
});
}, []); // dependencies variables are added here to re-run the effect when they change, if
return (
<div className = "flex flex-col gap-4">
{cities &&
cities.map((city) => <CityListCard key = {city.id} city = {city} />)}
</div>
);
}
спасибо, это было дело. Теперь это действительно работает так, как и ожидалось.