简体   繁体   English

state 更新,但未显示在页面上

[英]The state updates, but doesn't show up on the page

here is the function i am using to update my news website project with infinite scrolling:这是 function 我用来更新我的新闻网站项目的无限滚动:

import React,{ Component } from "react";
import NewsItem from './NewsItem';
import Spinner from "./Spinner";
import PropTypes from "prop-types";
import InfiniteScroll from "react-infinite-scroll-component";

export class News extends Component {
    static defaultProps={
        country: "in",
        pageSize: 6,
        category: 'general',
        totalResults: 0
    }
    static propTypes={
        country: PropTypes.string,
        pageSize: PropTypes.number,
        category: PropTypes.string
    }
    constructor(props) {
        super(props);
        this.state={
            articles: [],
            loading: true,
            page: 1
        }
    }
    async updateNews() {
        const url=`https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=[apikey]&page=${this.props.page}&pageSize=${this.props.pageSize}`;
        this.setState({ loading: true })
        let data=await fetch(url);
        let parsedData=await data.json()
        this.setState({
            articles: parsedData.articles,
            totalResults: parsedData.totalResults,
            loading: false
        })
    }
    async componentDidMount() {
        this.updateNews()
    }
    // prevClick=async () => {
    //     this.setState({ page: this.state.page-1 })
    // }
    // nextClick=async () => {
    //     this.setState({ page: this.state.page+1 })
    //     this.updateNews();
    // }
    fetchMoreData=async () => {
        this.setState({ page: this.state.page+1 })
        console.log(this.state.page)
        const url=`https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=[api key]&page=${this.props.page}&pageSize=${this.props.pageSize}`;
        let data=await fetch(url);
        let parsedData=await data.json()
        this.setState({
            articles: this.state.articles.concat(parsedData.articles),
            totalResults: parsedData.totalResults
        })
    }
    render() {
        return (
            <div className="container my-4">
                <h2 className="my-5 text-center">Top Headlines of today!</h2>
                <InfiniteScroll
                    dataLength={this.state.articles.length}
                    next={this.fetchMoreData}
                    hasMore={this.state.articles.length!==this.state.totalResults}
                    loader={<Spinner />}>
                    <div>
                        <div className="row">
                            {this.state.articles.map((element) => {
                                return <div className="col-md-4" key={element.title}>
                                    <NewsItem title={element.title} description={element.description} imageUrl={element.urlToImage} newsUrl={element.url} author={element.author} date={element.publishedAt} />
                                </div>
                            })}
                        </div>
                    </div>
                </InfiniteScroll>
            </div>
        )
    }
}

export default News

the issue is that change in state of page shows up in the console but when the page is updated, the same data/news gets repeated.问题是页面 state 的更改显示在控制台中,但是当页面更新时,相同的数据/新闻会重复。 I tried using 'this.state.page' instead of 'this.props.page' but there is no difference i guess.我尝试使用 'this.state.page' 而不是 'this.props.page' 但我猜没有区别。 Is there something i am missing?有什么我想念的吗?

Yes the problem is with your fetchMoreData function.是的,问题出在您的 fetchMoreData function 上。 The way state update work is that it does not update instantly instated its batch all the state update and update it into the next cycle. state 更新工作的方式是它不会立即更新,而是将其批次的所有 state 更新并更新到下一个周期。

You can run this code to better understand this example.您可以运行此代码以更好地理解此示例。

import react, { useState, useEffect } from "react";
 
const App = () => {
      const [state, setstate] = useState(1);
    
      const handleState = () => {
        console.log("before", state);
        setstate(state + 1);
        console.log("after", state);
      };
      return (
        <div>
          <button onClick={handleState}>Check</button>
        </div>
      );
    };
    
    export default App;    

The solution of your problem is that take out your page size from state add 1 then after success call increment it您的问题的解决方案是从 state 中取出您的页面大小添加 1 然后在成功调用后增加它

fetchMoreData = async () => {
    let page= this.state.page + 1; // increment like this
    const url = `https://newsapi.org/v2/top-headlines?country=${this.props.country}&category=${this.props.category}&apiKey=[api key]&page=${page}&pageSize=${this.props.pageSize}`;
    let data = await fetch(url);
    let parsedData = await data.json();

   this.setState({
      articles: this.state.articles.concat(parsedData.articles),
      totalResults: parsedData.totalResults,
      page: page
    });
  };

