I have a login modal. I use an action creator to turn isLoginModalVisible: true in the reducers. Calling the action creator inside a container, inside a component's onClick, like so:
<TextButtonRight onClick={()=> this.props.showLoginModal(true)}>
Inside the login modal, I have a login button that submits a form. I want the modal to disappear when 200OK otherwise, I display an error message in the modal. calling this action creator on login button click:
export function logInUser(){
console.log("Actions--> logInUser");
//Imagine I got a 200OK
dispatch(showLoginModal(false));
return({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
I'm calling the action creator to hide the modal from logInUser action creator and it's not working. The showLoginModal action creator does get hit but it does not dispatch to a reducer.
Here's the showLoginModal action creator:
export function showLoginModal(bool){
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
(I'm sorry if I'm making a rookie mistake)
part of my reducer.It does work because that's how I show the login modal. I pass false when I want to hide it. There's no problem with the payload either. The console.log isn't getting get when I call it via another action creator. works okay when I pass it to onClick on submit button this way:
onClick={()=> this.props.showLoginModal(false)}
case UPDATE_LOGIN_MODAL_VISIBLE:
console.log("REDUCER-->"+UPDATE_LOGIN_MODAL_VISIBLE);
return {...state, loginModalVisible: action.payload};
break;
CombineReducers:
const rootReducer = combineReducers({
posts: postsReducer,
displayComps: displayComponentsReducer,
form: formReducer,
searchForm: searchFormReducer
});
Sorry, I should have mentioned that I am using thunk. I wanted to know if there was a way to call an action from this one, like so:
req.then((response)=>{
console.log("REQ_COMPLETE");
dispatch({type: UPDATE_USER_LOGGED_IN, payload: true});
//like so:
showLoginModal(false);
localStorage.setItem('userLoggedIn', true);
})
instead of adding this:
dispatch({type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false});
dispatching the action from another action creator seemed kinda hacky.
Clarifying some terminology might help. Apologies in advance if this is stuff you already know.
When you want to dispatch multiple actions with redux-thunk, you dispatch an operation. That's a common pattern. It looks like your logInUser()
function is an operation. For the canonical example, see fetchPostsIfNeeded()
in Dan Abramov's documentation here.
An action creator simply returns an object and does nothing. An operation does stuff (often async) and then dispatches actions, which it generally builds by calling action creators. There's nothing hacky about dispatching actions from an operation.
However, calling any function from an action creator is not recommended. Action creators should return a simple object and have no side effects, like your showLoginModal()
function. Note that there is NO BEHAVIORAL DIFFERENCE between calling an action creator and creating an object manually. So doing this:
var action = { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }
is the same as
var action = showLoginModal(false)
Critical to note: Neither of these pieces of code does anything! They create an object but don't use it for anything. Nothing will happen in your app until you dispatch(action)
.
dispatch()
ed.dispatch
function variable that it in turn uses to dispatch actions. It looks like this code of yours is calling an action creator but not dispatching it:
showLoginModal(false);
Changing that to
dispatch(showLoginModal(false));
might fix your issue.
It can be helpful to name action creators in a way that will help anyone reading the code (including you) to see/remember that they just create an action. For example you could rename showLoginModal
to showLoginModalAction
or even createShowLoginModalAction
.
The logInUser()
function is an operation (since it dispatches an action) that, for no clear reason, also returns an action. The action it returns is never dispatched to the store, at least in the code that is posted, so it would have no effect. Probably your intention is to dispatch that action to the store, so why not dispatch it right there?
logInUser(){
dispatch( sendingLoginRequestAction() );
someAsyncLoginFuncThatReturnsAPromise(userName, password)
.then(result=>{
dispatch( loginSucceededAction(result) );
dispatch( hideLoginModalAction() );
});
}
Those action creators would look like:
sendingLoginRequestAction() { return { type: UPDATE_SENDING_LOGIN_REQUEST }; } // You don't have anything like this, but it could be used to show a Waiting animation
loginSucceededAction() { return { type: UPDATE_USER_LOGGED_IN, payload: true }; }
hideDialogModalAction { return { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }; }
Does that help?
I think part of your problem is that you are not using Redux Middleware. Here is a good tutorial from redux's creator himself: Building React Applications with Idiomatic Redux
For your purposes, if you incorporate Redux Thunk, you should be able to dispatch multiple actions from one action creator.
Here's how you can do it:
install:
npm install --save redux-thunk
put this in your store.js
file
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
Now, your action creator will have dispatch
and getState
available.
export const showLoginModal = (bool) => {
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
export const loginUser = () => (dispatch, getState) => {
console.log("Actions--> logInUser");
// you have complete state available as getState(), but this is
// not a good design pattern, so use with caution
//Imagine I got a 200OK
dispatch(showLoginModal(false));
dispatch({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
I hope it helps. Have fun hacking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With