action function is not being executed - reactjs

I have an action to login user using axios post request. but the action function is not being called on clicking login button in my functional component.
here is the action function
import {
SET_USER,
SET_ERRORS,
CLEAR_ERRORS,
LOADING_UI,
SET_AUTHENTICATED,
SET_UNAUTHENTICATED
} from "../types";
import axios from "axios";
export const loginUser = (userData) => (dispatch) => {
dispatch({ type: LOADING_UI });
axios
.post("/api/auth/login", userData)
.then((res) => {
const FBIdToken = `Bearer ${res.data.token}`;
localStorage.setItem("FBIdToken", FBIdToken);
axios.defaults.headers.common["Authorization"] = FBIdToken;
dispatch(getUserData());
dispatch({ type: CLEAR_ERRORS });
window.location = "/";
})
.catch((err) => {
dispatch({
type: SET_ERRORS,
payload: err.response.data
});
});
};
export const getUserData = () => (dispatch) => {
axios
.get("/api/user")
.then((res) => {
dispatch({
type: SET_USER,
payload: res.data
});
})
.catch((err) => console.log(err));
};
and here is my functional component.
i have logged statements before and after the function call, both are being printed but the function is not being executed
import React, { useState } from "react";
import PropTypes from "prop-types";
import AppIcon from "../images/icon.png";
import axios from "axios";
import { Link } from "react-router-dom";
//MUI imports
import withStyles from "#material-ui/core/styles/withStyles";
import Grid from "#material-ui/core/Grid";
import Typography from "#material-ui/core/Typography";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import CircularProgress from "#material-ui/core/CircularProgress";
//Redux
import { connect } from "react-redux";
import { loginUser } from "../Redux/actions/userActions";
const styles = {
form: {
textAlign: "center"
},
image: {
margin: "20px auto 20px auto"
},
pageTitle: {
margin: "10px auto"
},
textField: {
margin: "10px auto"
},
button: {
marginTop: 20,
position: "relative"
},
customError: {
color: "red"
},
progress: {
position: "absolute"
}
};
function Login({ classes, UI: { loading } }) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [errors, setErrors] = useState({});
const handleSubmit = (e) => {
e.preventDefault();
const userData = {
email: email,
password: password
};
console.log("before");
loginUser(userData);
console.log("after");
};
return (
<Grid container className={classes.form}>
<Grid item sm />
<Grid item sm>
<img src={AppIcon} alt="app logo" className={classes.image} />
<Typography variant="h2" className={classes.pageTitle}>
Login
</Typography>
<form noValidate onSubmit={handleSubmit}>
<TextField
id="email"
name="Email"
type="email"
label="Email"
className={classes.textField}
helperText={errors.email}
error={errors.email ? true : false}
value={email}
onChange={(e) => setEmail(e.target.value)}
fullWidth
/>
<TextField
id="password"
name="password"
type="password"
label="Password"
className={classes.textField}
helperText={errors.password}
error={errors.password ? true : false}
value={password}
onChange={(e) => setPassword(e.target.value)}
fullWidth
/>
{errors.error && (
<Typography variant="body2" className={classes.customError}>
Wrong credentials, please try again.
</Typography>
)}
<Button
type="submit"
variant="contained"
color="primary"
className={classes.button}
disabled={loading}
>
Login
{loading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
<br />
<small>
don't have an account? Signup <Link to="/signup">here</Link>
</small>
</form>
</Grid>
<Grid item sm />
</Grid>
);
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
loginUser: PropTypes.func.isRequired,
user: PropTypes.object.isRequired,
UI: PropTypes.object.isRequired
};
const mapStateToProps = (state) => ({
user: state.user,
UI: state.UI
});
const mapActionsToProps = {
loginUser
};
export default connect(
mapStateToProps,
mapActionsToProps
)(withStyles(styles)(Login));

