【问题标题】:The state changed but the render method from react does not trigger状态改变了,但是 react 的 render 方法没有触发
【发布时间】:2019-09-21 04:16:21
【问题描述】:

我目前正在自学代码,目前正在研究 React.js。我正在构建一个简单的应用程序,它显示通过 punkAPI (https://punkapi.com/documentation/v2) 提取的啤酒信息。

在我的应用程序中,我想添加某种“无限”滚动,当用户到达页面底部时,它会从 API 中提取更多数据。

目前,handleScroll 方法有效,并且更新了组件的状态,但它没有触发 render 方法,我想知道为什么。

我意识到我的代码有很多问题,我计划对其进行重构,在 this.state 中添加一些布尔值以检查是否还有更多数据要加载,处理错误并且不触发 handleScroll方法如此密集。

但是,我仍然想知道为什么即使状态已更新,也没有发生渲染。

class BeerList extends Component {
    constructor() {
        super()
        this.state = {
            loading: false,
            beers: []
        }
        this.handleScroll = this.handleScroll.bind(this)
    }

    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll, true);

        this.setState({
            loading: true
        })
        fetch("https://api.punkapi.com/v2/beers?per_page=12")
            .then(response => response.json())
            .then(data => {
                this.setState({
                    loading: false,
                    beers: data
                })
            })
    }

    handleScroll() {
        const checkForNewBeers = () => {
            let lastBeerCard = document.querySelector(".beer-list > div:last-child");
            let lastBeerCardOffset = lastBeerCard.offsetTop + lastBeerCard.clientHeight;
            let pageOffset = window.pageYOffset + window.innerHeight;

            if (pageOffset <= lastBeerCardOffset - 10) {
                return;
            }
            this.setState(prevState => {
                const beers = prevState.beers;
                const page = (prevState.beers.length / 12) + 1;
                fetch(`https://api.punkapi.com/v2/beers?per_page=12&page=${page}`)
                    .then(response => response.json())
                    .then(data => {
                        for (let item of data) {
                            beers.push(item);
                        }
                        console.log({
                            beers: beers
                        });
                        return {
                            beers: beers
                        }
                    });
            });
        }
        document.addEventListener("scroll", function (event) {
            checkForNewBeers();
        });
    }


    render() {
        let beerCards = []
        if (this.state.beers.length > 0) {
            beerCards = this.state.beers.map(beer => {
                return <BeerCard
                key = {
                    beer.id
                }
                img = {
                    beer.image_url
                }
                title = {
                    beer.name
                }
                description = {
                    beer.description
                }
                />
            })
        }

        return ( <
            div className = "container" >
            <
            div className = "row beer-list" > {
                beerCards
            } <
            /div> < /
            div >
        )
     }

}

export default BeerList


因此,当页面加载时,BeerCards 会正确附加,然后当您滚动控制台时,会显示状态已更新(太多但仍然如此)。我希望该页面加载大量的 BeerCards,但什么也没有发生。这是为什么呢?

【问题讨论】:

  • 您确定handleScroll 中的状态正在更新吗?只要您调用 fetch (setState 中的最后一条语句),就会返回一个未定义的。

标签: javascript reactjs scroll state render


【解决方案1】:

不要从异步fetch 返回对象,而是在.then() 内调用setState

let beers = this.state.beers;
const page = (this.state.beers.length / 12) + 1;
fetch(`https://api.punkapi.com/v2/beers?per_page=12&page=${page}`)
    .then(response => response.json())
    .then(data => {
        for (let item of data) {
            beers.push(item);
        }

         this.setState({ beers });
    });

【讨论】:

  • 感谢您的快速回答!那肯定比我做的更顺利:)
【解决方案2】:

只要调用 setState 中的最后一个语句 fetch,就会返回一个未定义的语句。尝试将 setState 参数转换为异步函数:

this.setState(async prevState => {
  const beers = prevState.beers;
  const page = prevState.beers.length / 12 + 1;
  let response = await fetch(
    `https://api.punkapi.com/v2/beers?per_page=12&page=${page}`
  );
  response = await response.json();
  for (const item of response) {
    beers.push(item);
  }
  console.log({
    beers: beers
  });
  return {
    beers: beers
  };
});

【讨论】:

  • 谢谢它的工作!但我不明白为什么它会返回一个未定义的。我必须承认我对异步如何在 js 中工作的知识仍然非常有限。
  • then 不会阻止调用函数的执行。因此,您的函数继续返回undefined。另一方面,await 让 JavaScript 等到 promise 完成并返回其结果。因此,您在此之后编写的任何内容都确保仅在 promise 解决后运行(包括函数结束)
  • 好的,很清楚,非常感谢您的解释!
【解决方案3】:

你离得太近了!只需在“this.setState”中的“prevState”前添加关键字“async”并在“fetch”前添加“return await”,您的应用程序的状态应该会更新并按预期触发重新渲染。

【讨论】:

  • 是的,谢谢,有人发表了几乎相同的评论。但是,我不明白为什么它会在没有异步的情况下返回未定义。我必须承认我对异步在 js 中的工作方式的了解仍然非常有限
  • 没问题!看起来伊斯瓦尔解释得很好。希望对您有所帮助:)
猜你喜欢
  • 2018-08-09
  • 2019-07-22
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
相关资源
最近更新 更多