#javascript #reactjs #npm
#javascript #reactjs #нпм
Вопрос:
Итак, я пытаюсь выучить React и застрял, пытаясь создать приложение для погоды.
Это моя составляющая и мой app.js файлы.
import React from 'react'
const WeatherCard = (props) => {
return (
<div className="card d-flex align-content-center align-items-center flex-wrap">
<div className= 'd-flex flex-column'>
<img className = 'd-flex' alt='Icona' src={props.icon}></img>
<p className ='d-flex'> {props.location} </p>
</div>
<div className= 'd-flex justify-content-between'>
<span className = "">{props.condition}</span><span className = ''>{props.temperature}°C</span>
</div>
</div>
)
}
export default WeatherCard;
import './App.css';
import React, {useEffect, useState} from 'react';
import WeatherCard from './components/WeatherCard';
const App = () => {
const APP_KEY = "My_key(yes, I put my key here)";
const [weatherDatas, setWeather] = useState({});
const [search, setSearch] = useState("");
const [query, setQuery] = useState('Iglesias');
useEffect(() => {
getWeather();
},[query]);
const getWeather = async () => {
const response = await fetch(`http://api.weatherapi.com/v1/current.json?key=${APP_KEY}amp;q=${query}`);
const data = await response.json()
setWeather(data);
}
const updateSearch = e => {
setSearch(e.target.value);
}
const getSearch = e => {
e.preventDefault();
setQuery(search);
}
return(
<div className="App">
<form onSubmit={getSearch} className="SearchForm d-flex justify-content-center">
<input type='text' value = {search} onChange = {updateSearch} />
<button type='submit'>Search</button>
</form>
<div className='d-flex justify-content-center'>
<WeatherCard
icon = {weatherDatas.current.condition.icon}
location = {weatherDatas.location.name}
condition = {weatherDatas.current.condition.text}
temperature = {weatherDatas.current.temp_c}
/>
</div>
</div>
)
}
export default App;
Проблема в том, что когда я запускаю «TypeError: Не удается прочитать свойство ‘condition’ неопределенного», появляется ошибка.
Но если я удалю эту часть кода во время его выполнения:
icon = {weatherDatas.current.condition.icon}
location = {weatherDatas.location.name}
condition = {weatherDatas.current.condition.text}
temperature = {weatherDatas.current.temp_c}
обновите и вставьте его снова, он работает плавно, я в таком замешательстве, похоже, он пытается получить реквизиты, прежде чем получать данные из API? может кто-нибудь помочь мне понять, что происходит?
Комментарии:
1. вы должны проверить, не является ли текст null или undefined, condition = {weatherDatas.current.condition.text}
2. Вы пытаетесь получить доступ к глубоко вложенным свойствам
weatherDatas
до того, как они будут установлены. Начальное значениеweatherDatas
является пустым объектом{}
, и при первоначальном рендеринге ни одно из этих значений, а также эти более глубокие свойства не имеют значения, отсюда и ошибка. Вам либо нужно использовать условный рендеринг для рендерингаWeatherCard
только после того, как эти данные были возвращены / разрешены из API, либо обновитьweatherDatas
начальное значение состояния, чтобы иметь значения по умолчанию, чтобы избежать возникновения ошибки. Рендеринг компонента не ожидает вызова API.3. вам нужно правильно инициализировать состояние, установить значения по умолчанию или использовать условный рендеринг, когда у вас есть данные, а затем показывать только дочерний компонент.
Ответ №1:
Это классическая ошибка, поскольку вы запускаете асинхронную функцию, в некоторые моменты, когда ваши компоненты монтируются, полученный реквизит — это просто «{}», и именно поэтому вы получаете сообщение об ошибке. Я изменил ваш фрагмент, и я думаю, что теперь это сработает.
import './App.css';
import React, {useEffect, useState} from 'react';
import WeatherCard from './components/WeatherCard';
const App = () => {
const APP_KEY = "My_key(yes, I put my key here)";
const [weatherDatas, setWeather] = useState(null); //CHANGE HERE
const [search, setSearch] = useState("");
const [query, setQuery] = useState('Iglesias');
useEffect(() => {
getWeather();
},[query]);
const getWeather = async () => {
const response = await fetch(`http://api.weatherapi.com/v1/current.json?key=${APP_KEY}amp;q=${query}`);
const data = await response.json()
setWeather(data);
}
const updateSearch = e => {
setSearch(e.target.value);
}
const getSearch = e => {
e.preventDefault();
setQuery(search);
}
return(
<div className="App">
<form onSubmit={getSearch} className="SearchForm d-flex justify-content-center">
<input type='text' value = {search} onChange = {updateSearch} />
<button type='submit'>Search</button>
</form>
<div className='d-flex justify-content-center'>
{weatherDatas amp;amp; ( //CHANGE HERE
<WeatherCard
icon = {weatherDatas.current.condition.icon}
location = {weatherDatas.location.name}
condition = {weatherDatas.current.condition.text}
temperature = {weatherDatas.current.temp_c}
/>)}
</div>
</div>
)
}
export default App;
Теперь ваш код просто попытается отобразить компонент, когда он будет загружен
Комментарии:
1. Большое вам спасибо! Это было очень полезно
2. @Pepe, вы действительно хотите, чтобы этот раздел был удален при первом запуске или если данные возвращают неверную информацию? Это предотвращает отображение этой карты погоды, но она появится позже, что может нарушить ваш макет, и если
getWeather
выполняется позже и возвращает пустое или нулевое значение, эта карта погоды снова исчезает. Если вы регулярно используете этот метод и ваши данные противоречивы, карта может мигать и гаснуть, что делает ее ненадежной или раздражающей. Проверка на наличие нулей в других местах может обеспечить видимость карты, даже если данные неверны.3. Также хорошим подходом является использование некоторого <LoadingComponent/> , и вы используете его, когда у вас нет готовых данных для доступа
Ответ №2:
Это распространенная проблема, вызванная многопоточностью. Вашей переменной не присвоено значение, поэтому оно равно null, и вы не можете извлечь что-либо из переменной, поэтому она выдает ошибку «Невозможно прочитать свойство ‘xxxx’ неопределенного».
Я могу понять, почему вы считаете weatherDatas
, что переменная должна быть заполнена из-за ключевого слова «await», но оно встроено в метод «async». В этом случае «асинхронность» превосходит «ожидание».
const getWeather = async () => {
const response = await fetch(`http://api.weatherapi.com/v1/current.json?key=${APP_KEY}amp;q=${query}`);
const data = await response.json()
setWeather(data);
}
Вам нужно будет выполнить проверку null при использовании weatherDatas
переменной. Вам следует изучить необязательную цепочку, что означает, что вы будете вызывать свой объект с вопросительными знаками перед .
тем, как он проверит наличие данных, прежде чем пытаться использовать их.
Есть несколько способов сделать это, и они могут работать хорошо или плохо, в зависимости от того, чего именно вы ожидаете. Вот несколько примеров, но они не обязательно являются тем, что вы хотите:
icon = {weatherDatas?.current?.condition?.icon}
location = {weatherDatas?.location.name}
condition = {weatherDatas.current.condition?.text}
Пример для вашей icon
переменной, вероятно, нужен вам. Это icon
предотвращает назначение чего-либо сверх null
, если только весь путь к объекту не содержит данных, поэтому он не будет выдавать ошибку нулевой ссылки при попытке доступа weatherDatas
, current
, или condition
. Однако icon
все равно может быть null, если weatherDatas.current.condition.icon
равно null . Вероятно, это та ситуация, которую вы хотите, поскольку она проверяет все объекты на null перед доступом к свойствам объекта. Это может быть необязательно для каждого использования объекта, но это хорошо для одноразового использования или для вашего использования. Однако обычно лучше выполнять обычную проверку на нуль.
Для location
переменной она не будет выдавать ошибку ссылки null при попытке доступа weatherDatas
, но она может быть использована для доступа weatherDatas.location
, если она равна null.
В condition
примере с переменной вы все равно можете получить ошибку ссылки null для weatherDatas
and current
, но нет condition
. Поскольку ваше weatherDatas
значение равно null, оно все равно не будет выполнено в вашей текущей настройке, так что это не то, что вы хотите прямо сейчас.