英文:
Can't add some data from API request to React component
问题
我开始了使用 React js 开发的新闻项目。不幸的是,我遇到了一个问题。我正在使用 axios 进行数据获取。我发起了一个请求,但在控制台中出现了错误。我尝试使用 useState 替代主文件中的变量 posts,但仍然收到了相同的错误。我认为,要么是 posts 变量出了问题,因为我认为 useEffect 的工作速度比将要返回的 HTML 代码要慢,要么是 map 方法出了问题。
错误:
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.log("error");
}
loading.classList.add("none");
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;
请注意,我已经将代码中的HTML转义字符(<
和>
)替换为正常的 JSX 标记(<
和>
),以便更容易阅读。
英文:
I have started my news project developing using React js. Unfortunately I have an issue. I am using axios for data fetching. I am making a request and I have an error in the console. I tried to use useState instead of variable posts in main file, but I had received the same error. I think, that something wrong either with posts variable, because I think, that useEffect is working slower, than html code, that will be returned or with map method.
Error:
TypeError: Cannot read properties of undefined (reading map) at news.jsx
Post file:
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;
Main file with requests:
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.log("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;
答案1
得分: 0
这是获取数据并显示它们的正确方式之一:
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([]); // 初始化状态为空数组,我们将在这里存储帖子
const [loading, setLoading] = useState(true); // 从 loading = true 开始
const [error, setError] = useState(false); // 从 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;
let response = [];
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); // 设置状态
setLoading(false); // 结束加载
} catch {
console.log("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方式(检查loading)。
此外,你必须使用状态,否则React不知道是否需要重新渲染任何内容。不需要使用查询选择器。
英文:
This is one of the proper ways to fetch data and display them:
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.log("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;
Basically, the error is that your posts are undefined. And trying to map it breaks your app. You need to check if it exists and if it is an array, then map trough it. Also, the React way to render loading or error components is to use conditional rendering in the return function (check loading)
Also, you must use state otherwise React wont know if it needs to rerender anything.
You do not need to use query selectors
答案2
得分: 0
您应该使用`useState`来更新组件中的内容。
我实现的*if语句*是为了确保接收到的内容不为空。在调试完之后,您可以将这些语句删除或在这些条件下实现不同的操作。
英文:
You should use useState
for updating content in your component.
The if statements I've implemented are in order to ensure the content received is not empty. You can remove those after you've debugged this or implement different actions under those conditions.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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.log("No articles in response data");
}
} else {
console.log("Empty response");
}
} catch (err) {
console.log(`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;
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论