奇怪的 React 状态行为?执行保存文件或 setTimeout 可以解决问题吗?

问题描述 投票:0回答:1

我尝试在谷歌和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)
    
}


reactjs typescript react-hooks state react-typescript
1个回答
0
投票

您的过滤器方法返回 Promise of Promise,这是不需要的,因为它不执行任何异步操作。从中删除异步。

export const filter = (filterOptions : FilterOptions) // async removed

也不需要在

return await newsData;
中使用await,因为newsData不是一个承诺。您可以将其保留为
return newsData;

© www.soinside.com 2019 - 2024. All rights reserved.