简体   繁体   中英

How to Implement a graceful Login in React-native?

I'm new to react-native and trying to build a login implementation that calls our backend apis hosted on aws and navigates to the homescreen if the api returns a token and stays on the login screen and give an error if the api returns some error.

I feel like my current logic & styling is a bit flawed. The main issue I had been facing was that when I clicked login the onPress handler was called, a request was sent to the api from redux actions, and the handler checked if the token was stored in asyncStorage. To login in this case, I had to press the login button twice, because on the first press the call is made, asyncStorage is null when checked. But if you click again a second time then asyncStorage has some value stored because of that first click. I fixed this issue by setting up a setTimeOut function but I don't think that this is a very good solution.

Secondly, there is some styling issue aswell. I have set up an activity indicator as well but it doesn't perform as I want to. I wish to incorporate it in such a way that when you click on login the activityIndicator appears and if login is succesfull, then transitions to the homescreen. And if unsuccesful then an alert pops up telling the issue. Currently, what happens is when I click login with correct credentials sometimes the activity indicator shows up and sometimes it doesnt. And if there are wrong credentials then it won't appear at all and after a second an alert would come up showing the error.

Here is my code.

login.js

    const {width: WIDTH} = Dimensions.get('window')
    class Login extends Component {

        state = {
            controls: {
                email: {
                    value: "",
                    valid: true,
                    validationRules: {
                        isEmail: true
                    }
                },
                password: {
                    value: "",
                    valid: true,
                    validationRules: {
                        minLength: 6
                    }
                }
            },
            loading: false
        }

        async componentDidMount() {

            let authToken = await AsyncStorage.getItem("auth-token")
            console.log(authToken);
            this.props.onAutoSignIn();

            this.props.navigation.navigate(authToken !== null ? 'MAIN_STACK' : 'LOGIN')

            /* if (authToken){
                this.props.navigation.navigate(this.props.token == null ? 'MAIN_STACK' : 'LOGIN')
            } */

        }

        updateInputState = (key, value) => {
            this.setState(prevState => {
                return{
                    controls: {
                        ...prevState.controls,
                        [key]:{
                            ...prevState.controls[key],
                            value: value
                        }
                    }
                }
            })
        }

        loginRequest = async () => {
            try{
                this.state.loading=true;
                const authData = {
                    email: this.state.controls.email.value,
                    password: this.state.controls.password.value
                }


                this.props.onLogin(authData);

                //let authToken = await AsyncStorage.getItem("auth-token")

                setTimeout(async () => {
                    let authToken = await AsyncStorage.getItem("auth-token");
                    console.log(authToken);
                    this.state.loading=false;
                    this.props.navigation.navigate(authToken !== null ? 'MAIN_STACK' : 'AUTH');

                    }, 2000);


                //console.log(authToken);

                //this.props.navigation.navigate(authToken !== null ? 'MAIN_STACK' : 'AUTH');



            }
            catch(err){
                console.log(err)
            }

        }

        render() {

            return (

            <View style={styles.base}>   
            <ImageBackground style={styles.container} source={img}>
                <KeyboardAvoidingView style={styles.containerKeyboard}>

                    <Image style={styles.logoContainer} source={imgLogo}/>



                    <View style={styles.inputContainer}>
                        <TextInput 
                        style={styles.input}
                        placeholder="Email"
                        placeholderTextColor= {'white'}
                        //underlineColorAndroid= 'transparent'
                        value={this.state.controls.email.value}
                        onChangeText={(val) => this.updateInputState("email",val)} 

                        />
                    </View>

                    <View style={styles.inputContainer}>
                        <TextInput 
                        placeholder="Password"
                        placeholderTextColor= {'white'}
                        //underlineColorAndroid='transparent'
                        secureTextEntry={true}
                        value={this.state.controls.password.value}
                        onChangeText={(val) => this.updateInputState("password",val)} 
                        style={styles.input}
                        />
                    </View>





                    <TouchableHighlight style={styles.loginButton} 
                                    onPress={this.loginRequest}>
                            <Text style={styles.loginText}>Log In</Text>
                    </TouchableHighlight>

                    {this.state.loading &&
                        <View style={styles.loading} pointerEvents="none" >
                            <ActivityIndicator size='large' />
                        </View>
                    }

                </KeyboardAvoidingView>
            </ImageBackground>
            </View>
            )
        }
    }

    const styles = StyleSheet.create({

        base: {
            flex:1
        },

        container: {
            flex: 1,
            //padding: 26,
            //backgroundColor: "black",
            alignItems: "center",
            justifyContent: "center"
        },
        logoContainer: {
            width: 150,
            height: 150,
            position: 'absolute',
            top: 50

        },
        containerKeyboard: {
            flex:1,
            //padding: 26,
            //backgroundColor: "black",
            alignItems: "center",
            justifyContent: "center"
        },
        inputContainer: {
            width: WIDTH-55,
            //borderBottomColor: '#F5FCFF',
            //borderBottomColor: 'red',
            borderRadius: 15,
            borderColor: '#ffffff',
            borderWidth: 1.5,
            backgroundColor: 'black',
            //backgroundColor: "#fff",
            //backgroundColor:'yellow',
            //borderBottomWidth: 1,
            marginBottom:20,
            flexDirection: 'row',
            alignItems:'center',
            opacity:.4


        },
        input: {
            width: WIDTH - 58,
            //height: 55,

            borderRadius: 13,
            fontSize: 16,
            paddingLeft: 45,
            backgroundColor: 'black',
            color: 'white'



        },
        loginButton_image: {
            width: 135,
            height: 50,
            position: 'absolute',
            bottom: 65,
        // opacity: .5,
            //borderRadius: 30



        },


        loginButton: {
            //height:45,
            width: 100,
            justifyContent: 'center',
            alignItems: 'center',
            position: 'absolute',
            bottom: 100,
            opacity: .5 ,
            borderWidth: 2,
            borderColor: 'yellow',
            borderRadius: 10,
            padding: 10
            //marginTop:350,
            //width:250,
            //backgroundColor: "#00b5ec",
        },
        loginText: {
            color: 'yellow',
            fontWeight: 'bold'
        },

        loading: {
            position: 'absolute',
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
            alignItems: 'center',
            justifyContent: 'center',
            backgroundColor: 'black'
        }

    })

    const mapStateToProps = (state) => {

        return {
            token: state.login.token
        }
    }

    const mapDispatchToProps = (dispatch) => {

        return {
            onLogin: (authData) => {dispatch(authLogin(authData))},
            onAutoSignIn: () => {dispatch(authGetToken())}
        }
    }

    export default connect (mapStateToProps, mapDispatchToProps)(Login);

