在setState之后,React异步函数将状态重置为null

时间:2018-11-07 21:12:55

标签: javascript reactjs react-native asynchronous async-await

当您单击分页按钮时,以下代码将返回未处理的承诺拒绝'cannot read property 'lastVisiblePost' of undefined的错误。

似乎在执行初始getPosts之后立即将状态设置为null。

它在第一次运行时有效,但是当您按下调用getPosts状态的按钮时,将等于null

class App extends Component {
    state = {
        listState: 'top',
        allPosts: [],
        lastVisiblePost: null
    }

    async componentDidMount() {
        const { user } = await firebase.auth().signInAnonymously()

        this.getPosts()
    }

    async getPosts() {
        console.log(this.state)
        console.log(this.state.lastVisiblePost)
        let posts = null
        if (this.state.lastVisiblePost) {
            posts = await firebase.firestore()
                    .collection('posts')
                    .orderBy('likes')
                    .startAfter(last)
                    .limit(2)
                    .get()
        } else {
            posts = await firebase.firestore()
                    .collection('posts')
                    .orderBy('likes')
                    .limit(2)
                    .get()
        }
        let newPosts = []
        posts.forEach(post => {
            newPosts.push({
                id: post.id,
                data: post.data()
            })
        })

        console.log(posts.docs)
        console.log("memes", posts.docs[posts.docs.length - 1])

        this.setState({
            allPosts: newPosts,
            lastVisiblePost: posts.docs[posts.docs.length - 1]
        }, () => {
            console.log("doink", this.state)
        })
    }

    render() {
        const { listState, allPosts } = this.state

        return (
            <SafeAreaView style={styles.container}>
                { /* Logo */ }
                <View style={styles.logoContainer}>
                    <Image style={styles.logo} source={anywayLogo} />
                </View>
                { /* Top and New Buttons */ }
                <View style={styles.topAndNewContainer}>
                    <Text style={[styles.topAndNewText, listState === 'top' ? { color: 'red' } : { color: 'black' }]} onPress={() => this.setState({listState: 'top'})}>top</Text>
                    <Text style={[styles.topAndNewText, listState === 'new' ? { color: 'red' } : { color: 'black' }]} onPress={() => this.setState({listState: 'new'})}>new</Text>
                </View>
                { /* Feed */ }
                <View style={styles.feedContainer}>
                    {
                        allPosts.map(post => {
                            return (<Text key={post.id}>{post.data.title}</Text>)
                        })
                    }
                </View>
                <Button title="Next page" onPress={this.getPosts} />
            </SafeAreaView>
        );
    }
}

异步正在等待破坏我的状态吗?

2 个答案:

答案 0 :(得分:1)

这是因为您的getPosts函数未正确绑定到您的组件,因此this指的是getPosts函数,而不是您的组件。由于它没有任何状态属性,因此会出现错误。

有两种方法可以执行此操作,或者将其绑定到构造函数中:

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      listState: 'top',
      allPosts: [],
      lastVisiblePost: null
    }

    this.getPosts = this.getPosts.bind(this)
  }
}

或者您使用transform-class-properties babel插件,然后可以将组件方法声明为箭头函数,这些函数不提供自己的this,因此this关键字将自动引用您的组件:

getPosts = async () => {
  //your code
}

答案 1 :(得分:0)

您需要在构造函数中设置状态,否则不会在其余函数中定义状态。

constructor(props) {
   super(props);
   this.state = {
    listState: 'top',
    allPosts: [],
    lastVisiblePost: null
   }
}