ReactNative:在现有状态转换期间(例如在`render`中)不能更新。渲染方法应该是props和state的纯函数

时间:2019-09-01 17:17:05

标签: javascript react-native

这是我的代码,我似乎找不到问题。我已经研究了问题,但是找不到解决方案,所以我向StackOverflow寻求帮助!

如您所见,我想在我的LoadingScreen中加载字体,并在完成后移至下一个屏幕。如果有更简单的方法,请告诉我。

import React from 'react';
import { StyleSheet, View, AsyncStorage, Alert, ActivityIndicator } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient'
import * as Font from 'expo-font';
import * as firebase from "firebase";


export default class Loading extends React.Component {

constructor(props) {
    super(props);
    this.state = {
        fontLoaded: false,
        client: {
            uid: ""
        }
    };
}


async componentWillMount() {
    //Load fonts + Login to Firebase + capture user ID
    let self = this;
    await Font.loadAsync({
        "Roboto-Regular": require("../assets/fonts/Roboto-Regular.ttf"),
        "Courgette-Regular": require("../assets/fonts/Courgette-Regular.ttf"),
        "Raleway-Regular": require("../assets/fonts/Raleway-Regular.ttf")


    })

    await firebase.auth().signInAnonymously().catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        Alert.alert("Error code : " + errorCode, errorMessage)

    });

    //Register the UID
    await this.setState({ uid: firebase.auth().currentUser.uid })

    this.setState({
        client: {
            ...this.state.client,
            uid: firebase.auth().currentUser.uid
        }
    });




    await this.setState({ fontLoaded: true })



}


render() {

    if (this.state.fontLoaded) {

        return (

            this.props.navigation.navigate("Home", { client: this.state.client })
        )
    }

    return (
        <View style={styles.container}>
            <LinearGradient
                colors={["#5B86E5", "#36D1DC"]}
                style={{ flex: 1 }}
            >
                <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}>

                    <ActivityIndicator size="large" color="#FFF" />

                </View>
            </LinearGradient>
        </View >
    )
}
}

const styles = StyleSheet.create({
    container: {
    flex: 1
}


});

2 个答案:

答案 0 :(得分:3)

我认为最好加载Home屏幕。在完成操作后执行诸如获取页面中的数据并导航到另一个页面之类的操作效率不高。我认为最好在componentDidMount生命周期中获取数据,并在收到数据后将fontLoaded更改为true,如下所示:

import React from 'react';
import { StyleSheet, View, AsyncStorage, Alert, ActivityIndicator } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient'
import * as Font from 'expo-font';
import * as firebase from "firebase";


export default class Home extends React.Component {

constructor(props) {
    super(props);
    this.state = {
        fontLoaded: false,
        client: {
            uid: ""
        }
    };
}


async componentDidMount() {
    //Load fonts + Login to Firebase + capture user ID
    let self = this;
    await Font.loadAsync({
        "Roboto-Regular": require("../assets/fonts/Roboto-Regular.ttf"),
        "Courgette-Regular": require("../assets/fonts/Courgette-Regular.ttf"),
        "Raleway-Regular": require("../assets/fonts/Raleway-Regular.ttf")


    })

    await firebase.auth().signInAnonymously().catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        Alert.alert("Error code : " + errorCode, errorMessage)

    });

    //Register the UID
    await this.setState({ uid: firebase.auth().currentUser.uid })

    this.setState({
        client: {
            ...this.state.client,
            uid: firebase.auth().currentUser.uid
        }
    });




    await this.setState({ fontLoaded: true })



}


render() {

    if (this.state.fontLoaded) {

        return (
........... Any code that presents in your Home component

        )
    }

    return (
        <View style={styles.container}>
            <LinearGradient
                colors={["#5B86E5", "#36D1DC"]}
                style={{ flex: 1 }}
            >
                <View style={{ justifyContent: "center", alignItems: "center", flex: 1 }}>

                    <ActivityIndicator size="large" color="#FFF" />

                </View>
            </LinearGradient>
        </View >
    )
}
}

const styles = StyleSheet.create({
    container: {
    flex: 1
}


});

我希望它对您有所帮助。如果这是您想要的解决方案,请给我投票:)

答案 1 :(得分:2)

您正在混合UI(渲染方法)和功能(在渲染内部导航)。当React检测到状态或道具更新时,该方法将执行多次。

如果这只是一个加载屏幕,则从渲染中删除条件,仅显示一个加载屏幕,并从componentDidMount方法导航到下一个屏幕,该方法仅在屏幕加载时触发一次。

那应该消除错误。基本上,删除setState({fontLoaded:true})并从那里导航到下一个屏幕。