我尝试在谷歌和chatGPT上搜索,但我没有运气,这让我失去了头发。我不明白为什么反应状态会这样。我有一个应用程序,它从不同的 API 中获取新闻,然后将它们合并到一个大数组中,然后以列表的形式显示它们,您可以根据需要对它们应用过滤器,并保留偏好以供以后使用。
以下是我的应用程序的结构:
App -> 首页(Router-dom) -> 新闻组件 -> 列表组件+过滤组件
家里没什么东西。只是一些 html 和新闻组件。新闻组件是我维护新闻列表和过滤器状态的地方。
新闻部分:
import React, {useEffect, useState} from 'react'
import List from '../../components/List';
import SearchBar from '../../components/SearchBar';
import { FilterOptions, filter, getNews } from '../../utils/data';
import Filter from '../Filter';
import Cookies from 'js-cookie';
export interface NewsItem {
id : string
apiSource : "news_api" | "guardian_news" | "nyt_api";
author : string;
description : string;
publishedAt : string;
source : string;
image: string;
title : string;
url : string;
}
export const sourcingFrom = {
news_api: "News API",
guardian_news: "The Guardian Open Platform",
nyt_api: "New York Times Article Search"
}
export type ApiSource = keyof typeof sourcingFrom;
function News() {
const [newsItems, setNewsItems] = useState([])
const [filters, setFilters] = useState<FilterOptions>({})
const updateFilters = (newFilters : FilterOptions) => {
const updateFiltersQuery :FilterOptions = {
...filters,
...newFilters,
}
setFilters(prev => updateFiltersQuery)
}
const updateNews = (filterData: FilterOptions = {}) => {
const filterRequest = Object.keys(filterData).length <= 0 ? filterData : filters
console.log(filterRequest)
filter(filterRequest).then(newNewsItems => {
setTimeout(() => {
setNewsItems(prev => newNewsItems);
}, 500);
});
};
const updateQuery = (e : string) => {
const updateFiltersQuery :FilterOptions = {
...filters,
query : e,
}
setFilters(prev => updateFiltersQuery)
}
const resetFilters = () => {
}
const resetPreferences = () => {
Cookies.remove('filterPreferences');
}
const savePreferences = () => {
Cookies.set('filterPreferences', JSON.stringify(filters), { expires: 30 });
}
useEffect(() => {
const savedPreferences = Cookies.get('filterPreferences');
if(savedPreferences){
const filterData : FilterOptions = JSON.parse(savedPreferences)
updateFilters(filterData);
updateNews(filterData);
}
else {
getNews().then(res => setNewsItems(res));
}
}, []);
return (
<section className='newsItems'>
<SearchBar updateQuery={updateQuery} updateNews={updateNews} resetFilters={resetFilters}/>
<Filter filter={updateFilters} savePreferences={savePreferences} resetPreferences={resetPreferences}/>
<List newsItems={newsItems}/>
</section>
)
}
如您所见,我必须在
setTimeout
中应用 updateNews
,这样当我收到数据时它会更新数据,这不好。使用 Cookie 的情况更糟,因为在通过 Cookie 设置过滤器后,它不会发送请求。除非我在文件中进行一些更改并保存它然后它开始工作。使用 setTimeout
也不起作用。我还删除了 setTimeout
并检查我是否仍然在列表中收到新的过滤新闻项目。
我尝试寻找解释,但无法弄清楚,所以任何帮助都会非常有帮助。我觉得我违反了一些 React 规则,如果你们能帮忙,那就太好了。
如有任何帮助,我们将不胜感激
过滤和 getNews API 调用:
export const getNews = async (newAPIParameters :DefaultAPIParas ={}, guardianNewsParameters :DefaultAPIParas ={}, nYTAPIParameters :DefaultAPIParas ={}, dontCallAPIs : DontCallAPIs = {}) => {
const newsData: any = [];
if(!dontCallAPIs?.news_api) {
getNewsApiData(newAPIParameters).then((res: any) => {
//console.log(res)
for (let item of res) {
const modifiedRes = {
id: generateRandomString(),
apiSource: "news_api",
author: item.author,
title: item.title,
url: item.url,
image: item.urlToImage,
publishedAt: item.publishedAt,
source: item.source?.name ?? "",
description: item.content ?? item.description,
};
newsData.push(modifiedRes);
}
});
}
if(!dontCallAPIs?.guardian_api) {
getGuardianNewsAPIData(guardianNewsParameters).then((res: any) => {
//console.log(res)
for (let item of res) {
const modifiedRes = {
id: generateRandomString(),
apiSource: "guardian_news",
author: item.tags[0]?.webTitle ?? 'Not Determined',
title: item.webTitle,
url: item.webUrl,
image: item.fields.thumbnail,
publishedAt: item.webPublicationDate,
source: "The Guardian News",
description: item.fields.trailText,
};
newsData.push(modifiedRes);
}
});
}
if(!dontCallAPIs?.nyt_api) {
getNYTAPIData(nYTAPIParameters).then((res: any) => {
//console.log(res)
for (let item of res) {
const modifiedRes = {
id: generateRandomString(),
apiSource: "nyt_api",
author: item.byline.original?.replace('By ', '') ?? 'Not Determined',
title: item.headline.main,
url: item.web_url,
image: "https://www.nytimes.com/"+item.multimedia[0]?.url ?? null,
publishedAt: item.pub_date,
source: "New York Times",
description: item.abstract,
};
newsData.push(modifiedRes);
}
});
}
return await newsData;
};
export const filter = async (filterOptions : FilterOptions) => {
const {query = null, category = '', from = null,to = null,sources = {}} = filterOptions
const dontCallAPIs : DontCallAPIs = {}
if (Object.keys(sources).length !== 0) {
dontCallAPIs['news_api'] = sources.news_api && sources?.news_api?.length <= 0;
dontCallAPIs['guardian_api'] = !sources.guardian_api;
dontCallAPIs['nyt_api'] = !sources.nyt_api;
}
const newAPIParameters ={
query : query ?? '',
from : from ?? '',
to : to ?? '',
category : category ?? '',
sources : sources.news_api?.join(', ')
}
const guardianNewsParameters = {
query : query ?? '',
from : from ?? '',
to : to ?? '',
category : category ?? '',
}
const nYTAPIParameters = {
query : query ?? '',
from : from ?? '',
to : to ?? '',
category : category ?? '',
}
return getNews(newAPIParameters, guardianNewsParameters, nYTAPIParameters, dontCallAPIs)
}
您的过滤器方法返回 Promise of Promise,这是不需要的,因为它不执行任何异步操作。从中删除异步。
export const filter = (filterOptions : FilterOptions) // async removed
也不需要在
return await newsData;
中使用await,因为newsData不是一个承诺。您可以将其保留为return newsData;