action.js

    export const authLogin = (authData) => {
        return dispatch => {
            let url = "http://ec2-54-169-225-146.ap-southeast-1.compute.amazonaws.com:8000/api/auth/login/";
            let body = JSON.stringify({
                username: authData.email,
                password: authData.password

            })
            return fetch(url, {
                method: "POST",
                body: body,
                headers: {
                "Content-Type": "application/json"
                }
            })

            .then((res) => { return res.json() })
            .then((parsedRes) => {
                console.log(parsedRes)
                if (parsedRes.error) {
                    console.log("Authentication failed, please try again!");
                    throw parsedRes.error

                } else {
                    dispatch(authStoreToken(parsedRes.token))
                    return true
                }

            })
            .catch(err => {
                console.log("ithaaay takooos")
                console.log(err);
                alert('Authentication Failed, Please Try Again!')
            })
        }
    }

    export const authStoreToken = token => {
        return dispatch => {
            dispatch(authSetToken(token));
            AsyncStorage.setItem("auth-token", token)
        }
    }

I would be grateful if someone could give me some direction I've been stuck with these things for a while now. I mean I am doing what I want to but this isn't graceful at all

Yes you are doing it wrong. setTimeout is causing the problem and not good solution. remove that from loginRequest function. and on login success in authStoreToken you are dispatching authSetToken so I am assuming this will update the token as a result call componentDidUpdate life cycle method. That's where you can check if the token prop of login component has some value and then navigate like this. this.props.navigation.navigate(this.props.token !== null ? 'MAIN_STACK' : 'AUTH');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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