Проблема с компонентом без повторного рендеринга в приложении React

Я изучаю 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, но поскольку хук не может находиться внутри функции, я не знаю, как заставить его работать.

Любая помощь приветствуется

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашем коде есть несколько ошибок (ну, не совсем неправильно, но это не «реактивный» способ сделать это).

  • Вы объявляете переменные вне вашего компонента React. Это делает его нереактивным, что означает, что React не будет знать, когда он обновится, поэтому не будет повторно отображать компонент.
  • Вы также выполняете вызов API вне компонента. Опять же, компонент React не имеет ни малейшего представления о том, что этот вызов выполняется. Что, если вы хотите показать загрузчик во время выполнения этого вызова? Как компонент узнает о своем статусе?
  • Кроме того, вы обновляете локально созданную переменную вне функции. область внутри вызова асинхронной функции, в идеале функции не должны обновлять переменную за пределами ее области действия, они должны возвращать некоторую форму данных, которые, в свою очередь, обновляют переменную.

Чтобы исправить ваш компонент, вам нужно узнать, как 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>
  );
}

спасибо, это было дело. Теперь это действительно работает так, как и ожидалось.

feub 21.08.2024 14:32

Другие вопросы по теме