You should execute the loginUser passed via props, not the one you import at the top of the file, better give it a different name to avoid confusion.
e.g.
function Login({ classes, UI: { loading }, loginUser }) {

Related

Formik: POST url/salary-scales 400 (Bad Request)

I have this project and it is a project to run a contracting company, and I am trying to create an interface in order to allow the admin to create a salary scale, and this is what the requestlooks like on Swagger:
And as it turns out, I have array of Objects.
And for that, I used a formik and sent the data to the backend
But I got this error:
POST https://ite-ria.herokuapp.com/api/v1/salary-scales 400 (Bad Request)
In addition, the data is not filled with data
This is what the network looks like in the browser:
How can i solve the problem?
file1.js:
import React, { useState } from "react";
import TextField from "#material-ui/core/TextField";
import Grid from "#material-ui/core/Grid";
import { makeStyles } from "#material-ui/core/styles";
import Button from "#material-ui/core/Button";
// import { addInvoice } from "../../../store/invoiceSlice";
import { motion } from "framer-motion";
import { useDispatch } from "react-redux";
import "react-datepicker/dist/react-datepicker.css";
import Slide from "#material-ui/core/Slide";
import { useSnackbar } from "notistack";
import { getJobs, addSalaryScale } from "../../store/salaryScaleSlice";
import { useEffect } from "react";
import InputAdornment from "#material-ui/core/InputAdornment";
import WorkOutlineOutlinedIcon from "#material-ui/icons/WorkOutlineOutlined";
import Input from "#material-ui/core/Input";
import AccountTreeOutlinedIcon from "#material-ui/icons/AccountTreeOutlined";
import { FieldArray, Field, Form, Formik } from "formik";
import { Card, CardContent } from "#material-ui/core";
import Autocomplete from "#material-ui/lab/Autocomplete";
import PostAddIcon from "#material-ui/icons/PostAdd";
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
},
},
input: {
display: "none",
},
button: {
margin: theme.spacing(1),
// padding: theme.spacing(4),
},
}));
function ShippingTab(props) {
const dispatch = useDispatch();
const classes = useStyles();
// const [amount, setAmount] = useState("");
const [jobs, setJobs] = useState([]);
// const [jobId, setJobId] = useState(0);
// const [employeeLevel, setEmployeeLevel] = useState("");
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const handleCreateInvoiceMessageClick = () => {
enqueueSnackbar(
"Invoice created successfully",
{ variant: "success" },
{
anchorOrigin: {
vertical: "top",
horizontal: "right",
},
},
{ TransitionComponent: Slide }
);
};
const handleAmountChange = (event) => {
setAmount(event.target.value);
};
useEffect(() => {
getJobs().then((response) => {
console.log("jobs response in approve: ", response);
// setJobs(response);
});
}, []);
return (
<Card>
<CardContent>
<Formik
initialValues={{
entities: [{ jobId: 0, amount: 0, employeeLevel: " " }],
}}
onSubmit={async (values) => {
console.log("values: ", values);
return dispatch(addSalaryScale(values));
}}
>
{({ values, isSubmitting }) => (
<Form autoComplete="off">
<Grid container>
<Grid item>
<FieldArray name="entities">
{({ push, remove, Formik }) => (
<React.Fragment>
{values?.entities.map((_, index) => (
<Grid container item key={index}>
<Grid item>
<Field
name={`entities[${index}].jobId`}
id="entities.jobId"
component={TextField}
label="JobId"
/>
</Grid>
<Grid item>
<Field
name={`entities[${index}].amount`}
id="entities.amount"
component={TextField}
type="number"
label="amount"
/>
</Grid>
<Grid item>
<Field
name={`entities[${index}].employeeLevel`}
id="entities.employeeLevel"
component={TextField}
label="employeeLevel"
/>
</Grid>
<Grid item>
<Button onClick={() => remove(index)}>
Delete
</Button>
</Grid>
</Grid>
))}
<Grid item>
<Button
onClick={() =>
push({ jobId: 0, amount: 0, employeeLevel: "" })
}
>
Add
</Button>
</Grid>
</React.Fragment>
)}
</FieldArray>
</Grid>
</Grid>
<pre>{JSON.stringify({ values }, null, 4)}</pre>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</CardContent>
</Card>
);
}
export default ShippingTab;
salaryScaleSlice.js:
export const addSalaryScale = createAsyncThunk(
"salaryScalesApp/salaryScale/addSalaryScale",
async (salaryScale, { dispatch, getState }) => {
console.log('salary Scale: ', salaryScale)
const response = await axios.post("/salary-scales", salaryScale);
const data = await response.data.data;
console.log("Hi I am Here in add new Job: ", data);
dispatch(getSalaryScales());
return data;
}
);
400 means you have an error in your Request (i.e. wrong url-param, missing body, etc.). -> https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
Since the Response shows you that 'entities' is an invalid field my guess is that some of the fields (like 'jobId') are required for the API-server to work probably. But without further knowledge or a link to the swagger documentation this is just a guess.
Best approach would be to contact the admin of the contracting company and ask him to send you a correctly formatted and working request so that you have some test-data.
...hope this was any helpful

Redux React, how to set state, from form, inside a function

I am learning Redux. I cannot figure out how to set state.
I need to set state (I'm assuming with useDispatch) by using a login form. On the component Fake1, I am able to console.log the "user" passed with useSelector. If i hardcode a change in state on user.js ({ i.e., username: "beanbag", password: "122345" }), the change in state appears on Fake1, telling me that the mechanics of my setup are good, and that the problem is that state is not being set inside loginOnSubmit().
My code:
const initialStateValue = { username: "", password: "" };
export const userSlice = createSlice({
name: "user",
initialState: { value: initialStateValue },
reducers: {
login: (state, action) => {
state.value = action.payload;
},
logout: (state) => {
state.value = initialStateValue;
},
},
});
export const { login, logout } = userSlice.actions;
export default userSlice.reducer;
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import Visibility from "#mui/icons-material/Visibility";
import VisibilityOff from "#mui/icons-material/VisibilityOff";
import InputAdornment from "#mui/material/InputAdornment";
import IconButton from "#mui/material/IconButton";
import Input from "#mui/material/Input";
import Button from "#mui/material/Button";
import LoginIcon from "#mui/icons-material/Login";
import AddCircleOutlineIcon from "#mui/icons-material/AddCircleOutline";
import Stack from "#mui/material/Stack";
import "./LoginForm.css";
import { useDispatch } from "react-redux";
import { login } from "../features/user";
function LoginForm() {
const [user, setUser] = useState(null);
const [loginUsername, setLoginUsername] = useState("");
const [loginError, setLoginError] = useState([]);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [values, setValues] = useState({
password: "",
showPassword: false,
});
const dispatch = useDispatch();
const navigate = useNavigate();
const handleChange = (prop) => (event) => {
setValues({ ...values, [prop]: event.target.value });
};
const handleClickShowPassword = () => {
setValues({
...values,
showPassword: !values.showPassword,
});
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
// useEffect(() => {
// fetch("/authorize_user")
// .then((res) => res.json())
// .then(setUser);
// }, []);
const loginOnSubmit = (e) => {
e.preventDefault();
const newUser = {
username: loginUsername,
password: values.password,
};
// dispatch(login({username: loginUsername, password: values.password}))
fetch("/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newUser),
}).then((res) => {
if (res.ok) {
res.json().then((newUser) => {
setUser(newUser);
setIsAuthenticated(true);
setLoginUsername("");
dispatch(login({ newUser }));
navigate("/fake1");
});
} else {
res.json().then((json) => setLoginError(json.error));
}
});
};
const handleSignupRoute = () => {
navigate("/signup");
};
return (
<form onSubmit={loginOnSubmit}>
<div>
<br></br>
<Input
className="test1"
value={loginUsername}
onChange={(e) => setLoginUsername(e.target.value)}
type="text"
label="Username"
placeholder="Username"
/>
<br></br>
<br></br>
<Input
id="standard-adornment-password"
type={values.showPassword ? "text" : "password"}
value={values.password}
// onChange={(e) => setValues(e.target.value)}
onChange={handleChange("password")}
placeholder="Password"
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{values.showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
/>
<br></br>
<br></br>
<br></br>
<div className="test2">
<Stack direction="row" spacing={2}>
<Button
type="submit"
variant="outlined"
endIcon={<LoginIcon />}
className="btn-login"
>
Login
</Button>
<Button
onClick={handleSignupRoute}
variant="outlined"
endIcon={<AddCircleOutlineIcon />}
className="btn-signup"
>
Signup
</Button>
</Stack>
<br></br>
<br></br>
</div>
</div>
</form>
);
}
export default LoginForm;
import React from 'react'
import {useSelector} from 'react-redux'
const Fake1 = () => {
const user = useSelector(state => state.user.value)
console.log(user)
return (
<div>Fake1</div>
)
}
export default Fake1

how to do testing in react redux application using Jest enzyme?

Login.test.js:-
import { shallow, mount } from "enzyme";
import renderer from "react-test-renderer";
import Login from "../Login";
import { Provider } from "react-redux";
//import LoginReducer from "../../../redux/reducers/loginReducer";
import configureStore from "redux-mock-store";
const mockStore = configureStore([]);
describe("Login Component", () => {
let store;
let jsx;
beforeEach(() => {
store = mockStore({ login: { email: "", password: "" } });
jsx = (
<Provider store={store}>
<Login />
</Provider>
);
});
it("should render an email input tag", () => {
const wrapper = shallow(jsx);
expect(wrapper.find("Field[type='email']").exists()).toBe(true);
});
it("should render a password input tag", () => {
const wrapper = shallow(jsx);
expect(wrapper.find('Field[type="password"]').exists()).toBe(true);
});
it("should render a submit button", () => {
const wrapper = shallow(jsx);
expect(wrapper.find('button[type="submit"]').exists()).toBe(true);
});
});
Appstore:-
/** combine reducers*/
let rootReducer = combineReducers({
register: RegisterReducer,
login: LoginReducer
Login.js:-
import { React, useState, useEffect, useContext } from "react";
import { useHistory } from "react-router";
import "./common_style.css";
import { connect } from "react-redux";
import * as actionCreator from "../../redux/actions/userActionCreater";
import "../common/common_style.css";
import {
Grid,
Paper,
Avatar,
TextField,
Button,
Typography,
Link,
} from "#material-ui/core";
import LockOutlinedIcon from "#material-ui/icons/LockOutlined";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import InputAdornment from "#material-ui/core/InputAdornment";
import AccountCircle from "#material-ui/icons/AccountCircle";
import LockIcon from "#material-ui/icons/Lock";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
//import { propTypes } from "react-bootstrap/esm/Image";
import InitializeReduxState from "./InitializeReduxState";
const paperStyle = {
padding: 20,
height: "70vh",
width: 280,
margin: "60px auto",
marginTop: "110px",
};
const avatarStyle = { backgroundColor: "#1bbd7e" };
const btnstyle = { margin: "8px 0" };
const Login = (props) => {
const initialValues = {
email: "",
password: "",
};
const validationSchema = Yup.object().shape({
email: Yup.string().email("Please enter valid email").required("Required"),
password: Yup.string("Enter your password")
.required("Required")
.min(4, "Password should be of minimum 4 characters length"),
});
const onSubmit = (values) => {
const payload = { email: values.email, password: values.password };
props.login(payload);
};
let history = useHistory();
useEffect(() => {
if (props.isLoggedIn === true) {
props.flashNotification({
message: "Login Succeessful...",
type: "success",
});
if (props.role === "admin") {
history.push("/admin");
} else if (props.role === "patient") {
patientStatus();
} else {
history.push("/physician");
}
}
}, []);
const patientStatus = () => {
if (props.currentUser.isActive) {
history.push("/demographics");
} else {
history.push("/patientinactive");
}
};
return (
<>
<Grid>
<Paper elevation={10} style={paperStyle}>
<Grid align="center">
<Avatar style={avatarStyle}>
<LockOutlinedIcon />
</Avatar>
<br />
<h4>Sign In</h4>
</Grid>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{(props) => (
<Form>
<Field
as={TextField}
label="Email"
margin="normal"
type="text"
name="email"
// onChange={handleUserChange}
placeholder="Enter email"
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<AccountCircle />
</InputAdornment>
),
}}
variant="standard"
helperText={<ErrorMessage name="email" />}
/>
<Field
as={TextField}
label="password"
placeholder="Enter password"
type="password"
name="password"
// onChange={handleUserChange}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<LockIcon />
</InputAdornment>
),
}}
helperText={<ErrorMessage name="password" />}
/>
<Button
type="submit"
color="primary"
variant="contained"
style={btnstyle}
fullWidth
>
Sign in
</Button>
</Form>
)}
</Formik>
<Typography> Do you have an account ?</Typography>
Sign Up
<p className="text text-danger fw-bold text-center">
{props.globalmessage}!!!
</p>
</Paper>
</Grid>
<InitializeReduxState />
</>
);
};
const mapStatetoProps = (state) => {
return {
isLoggedIn: state.login.isLoggedIn,
role: state.login.role,
globalmessage: state.login.globalmessage,
authToken: state.login.authToken,
currentUser: state.login.loggedUserInfo,
};
};
const mapDispatchToProps = (dispatch) => {
return {
login: (user) => dispatch(actionCreator.Login(user)),
};
};
let hof = connect(mapStatetoProps, mapDispatchToProps);
export default hof(Login);
Here I have tested my Login component with some simple test cases and I have also mock my store because my application is using Redux but it is giving me error like
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
I have a doubt that in beforeeach I have used the email and password. Is it correct? Is there is something that I have done wrong?

