Ошибка типа: не удается прочитать свойство «условие» неопределенного

#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, оно все равно не будет выполнено в вашей текущей настройке, так что это не то, что вы хотите прямо сейчас.