Не удается добавить некоторые данные из запроса API в компонент React

Я начал разработку своего новостного проекта с использованием React js. К сожалению, у меня есть проблема. Я использую axios для выборки данных. Я делаю запрос, и у меня есть ошибка в консоли. Я попытался использовать useState вместо переменных сообщений в основном файле, но получил ту же ошибку. Я думаю, что что-то не так либо с переменной posts, потому что я думаю, что useEffect работает медленнее, чем html-код, который будет возвращен или с методом карты.

Ошибка:

TypeError: Cannot read properties of undefined (reading map) at news.jsx

Почтовый файл:

import React from 'react';

function Post(props) {
    return (
        <div className = "post">
            <div className = "post-name">{props.title}</div>
            <div className = "post-content">{props.text}</div>
            <a className = "post-source" href = {props.url}>{props.name}</a>
        </div>
    );
}

export default Post;

Основной файл с запросами:

import React, { useEffect } from "react";
import SyncIcon from "@mui/icons-material/Sync";
import axios from "axios";
import "../css/news.css";
import Post from "./Post";

function News() {
  let posts;

  useEffect(() => {
    const loading = document.querySelector(".loading");
    const postsContainer = document.querySelector(".news-posts");

    async function loadPosts() {
      const date = new Date();

      const day = date.getDate();

      const month = date.getMonth();

      const year = date.getFullYear();

      const fullDate = year + "-0" + month + "-0" + day;

      let response = [];

      try {
        const request = await axios.get(
          `https://newsapi.org/v2/everything?qInTitle=Ukraine&from=${fullDate}&sortBy=publishedAt&apiKey=363858d3a88f49ffad9b467282270c8a`
        );

        const data = request.data.articles;

        for (let i = 0; i < 20; i++) {
          response.push({
            source: {
              name: data[i].source.name,
              url: data[i].url,
            },

            content: {
              title: data[i].title,
              text: data[i].content,
            },
          });
        }
      } catch {
        console.info("error");
      }

      loading.classList.add("none");
      // setPosts(response);
      posts = response;
    }

    loadPosts();
  }, []);

  return (
    <section className = "news-container">
      <div className = "news-posts">
        <div className = "loading">
          <SyncIcon />
        </div>
        {posts.map((post) => (
          <Post
            name = {post.source.name}
            url = {post.source.url}
            text = {post.content.text}
            title = {post.content.title}
          />
        ))}
      </div>
    </section>
  );
}

export default News;

Fetch асинхронный, вам нужно где-то useState.

jonrsharpe 13.02.2023 17:35

Я попробовал сначала useState, но у меня была та же ошибка. Поэтому из-за этого я использовал переменную

Roman 13.02.2023 17:37

Скорее всего, потому что ваше начальное состояние не было массивом, и вы не имели с этим дело.

jonrsharpe 13.02.2023 17:39

Ладно, понял. Можете ли вы добавить ответ на мой вопрос с помощью useState в коде. Потому что я перепробовал все, что мог на самом деле.

Roman 13.02.2023 17:45
Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел &quot;Заголовок&quot; в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
Как React Helmet спасает меня при разделении файлов CSS?
Как React Helmet спасает меня при разделении файлов CSS?
Многие новички могут столкнуться с проблемой, когда одна страница с CSS наследует свойства от другой страницы с другим CSS. У меня было много проблем,...
Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Руководство для начинающих по веб-разработке: HTML, CSS и JavaScript.
Руководство для начинающих по веб-разработке: HTML, CSS и JavaScript.
Добро пожаловать, мои коллеги по интернету, в захватывающий мир веб-разработки! Дорогие мои начинающие, я здесь, чтобы провести вас через основы HTML,...
0
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это один из правильных способов получения данных и их отображения:

import React, { useEffect } from "react";
import SyncIcon from "@mui/icons-material/Sync";
import axios from "axios";
import "../css/news.css";
import Post from "./Post";