Here is the problem.这是问题所在。

You shouldn't use the same object or array when updating the state.更新 state 时,不应使用相同的 object 或数组。 If so, the component doesn't know state as updated.如果是这样,则组件不知道 state 是否已更新。

So for line 8: You should copy your array with spread operator ... and concat that array.所以对于第 8 行:您应该使用扩展运算符...复制您的数组并连接该数组。

the problem here was that the increment in the page wasn't happening with set State, so the trick was to replace 'this.props.page' from the api url with a different variable to store the page no.这里的问题是设置 State 并没有发生页面中的增量,所以诀窍是从 api Z572D4E421E5E6B9BC11D815E8A021 不同的变量中替换“this.props.page”以存储页面。 and then incrementing it (see the code below to for this to make sense) so that the page gets incremented later but we do get the correct data.然后递增它(请参阅下面的代码以使其有意义),以便页面稍后递增,但我们确实获得了正确的数据。 I discovered this delay it later on when i was turning the class based components to function based(with hooks).(the delay might still be there so just make sure to cover the delay, by adding 1 in the url too, ie, 'pageNo+1' instead of 'pageNo' although this won't be necessary if you are using function based components with hooks)后来我在将基于 class 的组件转换为基于 function 的组件时发现了这种延迟。(延迟可能仍然存在,所以只要确保通过在 Z572D4E421 中添加 1 来弥补延迟,即 55E6B71BC12A8 pageNo+1' 而不是 'pageNo' 虽然如果您使用基于 function 的带有钩子的组件,这将不是必需的)

The change is quite a lot but if i change it to function based, then the page counter is initialized outside the function and then just increment it inside as the mathematical incrementing is faster then using the setState or anything else.变化很大,但如果我将其更改为基于 function,则页面计数器会在 function 之外初始化,然后只需在内部递增,因为数学递增比使用 setState 或其他任何东西更快。 here is the proper working code:这是正确的工作代码:

import React,{ useEffect,useState } from "react";
import NewsItem from './NewsItem';
import Spinner from './Spinner'
import PropTypes from "prop-types";
import InfiniteScroll from "react-infinite-scroll-component";

const News=(props) => {
    const [articles,setarticles]=useState([])
    const [loading,setloading]=useState(true)
    const [page,setpage]=useState(1)
    const [totalResults,settotalResults]=useState(0)
    const updateNews=async () => {
        const url=`https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${pageNo}&pageSize=${props.pageSize}`;
        let data=await fetch(url);
        let parsedData=await data.json()
        setarticles(parsedData.articles)
        settotalResults(parsedData.totalResults)
        setloading(false)

    }
    useEffect(() => {
        updateNews()
    },[])
    let pageNo=0;
    const fetchMoreData=async () => {
        pageNo=page+1
        const url=`https://newsapi.org/v2/top-headlines?country=${props.country}&category=${props.category}&apiKey=${props.apiKey}&page=${pageNo}&pageSize=${props.pageSize}`;
        let data=await fetch(url);
        let parsedData=await data.json()
        setarticles(articles.concat(parsedData.articles))
        settotalResults(parsedData.totalResults)
        setpage(pageNo)
    }
    return (
        <>
            <h1 className="text-center" style={{ margin: '35px 0px',marginTop: '90px' }}>Top Headlines of today!</h1>
            <InfiniteScroll
                dataLength={articles.length}
                next={fetchMoreData}
                hasMore={articles.length!==totalResults}
                loader={<Spinner />}>
                <div className="container">

                    <div className="row">
                        {articles.map((element) => {
                            return <div className="col-md-4" key={element.title}>
                                <NewsItem title={element.title} description={element.description} imageUrl={element.urlToImage} newsUrl={element.url} author={element.author} date={element.publishedAt} />
                            </div>
                        })}
                    </div>
                </div>
            </InfiniteScroll>
        </>
    )
}
News.defaultProps={
    country: "in",
    pageSize: 6,
    category: 'general',
    totalResults: 0
}
News.propTypes={
    country: PropTypes.string,
    pageSize: PropTypes.number,
    category: PropTypes.string
}
export default News

thank you everyone who helped me in this, as i was able to solve the problem partially but not completely now its done after a good nap.感谢所有在这方面帮助过我的人,因为我能够部分解决问题,但不能完全解决,现在它在午睡后完成。

have a nice day!!祝你今天过得愉快!!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM