Passing arguments to action - reactjs

I am trying to pass an object as an argument to a user action but I can't access it in the action. It just returns undefined when I do console.log(dataToSubmit).
Here is the action method:
const loginUser = (dataToSubmit) => {
console.log(dataToSubmit)
return (dispatch) => {
dispatch(loginUserRequest)
axios.post('http://localhost:5000/api/user/login' , dataToSubmit)
.then(response => {
if(response.data.loginSuccess){
const user = response.data.user
dispatch(loginUserSuccess(user))
}
else{
console.log('Login attempt failed')
}
})
.catch(error => dispatch(loginUserFailure(error.message)))
}
}
export default loginUser
I'm passing the argument here:
const handleSubmit = (event) => {
event.preventDefault();
if (isFormValid(email , password)){
const data = {
email,
password
}
loginUser(data)
}
}
I've already mapped dispatch to props:
const mapDispatchToProps = (dispatch) => {
return{
loginUser : () => dispatch(loginUser())
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SignIn)
I'm new to redux. Thanks

You need to pass the argument in mapDispatchToProps
const mapDispatchToProps = (dispatch) => {
return{
loginUser : (data) => dispatch(loginUser(data))
}
}

Related

How to test a dispatch function?

Hello I'm trying to test this function with the return of the dispatch in how many times it have been called, but really don't know how to do it correctly in order to call dispatch
export const mapDispatchToProps = (dispatch) => {
return {
hideSidebar: () => {
dispatch(hideSidebar)
},
updateUnit: (unitObject) => {
dispatch(settingsActions.updateArray(unitObject))
}
}
}
I have these test
describe('mapDispatchToProps', () => {
test('test', () => {
const dispatch = jest.fn(() => Promise.resolve())
mapDispatchToProps(dispatch)
expect(dispatch).toHaveBeenCalledTimes(2)
})
})
Any suggestions?
Create a dispatch mock function and pass it to mapDispatchToProps.
Then call the functions defined on the result.
You can use something like toHaveBeenCalledWith to verify that the correct action was dispatched:
// Stubs for hideSidebar and settingsActions.updateArray
const hideSidebar = { type: 'hide-side-bar' };
const settingsActions = { updateArray: u => ({ type: 'update-unit', payload: u })};
export const mapDispatchToProps = (dispatch) => {
return {
hideSidebar: () => {
dispatch(hideSidebar)
},
updateUnit: (unitObject) => {
dispatch(settingsActions.updateArray(unitObject))
}
}
}
test('mapDispatchToProps', () => {
const dispatch = jest.fn();
const map = mapDispatchToProps(dispatch);
map.hideSidebar();
expect(dispatch).toHaveBeenCalledWith({ type: 'hide-side-bar' }); // Success!
map.updateUnit({ theKey: 'theVal' });
expect(dispatch).toHaveBeenCalledWith({ type: 'update-unit', payload: { theKey: 'theVal' } }); // Success!
})

How to cover lines in mapDispatchToProps with Jest?

My question is how do we cover these lines in jest?
export const mapDispatchToProps = dispatch => {
return {
submitClaimsForm: form => {
dispatch(submitClaimsForm(form));
}
};
};
In my component this is what the redux connected area looks like:
export function mapStateToProps(state) {
return {
formNonMember: state.form,
submissionSuccess: state.claimSubmission.submissionSuccess
};
}
export const mapDispatchToProps = dispatch => {
return {
submitClaimsForm: form => {
dispatch(submitClaimsForm(form));
}
};
};
let AdditionalDetailsFormConnect = reduxForm({
form: 'AdditionalDetails',
destroyOnUnmount: false
})(AdditionalDetailsForm);
export default connect(
mapStateToProps,
mapDispatchToProps
)(AdditionalDetailsFormConnect);
And this is how the dispatched action is used:
onSubmit() {
this.props.submitClaimsForm(this.props.formattedForm);
}
Next this is what the actual action looks like:
import {postClaimsForm} from '../shared/services/api';
export const Actions = {
SET_SUBMISSION_STATUS: 'SET_SUBMISSION_STATUS'
};
export const submitClaimsForm = form => dispatch => {
return postClaimsForm(form)
.then(res => {
// console.log('promise returned:', res);
return dispatch({
type: Actions.SET_SUBMISSION_STATUS,
submissionSuccess: true
});
})
.catch(error => {
// console.log('error returned:', error);
return dispatch({
type: Actions.SET_SUBMISSION_STATUS,
submissionSuccess: false
});
});
};
What I've tried so far:
it('mapDispatchToProps works as expected', () => {
const actionProps = mapDispatchToProps({
submitClaimsForm: jest.fn()
});
actionProps.submitClaimsForm();
expect(submitClaimsForm).toHaveBeenCalled();
});
But this errors and tells me that dispatch is undefined.
I also have this test, which passes, it tells me that submitClaimsForm has been called, but it just covers the lines for onSubmit:
it('onSubmit is called on submit', function() {
const spyOnSubmit = jest.spyOn(wrapper.instance(), 'onSubmit');
const mockHandleSubmit = jest.fn(wrapper.instance().onSubmit);
const submitClaimsForm = jest.fn(wrapper.instance().submitClaimsForm);
wrapper.setProps({
handleSubmit: mockHandleSubmit,
submitClaimsForm
});
wrapper.find('MyForm').simulate('submit');
expect(mockHandleSubmit).toHaveBeenCalled();
expect(spyOnSubmit).toHaveBeenCalled();
expect(submitClaimsForm).toHaveBeenCalled(); // <--
});
The reason your mapDispatchToProps works as expected test fails is because mapDispatchToProps expects a dispatch function to be passed in, not the map itself (that's what mapDispatchToProps returns).
This should work:
jest.mock('./actions');
import * as actions from './actions';
it('mapDispatchToProps calls the appropriate action', async () => {
// mock the 'dispatch' object
const dispatch = jest.fn();
const actionProps = mapDispatchToProps(dispatch);
const formData = { ... };
actionProps.submitClaimsForm(formData);
// verify the appropriate action was called
expect(actions.submitClaimsForm).toHaveBeenCalled(formData);
});

return promise from thunk

I'm trying to use my first thunk in redux-thunk:
getting redux-thunk into my app which already uses redux-observable:
import thunk from 'redux-thunk'
export const store = createStore(
rootReducer,
vepo,
composeWithDevTools(applyMiddleware(createEpicMiddleware(rootEpic), thunk))
)
Using it like so:
Action creator:
export const updateShowProductIsVeganModal = (payload: boolean) => {
return function (dispatch) {
return new Promise((resolve, reject) => {
dispatch({
type: 'UPDATE_INSPECTION_SHOW_PRODUCT_IS_VEGAN_MODAL',
payload
})
resolve()
})
}
}
Then I have this component (It's much bigger, I've stripped it down for this question):
const veganPress = (props, refs) => {
props.updateShowProductIsVeganModal(true).then(() => {
console.log("plz work")
refs.toast.show('hello world!')
})
}
class ProductDetailsView extends Component<any, State> {
render = () => {
return (
<Button onPress={() => veganPress(this.props, this.refs)}>
<Toast ref="toast"/>
)}
}
const mapDispatchToProps = (dispatch: Dispatch<*>): any => ({
updateShowProductIsVeganModal: (show: boolean) => {
dispatch(updateShowProductIsVeganModal(show))
}
})
const view = connect(
mapStateToProps,
mapDispatchToProps
)(ProductDetailsView)
I get the error:
ExceptionsManager.js:63 Cannot read property 'then' of undefined
It is referring to the .then inside veganPress()
How can return a promise that can use .then in the way I am trying to do it?
updateShowProductIsVeganModal doesnt return promise. Change it to
const mapDispatchToProps = (dispatch: Dispatch<*>): any => ({
updateShowProductIsVeganModal: (show: boolean) => {
return dispatch(updateShowProductIsVeganModal(show))
}
})

How to pass async data to dispatch action so I can use it in action creator?

Redux is harrrrd... At least to me, it is!!! Can someone please explain to me how can I pass this fetched json[0] through mapDispatchToProps to my action creator? And am I doing it right? I am using redux-thunk, is this the correct way of using it?
state = {
articles: {
article: []
}
};
qrCodeOnReadHandler = ({ data }) => {
this.props.onQRRead();
console.log(this.props.art);
fetch(data)
.then(response => response.json())
.then(json => {
console.log(json),
// () => this.props.onQRRead(json[0]),
this.setState({
...this.state,
articles: {
...this.state.articles,
article: json[0]
}
});
});
};
connecting redux
const mapStateToProps = state => {
return {
art: state.articles.article
};
};
const mapDispatchToProps = dispatch => {
return {
onQRRead: () => dispatch(article())
};
};
action creators
export const fetchedArticle = res => {
return {
type: ARTICLE,
res: res
};
};
export const article = res => {
return dispatch => {
dispatch(fetchedArticle(res));
};
};
how can I pass this fetched json[0] through mapDispatchToProps to my
action creator
You have to make your onQRRead receive an argument like this:
const mapDispatchToProps = dispatch => {
return {
onQRRead: payload => dispatch(article(payload))
};
};
The name of the function parameter is arbitrary.
For now, you can use it like the way you just did:
this.props.onQRRead(json[0])

Redux-thunk - dispatch is not a function

I'm having trouble with redux-thunk. It's saying dispatch is not a function inside my action creator, I tried consoling the returned arguments and there is none.
Here goes the code:
Action
export function signUp(data) {
return dispatch => {
console.log(dispatch)
if (data.email === 'email#server.com') {
dispatch(signIn(data, () => {
if (data.type === '2') {
browserHistory.push('/settings/profile')
} else {
browserHistory.push('/')
}
}))
} else {
return {
type: ActionTypes.USER_SIGN_UP__ERROR
}
}
}
}`
mapActionsToProps
const mapActionsToProps = dispatch => ({
signUp (data) {
console.log(dispatch)
dispatch(userActions.signUp(data))
}
})
By the way, you can see I consoled the dispatch function inside the mapActionsToProps, and it is returning as it was supposed to:
function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
Dispatch is not a function, because it's not passed from action creator.
Besides, you should not dispatch any action inside your mapActionsToProps. You just need to bind them to be accessible by connected component.
Your mapActionsToProps
const mapActionsToProps = (dispatch) => {
return {
asyncAction: bindActionCreators(asyncAction, dispatch),
}
}
const Container = connect(mapStateToProps, mapActionsToProps)(Component);
Async action
export const asyncAction = (email) => {
return (dispatch, getState) => {
const state = getState();
dispatch(StartAsync());
return fetch(`${apiUrl}/endpoint?email=${email}`, {
method: 'GET'
})
.then(response => response.json())
.then((result) => dispatch(finishedAsync(result)),
(error) => dispatch(failedAsync(error)))
.catch(e => {
console.log('error:', e);
});
};
};
Then, in your connected component, you can dispatch this action from props.

Resources