简体   繁体   English

获取数据后,React setState不会重新呈现

[英]React setState doesn't re-render after fetching data

This code works if data already fetched. 如果已经提取了数据,则此代码有效。
But doesn't work if I refresh the page and doesn't rerender element. 但是如果我刷新页面并且不重新渲染元素则不起作用。
I'm also using Next JS if it's worth mentioning. 如果值得一提,我也在使用Next JS。

class Books extends Component {
    constructor(props) {
        super(props);
        this.state = {
            book: []
        }
        this.renderBooks= this.renderBooks.bind(this);
    }

    renderBooks() {
        let item;
        let items = [];
        return new Promise((resolve, reject) => {
            this.props.ids.forEach(address => {
                firebase.database().ref(`/books/${address}`)
                    .on('value', snap => {
                        item = snap.val();
                    });
                items.push(item);
            })
            resolve(items);
        });
    }

    async componentDidMount() {
        try {
            let res = [];
            res = await this.renderBooks();
            console.log(res);
            this.setState({ book: res });
        } catch (error) {
            console.log(error);
            this.setState(prevState => {
                return { book: 'err' }
              });
        }
    }

    render() {
        return (
            <div>
                { <List grid={{ gutter: 16 }}
                        dataSource={ this.state.book }
                        renderItem={ item => (
                            <List.Item>
                                <Card title={ !!item && item.title }>
                                    ...Book content...
                                </Card>
                            </List.Item>
                        )} />
                }
            </div>
        );
    }
}

export default Books; 

Is there anything to know about setState and fetching data that I missed here? 是否有任何关于setState和获取我错过的数据的知识?
PS. PS。 Edited constructor to book: []. 编辑构造函数预订:[]。

You are initializing this.state.book with a promise. 您正在使用promise初始化this.state.book Try setting it to null instead: 尝试将其设置为null

this.state = {
    book: null
}

You cannot initialize book with a promise. 您无法使用承诺初始化book Instead you can have a solution like below. 相反,你可以有一个像下面的解决方案。

Add a conditional rendering to you render method so it will know when to render book . render方法添加条件渲染,以便知道何时渲染book Also you don't need to return new Promise in this case. 在这种情况下,您也不需要返回new Promise

class Books extends Component {
    constructor(props) {
        super(props);
        this.state = { books: null }
    }

    componentDidMount() {
        this.renderBooks()
    }

    renderBooks() {
        this.props.ids.forEach(address => {
            firebase.database().ref(`/books/${address}`)
             .on('value', snap => {
                this.setState({books: [...(this.state.books || []), snap.val()] });
            });
        });
    }

    render() {
        return (
           this.state.books ? 
            <div>
                { <List grid={{ gutter: 16 }}
                        dataSource={ this.state.books }
                        renderItem={ item => (
                            <List.Item>
                                <Card title={ !!item && item.title }>
                                    ...Book content...
                                </Card>
                            </List.Item>
                        )} />
                }
            </div> 
           : 'Initializing'
        );
    }
}

export default Books;

Promises are basically async functions that are resolved when it's time. Promise基本上是异步函数,可以在时间解析。

So when you do 所以,当你这样做

 var item, items = []; // <---- Step 1
 this.props.ids.forEach(address => {
     firebase.database().ref(`/books/${address}`)
         .on('value', snap => {
             item = snap.val(); // <--- Step 3
         });
     });
     items.push(item); // <----- Step 2
 });

The steps are like this. 步骤是这样的。 So you were doing items.push(item) before item was assigned a new value which is snap.val() . 所以你在为item分配一个新值items.push(item)之前你正在做items.push(item) snap.val() And that makes item undefined . 这使得item undefined

I guess the second result you have is thanks to caching. 我猜你的第二个结果是由于缓存。 If the internet connection is SOOOO FAST Step 3 might be earlier than Step 2 , but that's a bad assumption. 如果互联网连接是SOOOO FAST, Step 3可能早于Step 2 ,但这是一个不好的假设。 That's why the second time you get the result correct. 这就是为什么你第二次得到正确的结果。

In this answer's case, instead of having an items array, the snap.val() is added to this.state.books. 在这个答案的情况下, snap.val()不是有一个items数组, snap.val()添加到this.state.books中。 But this makes it a bit heavyweight. 但这使它有点重量级。 Because every time a query on('value') is called, the setState method will be triggered and the component will be rendered again. 因为每次调用on('value')查询on('value') ,都会触发setState方法并再次呈现组件。 If there were 1000 ids the state would change 1000 times. 如果有1000个国家,州将改变1000次。

That's why instead of getting the data one by one I would suggest you to get all the data at once. 这就是为什么我不建议您逐个获取所有数据,而是逐个获取数据。 Try to google something like 'retrieve multiple data from firebase javascript' . 尝试google类似'retrieve multiple data from firebase javascript' Unfortunately I don't know much about firebase so cannot help there. 不幸的是,我对firebase了解不多,所以无法帮助。

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

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