#javascript #reactjs #api #axios #fetch
#javascript #reactjs #API #axios #выборка
Вопрос:
Я работаю над личным проектом веб-приложения в React. Я новичок в этой технологии, но очень хочу ее изучить. Я столкнулся с проблемой. Я использую axios для извлечения данных из ответа API Google Youtube, и это работает, но я не могу проанализировать полученные вложенные данные. Что я имею в виду под этим: внутри элементов есть несколько фрагментов
{
"items": [
{
"snippet": {
"title": "Dolby Atmos - usłysz więcej!",
"description": "W dzisiejszym odcinku opowiem wam o tym czym jest nagłośnienie i system dolby atmos. System i nagłośnienie Dolby atmos znajdziemy obecnie w najlepszych kinach. System wspierają takie filmy jak "Zjawa" czy "Kapitan Ameryka wojna bohaterów". Jakość dźwięk docenią kinomani i prawdziwi audiofile. Istnieje również stworzenia systemu składającego się z głośników dolby atmos kina domowego, ale jest poważna inwestycja.nJeżeli jesteś z Łodzi i chcesz poczuć Dolby Atmos na własnej skórze kliknij tutaj:nhttp://www.helios.pl/47,Lodz/StronaGlowna/nnJeżeli dzisiejszym odcinek Ci się spodobał zostaw like'a albo subskrybcję :DnFanPage:nhttp://facebook.com/RuchOpornikownGoogle :nhttps://plus.google.com/u/0/ RuchOpor...nTwitter:nhttps://twitter.com/RuchOpornikow",
"thumbnails": {
"standard": {
"url": "https://i.ytimg.com/vi/QWTk3vnztRw/sddefault.jpg",
"width": 640,
"height": 480
},
"maxres": {
"url": "https://i.ytimg.com/vi/QWTk3vnztRw/maxresdefault.jpg",
"width": 1280,
"height": 720
}
},
"resourceId": {
"videoId": "QWTk3vnztRw"
}
}
},
Я хочу получить случайный фрагмент из элементов и использовать его атрибут заголовка, описание и эскизы.
На данный момент я могу получить доступ к описанию и названию, но получить доступ к movie.description.thumbnails.standard.url или movie.resourceId.VideoID выдает ошибку.
TypeError: Cannot read property 'standard' of undefined
31 | backgroundPosition: "center center",
32 | }}
33 | >
> 34 | <img src ={`${movie.thumbnails.standard.url}`}/>
35 | <div className="banner_contents">
36 | {/* edge cases */}
37 | <h1 className="banner_title">
Вот мой полный код :
function Banner() {
const [movie, setMovie] = useState([]);
useEffect(() => {
async function fetchData() {
const request = await axios.get("./data.json");
setMovie(
request.data.items[
Math.floor(Math.random() * (request.data.items.length-1))
].snippet
);
return request;
}
fetchData();
}, []);
return (
<header
className="banner"
style={{
backgroundSize: "cover",
// backgroundImage: `url("${movie.snippet.thumbnails.maxres.url}")`,
backgroundPosition: "center center",
}}
>
<img src ={`${movie.thumbnails.standard.url}`}/>
<div className="banner_contents">
{/* edge cases */}
<h1 className="banner_title">
{movie.title}
</h1>
<div className="banner_buttons">
<button className="banner_button">Play</button>
<button className="banner_button">Original</button>
</div>
<h1 className="banner_description">{movie.description}</h1>
</div>
<div className="banner--fadeBottom" />
</header>
);
}
export default Banner;
Знаете ли вы, что может быть ошибкой и как ее исправить? Консоль.log и JSON.stringify показывают, что эти атрибуты есть.
Комментарии:
1. Ваше
movie
состояние — это массив, но вы ссылаетесь на него, как на объект в вашей логике рендеринга.movie.snippet
иmovie.thumbnails
, очевидно, будет неопределенным.2. Как получить доступ к этим элементам?
3. Ответ ниже, но при первоначальном рендеринге
movie
это массив и не будет иметь свойств, которые я вызвал. Преобразование его в пустой объект приблизит вас, но задержит «неопределенное» значение при дальнейшей ссылке на ваш объект состояния, что приведет к добавлению некоторых нулевых проверок.
Ответ №1:
Проблема (ы)
Ваше начальное movie
состояние — это массив, но вы ссылаетесь на него, как на объект в вашей логике рендеринга. movie.snippet
и movie.thumbnails
, очевидно, будет неопределенным.
const [movie, setMovie] = useState([]);
и
movie.thumbnails.standard.url
Решение
-
Приведите тип начального состояния в соответствие с тем, до чего он обновляется из запроса на выборку, и как к нему обращаются в логике рендеринга, т.Е. Объект
const [movie, setMovie] = useState({});
-
Используйте надлежащие проверки null и предоставьте резервные значения.
Проверки Null
movie.thumbnails amp;amp; movie.thumbnails.standard amp;amp; movie.thumbnails.standard.url || ""
или с использованием необязательной цепочки и объединения нулей
movie?.thumbnails?.standard?.url ?? ""
Комментарии:
1. Итак, что я сделал неправильно, пытался получить доступ к элементу массива, как если бы это был объект js, но элемента просто не было из-за природы структуры данных. И решение состояло в том, чтобы получить доступ к типу изменения с [] на { } object , это правильно?
2. @szymonindy Да, это была половина проблемы. Объекты представляют собой ассоциированные массивы пар ключ-значение, вы можете думать о массивах как о специальных объектах, где ключами являются индексы массива. Массив не будет иметь индекса с именем «thumbnails»,
movie["thumbnails"] // undefined
т. Е. При более глубоком доступе к неопределенному объекту, когда вы увидите ошибку, которая у вас была.
Ответ №2:
вы получаете ошибку, потому что перед получением каких-либо данных ваш объект movie пуст. вы должны проверить, прежде чем обращаться к вложенным свойствам. вот так
<img src ={movie.thumbnails ? `${movie.thumbnails.standard.url}` : ""}/>
Ответ №3:
movie?.thumbnails?.standard?.url
должен это сделать. Похоже movie.thumbnails
, это undefined
Ответ №4:
предполагая movie
, что содержит правильные данные, синтаксис должен работать. Вот тест: https://jsfiddle.net/yf470pma/1 /
Я бы добавил точку останова и проверил, что там на самом деле.
Ответ №5:
initial movie
— это пустой массив, и для извлечения из API. refactor потребуется некоторое время для приведения к приведенному ниже
const [movie, setMovie] = useState();
и проверьте movie, если оно не равно null перед рендерингом
return movie?(
<header
className="banner"
style={{
backgroundSize: "cover",
// backgroundImage: `url("${movie.snippet.thumbnails.maxres.url}")`,
backgroundPosition: "center center",
}}
>
<img src ={`${movie.thumbnails.standard.url}`}/>
<div className="banner_contents">
{/* edge cases */}
<h1 className="banner_title">
{movie.title}
</h1>
<div className="banner_buttons">
<button className="banner_button">Play</button>
<button className="banner_button">Original</button>
</div>
<h1 className="banner_description">{movie.description}</h1>
</div>
<div className="banner--fadeBottom" />
</header>
):null;