How to avoid redirecting user to homepage when there is an error while submitting the form using Redux Action in React?

I wanted to avoid redirecting user to homepage when there is an error while submitting the form during dispatching with redux action. Whenever we have error I am throwing one error message but not able to stop navigating towards the homepage. I am getting everything from store to stop redirecting user to homepage but it's not working. Can you please tell me what is going wrong with below code ?
import React, { useState, useEffect } from "react";
import { makeStyles } from "#material-ui/core/styles";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import {
addContactStart,
} from "../redux/contacts/contacts.actions";
import { MDBInput, MDBBtn, MDBTypography, MDBIcon } from "mdb-react-ui-kit";
import { toast } from "react-toastify";
const useStyles = makeStyles((theme) => ({
root: {
margin: "auto",
padding: "30px",
maxWidth: "500px",
alignContent: "center",
"& > *": {
margin: theme.spacing(1),
width: "45ch",
},
},
}));
const initialState = {
name: "",
mobile: "",
email: "",
};
const AddContact = () => {
const classes = useStyles();
const { contact, contacts, loading, error } = useSelector(
(state) => state.data
);
const { token } = useSelector((state) => state.auth);
const [state, setState] = useState(initialState);
const [emptyErrorMsg, setEmptyErrorMsg] = useState("");
let history = useHistory();
let dispatch = useDispatch();
const { name, email, mobile } = state;
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
useEffect(() => error && toast.error(error), [error]);
const handleSubmit = (e) => {
e.preventDefault();
if (!name || !email || !mobile) {
setEmptyErrorMsg("Please fill all input Field");
} else {
dispatch(addContactStart({ state, token }));
if (!error) {
history.push("/");
setEmptyErrorMsg("");
}
}
};
return (
<div>
{emptyErrorMsg && (
<MDBTypography style={{ color: "red" }}>{emptyErrorMsg}</MDBTypography>
)}
<form
className={classes.root}
noValidate
autoComplete="off"
onSubmit={handleSubmit}
>
<MDBInput
label="Name"
value={name || ""}
name="name"
type="text"
onChange={handleInputChange}
/>
<br />
<MDBInput
label="Email"
name="email"
value={email || ""}
type="email"
onChange={handleInputChange}
/>
<br />
<MDBInput
label="Contact"
value={mobile || ""}
name="mobile"
type="number"
onChange={handleInputChange}
/>
<br />
<MDBBtn
style={{ width: "100px" }}
type="submit"
onChange={handleInputChange}
>
Submit
</MDBBtn>
</form>
</div>
);
};
export default AddContact;

Dispatch redux not executed

I'm trying to submit a form when a user signUp. When the submit button clicked an action creator should executed to start an asynchronous action but actually the submit is not triggered and the action creator is not launched.
actions.ts:
import { ActionTypes } from "./types";
import { SignUpUser, User } from "../apis/authentication";
import { AxiosError } from "axios";
import { Dispatch } from "redux";
export interface ReturnedUser {
username: string;
}
export interface SignUpSuccessAction {
type: ActionTypes.SucceedSignUp;
payload: ReturnedUser;
}
export interface SignUpFailAction {
type: ActionTypes.FailSignUp;
payload: string;
}
export interface SignUpStartAction {
type: ActionTypes.StartSignUp;
}
const signUpStarted = (): SignUpStartAction => ({
type: ActionTypes.StartSignUp
});
const signUpSucceeded = (user: ReturnedUser): SignUpSuccessAction => ({
type: ActionTypes.SucceedSignUp,
payload: user
});
const signUpFailed = (error: string): SignUpFailAction => ({
type: ActionTypes.FailSignUp,
payload: error
});
export const signUpFetch = (user: User) => {
return async (dispatch: Dispatch) => {
dispatch(signUpStarted());
SignUpUser(user).then(
(response: any) => {
const { username } = response;
return dispatch(signUpSucceeded(username));
},
(error: AxiosError) => {
let errorMessage = "Internal Server Error";
if (error.response) {
errorMessage = error.response.data;
}
return dispatch(signUpFailed(errorMessage));
}
);
};
};
reducers/reducer.ts:
import { Action, ActionTypes } from "../actions";
export const SignUpReducer = (state = {}, action: Action) => {
switch (action.type) {
case ActionTypes.SucceedSignUp:
return { ...state, user: action.payload };
case ActionTypes.FailSignUp:
return { ...state, error: action.payload };
default:
return state;
}
};
reducers/index.ts:
import { SignUpReducer } from "./signUp";
import { combineReducers } from "redux";
export const reducer = combineReducers({
signUp: SignUpReducer
});
index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import SignUp from "./containers/Signup/SignUp";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import { reducer } from "./reducers/index";
const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
const App = () => <SignUp />;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
SignUp.tsx:
import React, { useState } from "react";
import Button from "#material-ui/core/Button";
import { connect } from "react-redux";
import { Form, Field } from "react-final-form";
import { makeStyles, Theme, createStyles } from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import CardWrapper from "../../components/CardWrapper";
import PasswordField from "../../components/Password";
import TextField from "../../components/TextField";
import { validate, submit } from "./validation";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
container: {
padding: 16,
margin: "auto",
maxWidth: "100%",
flexGrow: 1
},
paper: {
padding: 16
},
item: {
marginTop: 16
}
})
);
const SignUp = () => {
const classes = useStyles();
const [showPassword, setPassword] = useState(false);
const handleClickShowPassword = () => {
setPassword(!showPassword);
};
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
return (
<div className={classes.container}>
<Form
onSubmit={submit}
validate={validate}
render={({ handleSubmit, form, submitting, pristine }) => (
<form onSubmit={handleSubmit}>
<CardWrapper title='SignUp Form'>
<Grid container justify='center' spacing={3}>
<Grid item md={12}>
<Field fullWidth required name='username'>
{props => (
<TextField
label='Username'
type='text'
value={props.input.value}
onChange={props.input.onChange}
onBlur={props.input.onBlur}
meta={props.meta}
fullWidth={true}
/>
)}
</Field>
</Grid>
<Grid item md={12}>
<Field fullWidth required name='email'>
{props => (
<TextField
label='Email'
type='email'
value={props.input.value}
onChange={props.input.onChange}
onBlur={props.input.onBlur}
meta={props.meta}
fullWidth={true}
/>
)}
</Field>
</Grid>
<Grid item md={12}>
<Field fullWidth required name='password'>
{props => (
<PasswordField
value={props.input.value}
handleChange={props.input.onChange}
showPassword={showPassword}
handleClickShowPassword={handleClickShowPassword}
handleMouseDownPassword={handleMouseDownPassword}
fullWidth={true}
onBlur={props.input.onBlur}
meta={props.meta}
/>
)}
</Field>
</Grid>
<Grid item className={classes.item}>
<Button
type='button'
variant='contained'
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</Button>
</Grid>
<Grid item className={classes.item}>
<Button
variant='contained'
color='primary'
type='submit'
disabled={submitting || pristine}
>
Submit
</Button>
</Grid>
</Grid>
</CardWrapper>
</form>
)}
/>
</div>
);
};
export default connect()(SignUp);
validation.ts:
interface SignUpValues {
email: string;
password: string;
username: string;
}
const submit = (values: SignUpValues) => {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return signUpFetch(user);
};
export { submit };
I find a similar question posted about the same issue described by Redux Dispatch Not Working in Action Creator but the answer does not fix my problem. Does I make something wrong when linking the different component with redux?
It wont dispatch because in component You didnt dispatch Your function
return signUpFetch(user)
Instead Connect the component with Redux and dispatch the function
in Index.tsx
import { connect } from 'react-redux';
const mapDispatchToProps = {
submit
};
export default connect(null, mapDispatchToProps)(SignUp);
And access it with
this.props.submit
Add dispatch in Submit function
const submit = (values: SignUpValues) =>(dispatch, getState)=> {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return dispatch(signUpFetch(user));
};
Whenever you need to update redux state, dispatch the function from where it is also called and also in the actions.
You need to connection the component to the store when you do the dispatch:
import { connect } from 'react-redux';
const submit = (values: SignUpValues) => {
const user = {
username: values.username,
email: values.email,
password: values.password
};
return this.props.signUpFetch(user);
};
export const connectedSubmit = connect(null, {signUpFetch})(submit);
import { validate, connectedSubmit as submit } from "./validation";
And also you can just return at SignUpUser
export const signUpFetch = (user: User) => {
return async (dispatch: Dispatch) => {
dispatch(signUpStarted());
return SignUpUser(user).then(
(response: any) => {
const { username } = response;
dispatch(signUpSucceeded(username));
},
(error: AxiosError) => {
let errorMessage = "Internal Server Error";
if (error.response) {
errorMessage = error.response.data;
}
dispatch(signUpFailed(errorMessage));
}
);
};
}

Resources