cinnaroll45
cinnaroll45

Reputation: 2790

Async actions within a React component

I'm working on a login form in a project with React, Redux and Redux-Thunk. Using Redux-Thunk, I'm able to dispatch async actions like delivering the submitted login form to the back-end and bringing back validated data back to the state via reducers. Once the component gets the data it needs, it can then redirect to the page it needs without a problem.

The issue is, right before redirecting the user I need to write some data which came from asynchronous network request to the localStorage. If I don't do this async, the user gets redirected with the initial state values written to the local storage.

As a solution, I'm using promises and timeouts right in the React component to wait for the incoming data.

This approach seems to work but it doesn't feel right, can someone suggest me a better practice?

Here's the code in the component, I filtered most of the irrelevant things to make it as short as possible here.

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {browserHistory} from 'react-router';
import {reduxForm} from 'redux-form';
import {connect} from 'react-redux';

import {validate} from './../utils/login/surfaceValidation';
import {inputAlerts} from './../utils/login/inputAlerts';

import {submitLogin} from './../redux/actions/index';

class Form extends Component {

    componentWillReceiveProps(nextProps) {
        if(nextProps.loginApproved) {
            this.handleValidLogin();
        }
    }

    handleLogin(props) {
        this.props.submitLogin(props);
        // submitLogin is async action handled by redux-thunk it returns
        // this.props.loginApproved and if it's true componentWillReceiveProps
        // will trigger.
    }

    handleValidLogin() {
        this.writeToStorage()
        .then(() => {
            browserHistory.push('/main');
        }).catch((err) => {
            console.log(err);
        });
    }

    writeToStorage(){
        return new Promise((resolve, reject) => {
            setTimeout(() =>{
                localStorage.setItem('user',
                    JSON.stringify({
                        authenticated: true,
                        username: this.props.username,
                        id: this.props.id,
                        token: this.props.token
                    }));
            }, 3000);
            setTimeout(() => {
                if(this.props.token != null) {
                    resolve();
                    console.log('got a token - resolving.');
                } else {
                    reject();
                    console.log('no token - rejecting. ');
                }
            }, 4000);
        });
    }

    render() {

        return (
            // Login form component is here.
            // When user submits form, this.handleLogin() is called. 
        );
    }
}


function mapDispatchToProps(dispatch){
    return bindActionCreators({submitLogin});
}

function mapStateToProps(state) {
    return {
        loginApproved: state.login.loginApproved,
        username: state.login.username,
        id: state.login.id,
        token: state.login.token
    };
}

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

Upvotes: 1

Views: 657

Answers (1)

Bartek Fryzowicz
Bartek Fryzowicz

Reputation: 6674

As far as I know localStorage.seItem is synchronous so you can call function saving data to storage before redirecting.

Upvotes: 1

Related Questions