I am building a application with Redux, React-Redux, and React. When I am doing connect with component and making action call, I receive an error:
Uncaught (in promise) TypeError: sendLoginRequest is not a function
My Code:
component/
import React, { useState } from "react";
import { connect } from 'react-redux';
import { sendLogin } from './Login.Action';
import { Google, Microsoft } from "@mui/icons-material";
import { NavLink, useNavigate } from "react-router-dom";
import * as constant from "../../constant/commonString";
const Login = ({
userName,
isError,
loginSuccess,
loginErrorMessage,
triggerLogin
})=> {
const navigate = useNavigate();
const { sendRequest, loading } = useHttpClient();
const [email, setLoginEmail] = useState("");
const [password, setLoginPassword] = useState("");
const handleEmail = (e) => {
setLoginEmail(e.target.value);
};
const handlePassword = (e) => {
setLoginPassword(e.target.value);
};
const handleLogin = (e) => {
e.preventDefault();
try {
const log = triggerLogin({ email, password });
} catch {
console.log('errr');
}
};
return (
<div className="container">
<div className="welcome">
<h1>{constant.WELCOME}</h1>
</div>
<form>
<input
value={email}
onChange={handleEmail}
type="email"
id="emailnote"
name="email"
required
placeholder="Email address"
/>
<input
value={password}
onChange={handlePassword}
type="password"
id="passwordnote"
name="password"
required
placeholder="Password"
/>
<Button
type="submit"
stylx="button_style button-text-design next-button"
text=" Continue"
onClick={handleLogin}
/>
</form>
<div className="details">
<p>
{constant.ACCOUNT_INFO}
<NavLink className="signup" to="/signup">
{constant.SIGNUP}
</NavLink>
</p>
</div>
<div className="login-options">
<button className="google">
<Google color="primary" />
{constant.GOOGLE}
</button>
<button className="microsoft">
<Microsoft color="primary" />
{constant.MICROSOFT}
</button>
</div>
<div className="terms">
<NavLink to="/terms">{constant.TERMS}</NavLink>
<span>|</span>
<NavLink to="/policy">{constant.POLICY}</NavLink>
</div>
</div>
);
};
const mapStateToProps = ({ login }) => ({ ...login });
export default connect(mapStateToProps, {
triggerLogin: sendLogin,
})(Login);
Login.Action.js
/* eslint-disable */
import { createActions, handleActions, combineActions } from 'redux-actions';
import { post, } from '../../utils/api';
import {
SEND_LOGIN_REQUEST,
SEND_LOGIN_SUCCESS,
SEND_LOGIN_FAILED,
SET_TOKEN_ID
} from './Login.Action.constant';
const sendLoginRequest = createActions(SEND_LOGIN_REQUEST);
const sendLoginSuccess = createActions(SEND_LOGIN_SUCCESS);
const sendLoginFailed = createActions(SEND_LOGIN_FAILED);
export const setToken = createActions(SET_TOKEN_ID);
const API_URL = {
LOGIN: 'users/login',
LOGOUT: 'user/web/logout'
};
export const sendLogin = (data) => async (dispatch) => {
// here i am getting data
dispatch(sendLoginRequest());
const { error, response } = await post(`${API_URL.LOGIN}`, data);
if (response) {
dispatch(sendLoginSuccess(response));
} else if (error) {
dispatch(sendLoginFailed(error));
}
};
Error
Login.Action.js:44 Uncaught (in promise) TypeError: sendLoginRequest is not a function
at Login.Action.js:44:1
at Object.dispatch (redux-thunk.mjs:5:1)
at dispatch (<anonymous>:6:7384)
at boundActionCreators.<computed> (bindActionCreators.ts:12:1)
at handleLogin (Login.js:37:1)
I am unable to find whats wrong is going here. I have tried React-Action creation many solution related to this, but unable to solve this problem.
2
Answers
Looking at the docs for
redux-actions
,createActions
takes an object and also returns an object, not a function. Did you mean to callcreateAction
instead?The basic issue is that you have used
createActions
(plural, with an "s") instead ofcreateAction
to create your individual actions. It appears that createActions handles this as an edge-case though, and returns an object of action creator functions.So (safely) assuming that
SEND_LOGIN_REQUEST
is a string value, i.e."SEND_LOGIN_REQUEST"
, the following lineproduces an object that contains the action creator functions instead of the action creator function directly.
versus
If you wanted to dispatch this
sendLoginRequest
action then it’d likely look likedispatch(sendLoginRequest.sendLoginRequest());
where you access thesendLoginRequest
of the returned action map object (also namedsendLoginRequest
).You should probably just use the
createAction
utility instead to keep it simple (and very likely what you meant to do from the start).Recommendation: Use Redux-Toolkit
You are maintaining/implementing a very outdated form of Redux. You should really integrate Redux-Toolkit which cuts out much of the Redux boilerplate code (e.g. declaring actions types, creating action/success/failure actions, etc…). If you are already familiar with Redux this is about a 5-10 minute upgrade to swap out the store creation.
Login.Action.js
could be re-written as the following:If
post
simply throws errors/rejections instead of resolving with anerror
property though the code becomes quite trivial:createAsyncThunk
generates three actions for you:sendLogin.pending
sendLoginRequest
sendLogin.fulfilled
sendLoginSuccess
sendLogin.rejected
sendLoginFailed
You can reference these new actions in any existing case reducers:
Additional Suggestion
Using the
connect
Higher Order Component is also considered a dated practice these days. Use theuseDispatch
anduseSelector
hooks to access thedispatch
function and subscribe to state updates.Example: