简体   繁体   English

状态改变了,但是react的render方法没有触发

[英]The state changed but the render method from react does not trigger

I am currently self teaching myself code and at the moment diving into React.js.我目前正在自学代码,目前正在深入研究 React.js。 I am building a simple app which displays beer information pulled through the punkAPI ( https://punkapi.com/documentation/v2 ).我正在构建一个简单的应用程序,它显示通过 punkAPI ( https://punkapi.com/documentation/v2 ) 提取的啤酒信息。

In my app I wanted to add some kind of "infinite" scroll which would pull more data from the API when the user reaches the bottom of the page.在我的应用程序中,我想添加某种“无限”滚动,当用户到达页面底部时,它会从 API 中提取更多数据。

At the moment, the handleScroll method works, and updates the state of the component but it does not trigger the render method and I was wondering why.目前,handleScroll 方法工作,并更新组件的状态,但它不会触发渲染方法,我想知道为什么。

I realize that there are a lot of things wrong with my code and I plan to restructure it, add some booleans in this.state to check if there is still more data to load, to handle errors and to not trigger the handleScroll method so intensively.我意识到我的代码有很多问题,我打算重新构造它,在 this.state 中添加一些布尔值以检查是否还有更多数据要加载,处理错误并不会如此密集地触发 handleScroll 方法.

However, I am still wondering why there is no rendering happening even though the state is updated.但是,我仍然想知道为什么即使状态更新了也没有渲染发生。

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


So BeerCards are correctly appended when the page is loading then when you scroll the console shows you that the state is updated (way too much but still).因此,当页面加载时正确附加 BeerCards,然后当您滚动控制台时,会显示状态已更新(太多但仍然如此)。 I would expect the page loading a shit ton of BeerCards but nothing is happening.我希望页面加载大量 BeerCards,但什么也没发生。 Why is that?这是为什么?

As soon as you invoke fetch which is the last statement inside setState, an undefined would be returned.一旦调用 setState 中的最后一个语句 fetch,就会返回一个 undefined。 Try transforming the setState parameter to an async function:尝试将 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
  };
});

Instead of returning an object from your async fetch , call setState inside the .then()不是从异步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 });
    });

You are so close!你离得那么近! By simply adding the keyword "async" in front of "prevState" in "this.setState" and "return await" in front of "fetch", the state of your app should be updated and trigger a rerender as expected.通过简单地在“this.setState”中的“prevState”前面添加关键字“async”,在“fetch”前面添加“return await”,您的应用程序的状态应该被更新并按预期触发重新渲染。

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

相关问题 反应无法识别第一次渲染时输入框更改的 state - React not recognizing changed state from input boxes on first render Mobx-react 无渲染但 state 已更改 - Mobx-react no render but state changed 状态更改后,UI不会呈现 - UI does not render after state is changed 当redux状态更改时,应该使用哪种React循环方法重新渲染组件? - Which React cycle method should I use to re-render component when redux state has changed? 无法通过渲染方法React es6设置动态状态 - Unable to set dynamic state from render method react es6 为什么使用React Hooks,MomentJS对象和时间间隔/超时更新状态不会触发重新渲染? - Why does updating state using React Hooks, MomentJS object and interval/timeout not trigger re-render? 使用 Lodash.remove 通过 Vuex 突变更改 state 不会触发我的 Vue 组件中的反应性重新渲染 - Changed state through Vuex mutation using Lodash.remove does not trigger a reactive re-render in my Vue component 反应 | DataGrid 不更新 State - React | DataGrid does not update with changed State 反应中的功能组件是否会触发重新渲染? - Does functional component in react trigger a re render? react状态数组对象在render()方法中不可访问 - react state array object is not accessible in render() method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM