TypeError: Невозможно прочитать свойство 'url' из неопределенного для JSONPlaceholder - PullRequest
2 голосов
/ 12 апреля 2020

Я пытаюсь загрузить картинки из jsonPlaceholder. Когда я console.log из массива изображений, он работает успешно. В тот момент, когда я пытаюсь вызвать URL из элемента, он выдает ошибку TypeError. Я пытался сделать это асинхронным способом, даже это не работает. Есть ли обходной путь для этого? В чем, возможно, проблема?

import React, {Component} from 'react';
import axios from 'axios';

class Home extends Component{



    state = {
                posts : [],
                images : []

            };

    componentDidMount =  async () => {
        const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
            this.setState({posts: res.data.slice(0,10)})

        const res2 = await axios.get('https://jsonplaceholder.typicode.com/photos');
            this.setState({images: res2.data.slice(0,10)})

        }


    render = () => {    


        const {posts} = this.state.posts;
        const {images} = this.state.images;

        const PostList = this.state.posts.length ? (


            this.state.posts.map((post,index) => {
                return(
                    <div className = "post card" key = {post.id}>
                            <div className = "card-content">
                                <div className = "card-title">
                                    {post.title}
                                </div>
                                <div className>
                                    {(this.state.images[index].url)} //console.log(this.state.images[index] works, but .URL doesn't 
                                </div>
                                <div>
                                    <p>{post.body}</p>
                                </div>
                            </div>
                    </div>

                )
            })) : (<div className = "center">No Posts!</div> ) 

        return(
                <div className = "container">
                    <div className = "center">
                        {PostList}
                    </div>
                </div>)
    }

}

export default Home;

Ответы [ 3 ]

3 голосов
/ 12 апреля 2020

Проблема была в нескольких setState. Как только вы установите setState, он обновляет и отображает asynchronously. Так что не дождался next setState. Лучше установить обе данные за один вызов.

componentDidMount =  async () => {
        const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
            this.setState({posts: res.data.slice(0,10)})

        const res2 = await axios.get('https://jsonplaceholder.typicode.com/photos');
            this.setState({images: res2.data.slice(0,10)})

        }

Вы можете очистить код следующим образом:

Рабочий пост: https://codesandbox.io/s/articlepodcast-wd2rv?file= / home. js: 0-1214

import React, { Component } from "react";
import axios from "axios";

class Home extends Component {
  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      images: []
    };
  }

  componentDidMount = async () => {
    const res = await axios.get("https://jsonplaceholder.typicode.com/posts");
    const res2 = await axios.get("https://jsonplaceholder.typicode.com/photos");
    this.setState({
      posts: res.data.slice(0, 10),
      images: res2.data.slice(0, 10)
    });
  };

  render = () => {
    const { posts, images } = this.state;
    const PostList = posts.length ? (
      posts.map((post, index) => {
        return (
          <div className="post card" key={post.id}>
            <div className="card-content">
              <div className="card-title">{post.title}</div>
              <div className>{images[index].url} </div>
              <div>
                <p>{post.body}</p>
              </div>
            </div>
          </div>
        );
      })
    ) : (
      <div className="center">No Posts!</div>
    );

    return (
      <div className="container">
        <div className="center">{PostList}</div>
      </div>
    );
  };
}

export default Home;
0 голосов
/ 12 апреля 2020

Проблема

Ошибка возникает из-за способа установки состояния в функции componentDidMount. Чтобы понять, почему это происходит, я объясню, что код пытается сделать: во-первых, Ax ios отправит запрос на получение для получения сообщений, потому что это асинхронное действие c, которое выполняется awaited javascript будет работать над чем-то другим во время получения данных. Так что он продолжится и запустит функцию render в первый раз. Функция рендеринга вернет No Posts!, поскольку this.state.posts.length ? равно false.

Затем, когда мы закончим sh получение сообщений, componentDidMount продолжится, в этом случае будет обновлено состояние this.setState({posts: res.data.slice(0,10)}), каждый раз, когда вызывается setState, он будет реагировать на повторное выполнение функции render для этого компонента, чтобы убедиться, что страница отражает то, что находится в нашем состоянии. Затем мы переходим к следующей строке, где ожидаем получения фотографий, в то время как мы ожидаем, что функция render запустится во второй раз, потому что (как только что было сказано) мы изменили состояние компонента. На данный момент у нас по-прежнему нет фотографий, так как мы ожидаем их получения, но у нас есть сообщения, поэтому проверка на наличие сообщений this.state.posts.length ? будет true. Затем, когда мы доберемся до images[index], оно будет неопределенным, потому что мы еще не завершили получение фотографий и не установили их в состояние. (Надеюсь, это поможет вам понять проблему).

Решение

Обновите состояние после того, как мы получим все данные, чтобы второй раз использовать функцию render запускает, у нас есть изображения:

const res = await axios.get("https://jsonplaceholder.typicode.com/posts");
const res2 = await axios.get("https://jsonplaceholder.typicode.com/photos");
this.setState({
  posts: res.data.slice(0, 10),
  images: res2.data.slice(0, 10)
});

Я бы также предложил добавить проверку безопасности к this.state.images, как вы делали с постами, чтобы убедиться, что у вас действительно есть данные, прежде чем пытаться их использовать. Это хорошая практика для всех данных, которые поступают из сетевых вызовов, потому что при попытке получить данные из службы может произойти много неожиданных вещей.

Наконец, я также предлагаю вам попробовать выполнить код с помощью chrome отладчик. Это поможет вам понять, что делает код, чтобы лучше понять, почему может происходить такая проблема. Вот хорошее руководство о том, как это сделать. https://developers.google.com/web/tools/chrome-devtools/javascript

0 голосов
/ 12 апреля 2020

Из-за вашего первого setState он рендерится до второго asyn c -aaait.

const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
const res2 = await axios.get('https://jsonplaceholder.typicode.com/photos');

this.setState({images: res2.data.slice(0,10), posts: res.data.slice(0,10)})

попробуйте вот так.

лучше иметь что-то подобное;

this.setState({
   posts: res.data.slice(0,10).map((post, index) => ({
     ...post,
    image: res2.data.slice(0,10)[index]

   }))

})
...