I'm trying to make a little login screen with functional React. I have an input button that I want to click and have the login post happen. For the life of me, I can't get the handler to fire. loginPressed just won't get called. I'm sure it's something easy that I'm overlooking.
import * as React from 'react';
import axios from 'axios'
export default function Login() {
const [email, setEmail] = React.useState([]);
const [password, setPassword] = React.useState([]);
const loginPressed = () => {
var body = {
'email': email,
'password': password
}
axios.post('login', body)
.then(response => {
})
}
return (
<div>
<p>Username:</p>
<p><input type="text" name="email" onChange={(e) => {setEmail(e.target.value)}}/></p>
<p>Password:</p>
<p><input type="password" name="password" onChange={(e) => {setPassword(e.target.value)}}/></p>
<p>
<input type='button' value='Login' onClick={loginPressed}/>
</p>
</div>
);
}
You should use form with onSubmit={loginPressed}. Instead of input use button html element with type of submit.
Related
I am quite new to React JS and was trying to make an app. However whenever typing something in a textbook, the whole app seems to freeze and then stop working.
import React, { useState } from 'react'
import { auth } from './firebase';
import styles from '../static/SignIn.module.css';
import { Link, useNavigate } from "react-router-dom";
import {
// createUserWithEmailAndPassword,
signInWithEmailAndPassword,
onAuthStateChanged,
// signOut,
} from "firebase/auth";
export default function SignIn(){
const [user, setUser] = useState({});
const history = useNavigate();
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
// const goBack = () => {
// history.push('/')
// };
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const signIn = async() => {
try {
const user = await signInWithEmailAndPassword(
auth,
email,
password
);
history.push('/home')
console.log(user);
} catch (error) {
console.log(error)
if (password.length < 6){
alert('Password should be at least 6 characters!')
}
}
}
return(
<div className={styles.main}>
<div className={styles.center}>
<h1>Login</h1>
<div className={styles.form}>
<div className={styles.txt_field}>
<input type="text" id='text' name='text' value={email} onChange={e => setEmail(e.currentTarget.value)} required/>
<span></span>
<label>Email ID</label>
</div>
<div className={styles.txt_field}>
<input type="password" id='password' name='password' value={password} onChange={e => setPassword(e.currentTarget.value)} required/>
<span></span>
<label>Password</label>
</div>
<input type="submit" value="Login" onClick={signIn}/>
<div className={styles.signup_link}>
Not a member? <Link to="/signup">Signup</Link>
</div>
</div>
</div>
</div>
)
}
Any help would be appreciated because this is stopping me from progressing further, as I need to rerun the app using npm start in order to make it work.
I think your issue is that on every render of the SignIn component you call the onAuthStateChanged listener. I have never used this but my guess is that it would need to be called only once, when the component mounts.
So you could do something like this instead:
export default function SignIn(){
const [user, setUser] = useState({});
const history = useNavigate();
React.useEffect(() => {
onAuthStateChanged(auth, (currentUser) => setUser(currentUser))
// Notice the empty dependency array, there to make sure the effect is only run once when the component mounts
}, [])
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// ...
}
I think everything is fine as I have tried running your code without the firebase functions and just removing the styles, just rendering the input button and it works fine and the events occur perfectly for setting email and password field. But I think you should make little amendments to your code. Please first check user object whether if it contains any data or not before pushing home route.
I am trying to create a simple React form that, on button click, will display the entered input value in a controlled input element. Specifically, I do NOT want to have an identical solution to that in the React docs (constantly updating the displayed value on input change), rather I only want it to update the displayed paragraph text after the user has hit the submit button. I am able to do this with this current solution (conditionally rendering based on submitted state that is set in handler functions):
import { useState } from 'react';
export default function App() {
const [text, setText] = useState('');
const [submitted, setSubmitted] = useState(false);
const handleSubmit = e => {
e.preventDefault();
setSubmitted(true);
};
const handleChange = e => {
setSubmitted(false);
setText(e.target.value);
};
return (
<>
<form onSubmit={e => handleSubmit(e)}>
<label>Text: </label>
<input type="text" value={text} onChange={e => handleChange(e)} />
<button type="submit" onClick={handleSubmit}>
Show
</button>
{submitted && <p>{text}</p>}
</form>
</>
);
}
But I am guessing that there is a much better way to do this.
If you want to be able to submit multiple times and keep the last before submitting again, use this:
import { useState } from 'react';
export default function App() {
const [text, setText] = useState('');
const [displayText, setDisplayText] = useState('');
const handleSubmit = e => {
e.preventDefault();
setDisplayText(text);
};
const handleChange = e => {
setText(e.target.value);
};
return (
<>
<form onSubmit={e => handleSubmit(e)}>
<label>Text: </label>
<input type="text" value={text} onChange={e => handleChange(e)} />
<button type="submit" onClick={handleSubmit}>
Show
</button>
{displayText && <p>{displayText}</p>}
</form>
</>
);
}
displayText && ... is so that the paragraph tag doesn't exist until it has a value to display, but you can just replace that section with out that and it will work.
I am learning reactjs form with hooks, now I would like to test form on submit using jest and enzyme.
here is my login component.
import React from 'react'
function Login() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
// ....api calLS
}
return (
<div>
<form onSubmit={handleSubmit} className="login">
<input type="email" id="email-input" name="email" value={email} onChange={e => setEmail(e.target.value)} />
<input type="password" id="password-input" name="password" value={password} onChange={e =>setPassword(e.target.value)} />
<input type="submit" value="Submit" />
</form>
</div>
)
}
export default Login
Here is the login.test.js file
describe('my sweet test', () => {
it('clicks it', () => {
const wrapper = shallow(<Login />);
const updatedEmailInput = simulateChangeOnInput(wrapper, 'input#email-input', 'blah#gmail.com')
const updatedPasswordInput = simulateChangeOnInput(wrapper, 'input#password-input', 'death');
expect(updatedEmailInput.props().value).toEqual('blah#gmail.com');
expect(updatedPasswordInput.props().value).toEqual('death');
const instance = wrapper.instance()
const spy = jest.spyOn(instance, 'handleSubmit')
instance.forceUpdate();
const submitBtn = app.find('#sign-in')
submitBtn.simulate('click')
expect(spy).toHaveBeenCalled()
})
})
Unfortunately when I run npm test I get the following error.
What do I need to do to solve this error or can someone provide a tutorial on how to test a form submit?
In the documentation it's said that you cant use shallow.instance() for functional components
It will return null: https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/instance.html
There was also a previous answer on this topik
Enzyme instance() returns null
You can pass validated function handleSubmit to Login as a prop like there How to use jest.spyOn with React function component using Typescript
// Unit test
describe('SomeComponent' () => {
it('validates model on button click', () => {
const handleSubmit = jest.fn();
const wrapper = mount(
<Login handleSubmit={handleSubmit}/>
);
const instance = wrapper.instance();
const submitBtn = app.find('#sign-in')
submitBtn.simulate('click')
expect(handleSubmit).toHaveBeenCalled();
});
}
You need to call this test function handleSubmit in your login component either as a part of onSubmit or export whole onSubmit from upper components. Example login code with importing part of login function
import React from 'react'
function Login( {handleSubmit}) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onSubmit = async (e) => {
if (handleSubmit) {
handleSubmit()
}
e.preventDefault();
// ....api calLS
}
return (
<div>
<form onSubmit={onSubmit} className="login">
<input type="email" id="email-input" name="email" value={email} onChange={e => setEmail(e.target.value)} />
<input type="password" id="password-input" name="password" value={password} onChange={e =>setPassword(e.target.value)} />
<input type="submit" value="Submit" />
</form>
</div>
)
}
export default Login
Example login code with importing of submit function
import React from 'react'
function Login( {handleSubmit}) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// handleSubmit is imported with props
return (
<div>
<form onSubmit={handleSubmit} className="login">
<input type="email" id="email-input" name="email" value={email} onChange={e => setEmail(e.target.value)} />
<input type="password" id="password-input" name="password" value={password} onChange={e =>setPassword(e.target.value)} />
<input type="submit" value="Submit" />
</form>
</div>
)
}
export default Login
I want to add email validation to the input field and based on that disable the add button if the email entered by user is wrong.
below you can see my code,
function Parent() {
const [email, setEmail] = useState('');
const onEmailChange = (event: any) => {
setEmail(event.target.value);
};
const isDisabled = email.length === 0;
return (
<Input
type="email"
value={email}
onChange={onEmailChange}
placeholder="Insert user email"
/>
<button disabled={isdisabled}>Add</button> //add button to be disabled when user input email is wrong
);
}
I want to make sure i have basic email validation for the input and be able to enter only numbers, ''.
Could someone help me with this? Thanks in advance.
EDIT:
image for the error unnecessary escape character
There are multiple ways of doing this but I would advise keeping a track of the disabled state of the button in its own state which is initialized to true.
Now change the disabled state inside a useEffect which runs every time the email is changed and set it to true or false based on your validation.
import React from "react";
// Modify this function as per your needs
const validateEmail = email => typeof email === "string" && email.includes("#");
export default function App() {
const [email, setEmail] = React.useState("");
const [isDisabled, setIsDisabled] = React.useState(true);
const onEmailChange = event => {
setEmail(event.target.value);
};
React.useEffect(() => {
setIsDisabled(!validateEmail(email));
}, [email]);
return (
<>
<input
type="text"
value={email}
onChange={onEmailChange}
placeholder="Insert user email"
/>
<button disabled={isDisabled}>Add</button>
</>
);
}
Here is the working prototype in codesandbox
You can use regex in order to check if the input value is an email by using the onChange() property.
import React from "react";
const regex = /^(([^<>()[\].,;:\s#"]+(\.[^<>()[\].,;:\s#"]+)*)|(".+"))#(([^<>()[\].,;:\s#"]+\.)+[^<>()[\].,;:\s#"]{2,})$/i;
export default function App() {
const [isDisabled, setDisibility] = React.useState(true);
const checkEmail = e => {
setDisibility(!regex.test(e.target.value));
}
return (
<div>
<input onChange={checkEmail} placeholder="email address" />
<button disabled={isDisabled}>add</button>
</div>
);
}
https://codesandbox.io/s/dry-sun-votmt?fontsize=14&hidenavigation=1&theme=dark
this is my first time using hooks I don't know How can I clear input fields after submit, form.reset() doesn't work
import { useForm } from "react-hook-form";
import....
export default function AddUser() {
const URL = "http://localhost:3000/AddUser";
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => {
if (data) {
axios.post(URL, data);
}
form.reset()
};
here is the return part
return (
<form onSubmit={handleSubmit(onSubmit)} noValidate>
<div className="container">
<input type="text" name="name" placeholder="Name" ref={register({required: true})}/>
<input type="radio" name="gender" value="male" ref={register({ required: true })}/>:Male
<input type="radio" name="gender" value="female" ref={register({ required: true })}/:Female
<button type="submit" className="btn "> add</button>
</div>
</form>
);
}
thanks in advance
//////////
You need to import reset from useForm() hook to be able to use it outside of your tags.
so
const { register, handleSubmit, errors, reset } = useForm();
then on your submit function
const onSubmit = (data) => {
if (data) {
axios.post(URL, data);
}
reset({})
};
Something along those lines should work.
You need to set a default state to set when your click is handle, that way your component will reset on every submit. And yet, and if you wanna prevent default you must set event.preventDefault(); inside the onSubmit function
import { useForm, useState } from "react-hook-form";
import....
export default function AddUser() {
const [formState, setFormState] = useState({})
const URL = "http://localhost:3000/AddUser";
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => {
if (data) {
setFormState(data)
axios.post(URL, formState);
}
form.reset()[![enter image description here][1]][1]
};