1
votes

Usually I use redux-saga, but currently I need redux-thunk. I'm using ducks for modular structure and now for example I have two ducks: auth and user with async actions below:

auth-duck.js

register(credentials) {
    return dispatch => {
        dispatch(actions.registerRequest());
        return service.requestRegister(credentials)
            .then((response) => {
                dispatch(actions.registerSuccess(...));

                // Here I need to dispatch some action from user-duck.js
            })
            .catch(() => dispatch(actions.registerError(...)))
    }
}

user-duck.js

fetchUser() {
    return dispatch => {...}
}

I really don't know how to not mess these two modules and dispatch fetchUser after successful register.

I could return register result (e.g. token or something else) to container from here it was dispatched and then using chaining dispatch fetchUser.

AuthContainer.js

_onSubmit() {
    this.props.register().then(() => this.props.fetchUser);
}

But I don't know is it the best way to manage such operations with redux-thunk?

2
That seems okay as long as _onSubmit doesn't get more complex in the future. I'd probably put that logic inside mapDispatchToProps instead though, personally. That way your component doesn't have to know anything about the actions. - DonovanM
@DonovanM yes, you are right, mapDispatchToProps better then methods in component - Piroru

2 Answers

1
votes

There is no rule thunks can only make one HTTP request. If you need to fetch the user after login, then fetch it.

const login = credentials => dispatch => {
    fetchLogin(credentials).then(() => {
        dispatch({ type: "LoginSuccess" })
        return fetchUser()
    }).then(() => {
        dispatch({ type: "UserFetched" })
    })
}

If you want to reuse the user fetch action, then dispatch a thunk from a thunk.

const fetchCurrentUser = login => dispatch => {
    return fetchUser(login.userId).then(user => {
        dispatch({ type: "UserLoad" })
        return user
    })
}

const login = credentials => dispatch => {
    return fetchLogin(credentials).then(login => {
        dispatch({ type: "LoginSuccess" })
        return dispatch(fetchCurrentUser(login))
    }
}

In one of my apps, I call 7 action thunks after successful login.

1
votes

After a long search I found two options how to share the logic from separate domains. The first one is to use mapDispatchToProps (Thanks @DonovanM), just like this:

function mapDispatchToProps(dispatch) {
   return {
       login: (credentials) => {
           return dispatch(authActions.login(credentials)).then(
               () => dispatch(userActions.fetchUser())
           );
       }
   }
}

login function returns Promise thats why we can chain it to another one.

And the second possible option: Use something like a "bridge" file in our case it is app-sagas.js

app-duck.js

import {actions as authActions} from './auth-duck.js';
import {actions as userActions} from './user-duck.js';

export function doLogin(credentials) {
    return dispatch => {
        return dispatch(authAction.login(credentials)).then(
            () => dispatch(userActions.fetchUser())
        );
    }
}

In the second case we can place all logic into ducks and avoid spreading the logic within containers. But I guess it is possible to combine both methods.