I have been trying to implement a login page functionality in react using Ant Desing forms.
I keep getting the following error
I tried checking all the semicolons to see if this is due to a missing semicolon but was unable to find the root cause.
TypeError: e.preventDefault is not a function
at onSubmit (LoginForm.js:27)
at onFinish (LoginForm.js:44)
at onFinish (Form.js:73)
at useForm.js:811
Here is my code for the login page.
import React, {useState} from 'react';
import {Link, Redirect} from 'react-router-dom';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import styles from './NormalLoginForm.css';
import { Form, Input, Button, Checkbox, Layout, Card } from 'antd';
import { UserOutlined, LockOutlined } from '#ant-design/icons';
import {login} from '../auth/actions/auth';
const NormalLoginForm = ({ login, isAuthenticated }) => {
const [formData, setFormData] = useState({
username: '',
password:''
});
const { username, password} = formData;
const onChange = e => setFormData({...formData, [e.target.name]: e.target.value});
const onFinish = (values) => {
console.log('Received values of form onFinish: ', values);
// login(username,password)
};
const onSubmit = e => {
e.preventDefault();
console.log('Received values of form(onSumbit):' );
login(username,password);
};
if (isAuthenticated)
return <Redirect to='/' />;
return (
<Form
name="normal_login"
className="login-form"
initialValues={{
remember: true,
}}
onFinish={e=> onSubmit(e)}
style={{ maxWidth: 300, align: 'center'}}
>
<Form.Item
name="username"
rules={[
{
required: true,
message: 'Please input your Username!',
},
]}
>
<Input prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Username"
onChange={e=> onChange(e)}
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{
required: true,
message: 'Please input your Password!',
},
]}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
onChange={e => onChange(e)}
/>
</Form.Item>
<Form.Item>
<Form.Item name="remember" valuePropName="checked" noStyle>
<Checkbox>Remember me</Checkbox>
</Form.Item>
<a className="login-form-forgot" href="">
Forgot password
</a>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
{/*Or register now!*/}
</Form.Item>
</Form>
);
};
NormalLoginForm.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
};
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
connect(mapStateToProps, { login })(NormalLoginForm);
function LoginForm () {
return (
<NormalLoginForm/>
)
}
export default LoginForm;
Where am I making the mistake? this is my first project in React, been stuck here for weeks. Kindly help.
If you want to call preventDefault when the form gets submitted, use an onSubmit handler instead. onFinish's parameter is not the event, but the values.
onSubmit={e => e.preventDefault()}
onFinish={onFinish}
const onFinish = (values) => { // you can remove this parameter if you don't use it
login(username, password);
};
Related
i'm quite new with react and i'm building a form with react-hook and useState to manage my datas after the submit.
I'm not able to use textfield as they are blocked. I think that i make some errors into value/onChange parameters but i don't know what type of error.
import React, { useState } from "react";
import {
TextField,
MenuItem,
Typography,
Checkbox,
Divider,
Button,
} from "#mui/material";
import { MdError } from "react-icons/md";
import { BsArrowRight } from "react-icons/bs";
import "../style/contactform.scss";
import { useForm } from "react-hook-form";
const initialState = {
name: "",
email: "",
};
const ContactForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const [state, setState] = useState(initialState);
const { name, email } = state;
const handleInputChange = (e) => {
const { name, value } = e.target;
setState({ ...state, [name]: value });
};
const onSubmit = (e) => {
e.preventDefault();
console.log("form submit");
setState(initialState);
};
return (
<form className="contact-form" onSubmit={handleSubmit(onSubmit)}>
<Typography variant="h4" className="form-title">
Be the first.
</Typography>
<div className="form-component">
<TextField
id="standard-basic"
label="Nome*"
variant="standard"
name="nome"
value={name}
onChange={handleInputChange}
{...register("nome", {
required: true,
})}
/>
{errors?.nome?.type === "required" && (
<MdError className="form-validation-icon" />
)}
</div>
<Divider className="form-hr" />
<div className="form-component">
<TextField
id="standard-basic"
label="Email*"
variant="standard"
name="email"
value={email}
onChange={handleInputChange}
{...register("email", {
required: true,
pattern: {
value:
/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
},
})}
/>
{errors?.email?.type === "required" && (
<MdError className="form-validation-icon" />
)}
{errors?.email?.type === "pattern" && (
<Typography variant="p" className="form-validation-email">
Inserisci un indirizzo email valido.
</Typography>
)}
</div>
<Divider className="form-hr" />
<Button className="form-submit" type="submit" variant="contained">
<BsArrowRight />
</Button>
</form>
);
};
export default ContactForm;
Textfields are completely block but initial state is actually working, do i miss something?
Can you help me?
To assign initial values using the useForm hook, you pass it under the defaultValues parameter passed to the hook like so:
const {
register,
handleSubmit,
reset
formState: { errors },
} = useForm({
defaultValues: initialState
});
Then just pass the ...register name and email to the inputs. There is no need to assign values to them again:
<TextField
id="standard-basic"
label="Name*"
variant="standard"
name="name"
{...register("name", {
required: true,
})}
/>
// for the email..
<TextField
id="standard-basic"
label="Email*"
variant="standard"
name="email"
{...register("email", {
required: true,
pattern: {
value: /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,},
})}
/>
If you'll notice, the values are off the text fields already and there's also no need for the handleInputChange function. The useForm hook takes care of that.
Edit:
In addition to the onSubmit function, the handleSubmit from useForm passes a data object into the function like this:
const onSubmit = (data) => {
console.log("form submitted", data);
reset(); // this can be destructured of the `useForm` hook.
};
For more info check their documentation
I am trying to get the state from redux store and trying to fill the input field from state. If user in edit mode. In edit mode, we normally show the prefilled value in input field. But what is wrong with the below approach?
I am able to store single user successfully in reducer but in component i am not getting. Sometimes i get the value. Overall, it's very inconsistent.
import React, { useState, useEffect } from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
import { useSelector, useDispatch } from "react-redux";
import { useHistory, useParams } from "react-router-dom";
import { addUser, getSingleUser, updateUser } from "../redux/actions";
const useStyles = makeStyles((theme) => ({
root: {
marginTop: 100,
"& > *": {
margin: theme.spacing(1),
width: "45ch",
},
},
}));
const initialState = {
name: "",
address: "",
contact: "",
email: "",
};
const EditUser = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.users);
console.log("user", user);
const [state, setState] = useState(user);
const [error, setError] = useState("");
const { name, address, email, contact } = state;
const classes = useStyles();
const history = useHistory();
let dispatch = useDispatch();
const onInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
const handlSubmit = (e) => {
e.preventDefault();
console.log("name", name);
if (!name || !email || !address || !contact) {
setError("Please fill all Input Field");
} else {
dispatch(updateUser(state, id));
setError("");
history.push("/");
}
};
return (
<>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
type="submit"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit user</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form
className={classes.root}
noValidate
autoComplete="off"
onSubmit={handlSubmit}
>
<TextField
id="standard-basic"
label="Name"
value={name}
name="name"
onChange={onInputChange}
type="text"
/>
<br />
<TextField
id="standard-basic"
value={email}
name="email"
label="Email"
type="email"
onChange={onInputChange}
/>
<br />
<TextField
id="standard-basic"
value={contact}
name="contact"
label="Contact"
type="number"
onChange={onInputChange}
/>
<br />
<TextField
id="standard-basic"
label="Address"
value={address}
name="address"
type="text "
onChange={onInputChange}
/>
<br />
<Button
style={{ width: "100px" }}
variant="contained"
type="submit"
color="primary"
>
Update
</Button>
</form>
</>
);
};
export default EditUser;
Below is redux actions logic to get the single user and dispatching an action to store single user value in reducer.
export const getSingleUser = (id) => {
return function (dispatch) {
axios
.get(`${process.env.REACT_APP_API}/${id}`)
.then((resp) => {
console.log("resp", resp);
dispatch(singleUser(resp.data));
})
.catch((error) => console.log(error));
};
};
I have successfully written a Login component in React using plain Javascript. I would now like to convert this component to TypeScript. I have defined some types and also threw in some "any" just to initially compile. Unfortunately, the onClick parameter in my submit button throws the following error:
TS2322: Type '(e?: FormEvent | undefined) => void' is not assignable to type '(event: MouseEvent<HTMLElement, MouseEvent>)
=> void'.
Here is the relevant code:
class Login extends React.Component<LoginProps, LoginState> {
constructor(props) {
super(props);
this.login = this.login.bind(this);
}
async login(values) {
const user = {
email: values.email,
password: values.password,
};
const query = `mutation userLogin(
$user: UserLoginInputs!
) {
userLogin(
user: $user
) {
token
}
}`;
const data: any = await graphQLFetch(query, { user });
if (data && data.userLogin.token) {
const decoded: any = jwt.decode(data.userLogin.token);
const { onUserChange } = this.props;
onUserChange({ loggedIn: true, givenName: decoded.givenName });
const { history } = this.props;
history.push('/');
}
}
render() {
return (
<Formik
onSubmit={this.login}
validationSchema={loginSchema}
initialValues={{
email: '',
password: '',
}}
>
{({
handleSubmit,
handleChange,
values,
}) => (
<Card>
<Card.Body>
<Form>
<Form.Group>
<Form.Label>E-mail</Form.Label>
<Form.Control
name="email"
value={values.email}
onChange={handleChange}
/>
</Form.Group>
<Form.Group>
<Form.Label>Password</Form.Label>
<Form.Control
name="password"
value={values.password}
onChange={handleChange}
/>
</Form.Group>
</Form>
<Button
type="button"
variant="primary"
onClick={handleSubmit}
>
Submit
</Button>
</Card.Body>
</Card>
)}
</Formik>
);
}
}
I'm new to TypeScript and don't fully understand why an error occurs regarding e versus event when the login function does not explicitly reference either of those. Can someone please help me assign types to my handleSubmit function (aka login)?
I hope that example could help you to resolve your issue
import { Field, Form, Formik } from 'formik';
import * as React from 'react';
import './style.css';
interface MyFormValues {
firstName: string;
}
export default function App() {
const initialValues: MyFormValues = { firstName: '' };
const getSubmitHandler =
() =>
(values, formik) => {
console.log({ values, formik });
alert(JSON.stringify(values, null, 2));
formik.setSubmitting(false);
};
return (
<div>
<Formik
initialValues={initialValues}
onSubmit={getSubmitHandler()}
>
{(formik) => (
<Form>
<label htmlFor="firstName">First Name</label>
<Field id="firstName" name="firstName" placeholder="First Name" />
<button
type="button"
onClick={(event) =>
getSubmitHandler()(formik.values, formik)
}
>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
}
I can't find a solution on how to re-render app.js function.
It's loaded first time, but when I click login or logout button I need to call a function from the helper again to check user status.
App.js
import Routes from "./Routes";
import NavBar from "./common/navBar";
import { isAuthenticated } from "./helpers/checkAuthentication";
function App() {
useEffect(() => {
{
console.log("useEffect", isAuthenticated());
}
});
return (
<>
{console.log("INININ", isAuthenticated())}
<div
className={
isAuthenticated()
? "loggedIn internalDashboard"
: "loggedOut internalDashboard"
}>
{isAuthenticated() ? (
<div className='menu'>
<NavBar />
</div>
) : null}
<div className='mainContent'>
<Routes />
</div>
</div>
</>
);
}
export default App;
Login.jsx
import { Form, Input, Button } from "antd";
import { useHistory } from "react-router";
const Login = () => {
const history = useHistory();
const [, forceRender] = useReducer((s) => s + 1, 0);
const onFinish = (values) => {
console.log("Success:", values);
const userInfo = {
email: values.email
};
localStorage.setItem("user", JSON.stringify(userInfo));
history.push("/");
};
useEffect(() => {
let user = localStorage.getItem("user");
console.log("IN");
if (user) {
localStorage.removeItem("user");
history.push("/");
}
});
return (
<Form
name='basic'
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}>
<Form.Item
label='Username'
name='email'
rules={[{ required: true, message: "Please input your email!" }]}>
<Input />
</Form.Item>
<Form.Item
label='Password'
name='password'
rules={[{ required: true, message: "Please input your password!" }]}>
<Input.Password />
</Form.Item>
<Form.Item>
<Button type='primary' htmlType='submit'>
Submit
</Button>
</Form.Item>
</Form>
);
};
export default Login;
In console.log:
INININ true
navBar.jsx:66 dsadsadsddasadsa true
App.js:11 useEffect true
This part will be loaded only first time on pageload, after that I need to reload page to see new status
On lick login button localstorage will receive new data, but app.js will not check authentication and show <NavBar />. And if I click logout user will be removed from localstorage but I can see <NavBar />, and I need to refresh page and everything works fine
I guess you can use Context API to save and update your global state without connecting any state management library such as redux, mobx and so on. Thanks to this API you will be able always to know whether a user is authenticated or not.
So, I have found a very interesting article that must help you to resolve your issue. Let's me attach the link: https://www.sitepoint.com/replace-redux-react-hooks-context-api/
I'm working with a React.js frontend, and when I try to login or signup I get the below error when clicking the login or Sign up buttons.
Uncaught TypeError: _this.props.onSubmit is not a function
The stacktrace is pointing to the following file,
/src/containers/Login/index.js
// #flow
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Link } from 'react-router-dom';
import { css, StyleSheet } from 'aphrodite';
import Input from '../../components/Input';
const styles = StyleSheet.create({
card: {
maxWidth: '500px',
padding: '3rem 4rem',
margin: '2rem auto',
},
});
type Props = {
onSubmit: () => void,
handleSubmit: () => void,
submitting: boolean,
}
class LoginForm extends Component {
props: Props
handleSubmit = (data) => this.props.onSubmit(data);
// handleSubmit: (data) => this.props.onSubmit(data);
render() {
const { handleSubmit, submitting } = this.props;
return (
<form
className={`card ${css(styles.card)}`}
onSubmit={handleSubmit(this.handleSubmit)}
>
<h3 style={{ marginBottom: '2rem', textAlign: 'center' }}>Login to Sling</h3>
<Field name="email" type="text" component={Input} placeholder="Email" />
<Field name="password" type="password" component={Input} placeholder="Password" />
<button
type="submit"
disabled={submitting}
className="btn btn-block btn-primary"
>
{submitting ? 'Logging in...' : 'Login'}
</button>
<hr style={{ margin: '2rem 0' }} />
<Link to="/signup" className="btn btn-block btn-secondary">
Create a new account
</Link>
</form>
);
}
}
const validate = (values) => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
}
if (!values.password) {
errors.password = 'Required';
}
return errors;
};
export default reduxForm({
form: 'login',
validate,
})(LoginForm);
specifically the below line,
handleSubmit = (data) => this.props.onSubmit(data);
Again, any and all help is greatly appreciated.
Finally, the entire project can be found here.
handleSubmit is a prop "injected" into the Component by redux-form, onSubmit is not... you either have to make sure you're supplying it yourself or just handle the form submit within LoginForm#handleSubmit
You can also do it this way: https://github.com/erikras/redux-form/issues/1163
references:
http://redux-form.com/6.0.0-alpha.4/docs/faq/HandleVsOn.md/
In your App/index.js, you did
<RedirectAuthenticated path="/login" component={Login} {...authProps} />
You can see you did not pass a onSubmit function to the Login component
You can fix it by making these changes to App/index.js
// add this function
const LoginComponent = () => {
return (
<Login onSubmit={() => { console.log("hi") }} />
)
}
class App extends Component {
...
render() {
....
<RedirectAuthenticated path="/login" component={LoginComponent} {...authProps} />
In this case, you will see 'hi' printed to the dev console.