reactjsreact-reduxazure-ad-msalreact-aad-msal

How do I trigger an action after login using react-redux and react-aad-msal?


I have created an application which uses react-redux and react-aad-msal to handle AD login. I can login and logout without any problems, but after the user is logged in I want to trigger an API call to fetch data from an API. I'm not sure how to trigger this action both on manual and forced login using the AzureAD component and the authProvider it requires.

At the moment I have added a call in my index component in the componentDidMount function to call the API to get the data, but if the user isn't on the index page and refreshes the page the application breaks since the API call isn't triggered after AD login is completed.

I don't want to trigger the call in my auth reducer, which I think would be an anti pattern in regards to Redux and how it is supposed to be used.

How can I tap into the "AAD_LOGIN_SUCCESS" or "AAD_INITIALIZED" actions so that my API call always is triggered after login and thus avoiding adding logic in my components?

This is basically what I have at the moment, which works, but not if you are on the /some-other-page and hit refresh, since that won't trigger the API call.

App.js

...
<Router>
    <Header />
    <AzureAD provider={ authProvider } reduxStore={ reduxStore } forceLogin={ true }>
        <Switch>
            <Route exact path="/">
                <EnvironmentsOverview />
            </Route>
            <Route path="/some-other-page">
                <SomeOtherPage />
            </Route>
            <Route path="*">
                <NotFound />
            </Route>
        </Switch>
    </AzureAD>
</Router>
...

EnvironmentsOverview.js

...
export class EnvironmentsOverview extends Component {
    componentDidMount() {
        this.props.getSystemsAndEnvironments();
    }

    render() {
        ...
    }
}
...

Solution

  • Depends on how you want to handle this, but for me, I'm happy using redux-saga, you could do something similiar with thunk if that's your prefered choice.

    1. Simple watcher for the login event
    2. Worker to fire off any side-effects you need to do post login i.e. async or blocking requests/connection you need to make.
    3. Potentially dispatch other actions from your worker function

    NOTE: The redux-saga docs are great, super in detail, but an example of something I've just done for your specific use case below:

    import { takeLatest, put, call } from 'redux-saga/effects';
    
    //watcher 
    function* watchForLoginSuccess() {
        yield takeLatest('AAD_LOGIN_SUCCESS', doPostLoginWorker); 
    };
    
    //worker
    function* doPostLoginWorker() {
        try {
            //async action 
            const response = yield call(functionRefToFetchData, someParameterForFunction);
            //Dispatch another action with returned async data
            yield put(addUserData(response)); 
        } catch (error) {
            //dispatch an error action with the error info as payload
            yield put(addError(error));
        }
    };
    
    export default [
        watchForLoginSuccess
    ]