function News() {
  const [posts, setPosts] = useState([]) // init state as empty array. We will store posts here
  const [loading, setLoading] = useState(true) //Start with loading = true
 const [error, setError] = useState(false) //Start with error = false 

  useEffect(() => {
    async function loadPosts() {
      const date = new Date();

      const day = date.getDate();

      const month = date.getMonth();

      const year = date.getFullYear();

      const fullDate = year + "-0" + month + "-0" + day;

     

      try {
        const request = await axios.get(
          `https://newsapi.org/v2/everything?qInTitle=Ukraine&from=${fullDate}&sortBy=publishedAt&apiKey=363858d3a88f49ffad9b467282270c8a`
        );

        const data = request.data.articles;
        
        for (let i = 0; i < 20; i++) {
          response.push({
            source: {
              name: data[i].source.name,
              url: data[i].url,
            },

            content: {
              title: data[i].title,
              text: data[i].content,
            },
          });
        }

      setPosts(response); //set state
      setLoading(false) //end loading
    
      } catch {
        console.info("error");
        setError(true)
        setLoading(false)
      }

      

    }

    loadPosts();
  }, []);

  return (
    <section className = "news-container">
      <div className = "news-posts">
        {loading? 
        (<div className = "loading">
          <SyncIcon />
        </div>)
   : null }
        {posts?.length? posts.map((post) => (
          <Post
            name = {post.source.name}
            url = {post.source.url}
            text = {post.content.text}
            title = {post.content.title}
          />
        ))} : <p>No data found</p>
      </div>
    </section>
  );
}

export default News;

По сути, ошибка в том, что ваши сообщения не определены. И попытка отобразить это сломает ваше приложение. Вам нужно проверить, существует ли он, и если это массив, а затем сопоставить его. Кроме того, способ React для рендеринга компонентов загрузки или ошибок заключается в использовании условного рендеринга в функции возврата (проверьте загрузку).

Кроме того, вы должны использовать состояние, иначе React не узнает, нужно ли ему что-либо перерисовывать.

Вам не нужно использовать селекторы запросов

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

Вы должны использовать useState для обновления контента в вашем компоненте.

Операторы if, которые я реализовал, предназначены для обеспечения того, чтобы полученный контент не был пустым. Вы можете удалить их после того, как отладите это, или выполните другие действия в этих условиях.

import React, { useEffect, useState } from "react";
import SyncIcon from "@mui/icons-material/Sync";
import axios from "axios";
import "../css/news.css";
import Post from "./Post";

function News() {
  const [posts, setPosts] = useState([]);

  useEffect(async () => {
    const loading = document.querySelector(".loading");
    const postsContainer = document.querySelector(".news-posts");

    const date = new Date();
    const day = date.getDate();
    const month = date.getMonth();
    const year = date.getFullYear();
    const fullDate = year + "-0" + month + "-0" + day;
    let response = [];

    try {
      const request = await axios.get(
        `https://newsapi.org/v2/everything?qInTitle=Ukraine&from=${fullDate}&sortBy=publishedAt&apiKey=363858d3a88f49ffad9b467282270c8a`
      );

      if (request.data) {
        const data = request.data.articles;

        if (data) {
          for (let i = 0; i < 20; i++) {
            response.push({
              source: {
                name: data[i].source.name,
                url: data[i].url,
              },

              content: {
                title: data[i].title,
                text: data[i].content,
              },
            });
          }

          setPosts(response);
        } else {
          console.info("No articles in response data");
        }
      } else {
        console.info("Empty response");
      }
    } catch (err) {
      console.info(`Error: ${err}`);
    }

    loading.classList.add("none");
  });

  return (
    <section className = "news-container">
      <div className = "news-posts">
        <div className = "loading">
          <SyncIcon />
        </div>{" "}
        {posts.map((post) => (
          <Post
            name = {post.source.name}
            url = {post.source.url}
            text = {post.content.text}
            title = {post.content.title}
          />
        ))}
      </div>{" "}
    </section>
  );
}

export default News;

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