I have form in react:
let isSubmitted = false
const {
register,
errors,
handleSubmit
} = useForm < FormInput > ()
const onSubmit = (data: FormInput) => {
axios
.post(endpoint, data, {
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
isSubmitted = true
})
.catch(err => {})
}
return (
<div>
<div>
<div>
<form className={classes.root} autoComplete="off">
<Grid style={formGrid} container>
<Grid item xs={6}>
<div style={formItem}>
<input style={inputStyle} placeholder="Name of Provider" name="provider" type="text" ref={register({ required: true })} />
<div style={erroStyle}>{errors.Provider && 'Provider is required'}</div>
</div>
<div style={formItem}>
<input placeholder="Name of Contact Person" name="contactPerson" ref={register({ required: true })} style={inputStyle} />
<div style={erroStyle}>{errors.ContactPerson && 'Contact person is required'}</div>
</div>
<div style={formItem}>
<input placeholder="Contact Email" name="email" ref={register({ required: true })} style={inputStyle} />
<div style={erroStyle}>{errors.Email && 'Contact email is required'}</div>
</div>
<input onClick={handleSubmit(onSubmit)} type="submit" style={submitStyle} />
</Grid>
<Grid item xs={6}>
<div style={formItem}>
<input placeholder="Address (optional)" required name="address" style={inputStyle} ref={register} />
</div>
</Grid>
{isSubmitted &&
<div>Thank you! Form submitted, we'll contact you shortly.</div>}
</Grid>
</form>
</div>
</div>
</div>
) }
on submit I want to show this div: {isSubmitted && <div>Thank you! Form submitted, we'll contact you shortly.</div>} however it doesn't appear. I'm new to react and I'm looking from angular perspective and if it was angular it would work :) what I am missing here?
React will only re-render your component if the state has changed, any update on a variable will not trigger a re-render.
Assuming you are using a function component, you have to use the useState hook to allow your component to re-render:
import React, { useState } from 'react';
// --- snip ---
const [isSubmitted, setIsSubmitted] = useState(false);
const {
register,
errors,
handleSubmit
} = useForm < FormInput > ()
const onSubmit = (data: FormInput) => {
axios
.post(endpoint, data, {
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
setIsSubmitted(true)
})
.catch(err => {})
}
Related
I'm new in react. The problem is this - when I enter data into the input, my focus is reset. I understand that it happens due to changeHandler. But I don't understand how to change it. I've seen similar problems, but they are all related to class components. I would like to implement the solution exactly in a functional component, not using classes.
import React, { useContext, useEffect, useState } from 'react'
import { AuthContext } from '../context/AuthContext'
import axios from 'axios';
import { render } from '#testing-library/react';
export const AuthPage = () => {
const auth = useContext(AuthContext)
const [typeOfForm, setTypeOfForm] = useState('login')
const [form, setForm] = useState({
email: '', password: ''
})
const loginHandler = async () => {
try {
var config = {
headers: { 'Access-Control-Allow-Origin': '*' }
};
axios.post('http://localhost:5000/api/login', { ...form }, { headers: { 'Authorization': `Bearer ${auth.token}` } })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const registerHandler = async () => {
try {
var config = {
headers: { 'Authorization': `Bearer ${auth.token}` }
};
axios.post('http://localhost:5000/api/register', { ...form })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value })
}
return (
<div className="App" key="editor2">
<div className="logreg-bg"></div>
<a href="/">
<h1 id="logreg-logo">Animal Assistance <br /> <span id="logreg-logo-down">save nature togehter</span></h1>
</a>
{typeOfForm == 'login' ? <LoginForm /> : <RegisterForm />}
<h1 id="logreg-logo2"> Created by: <br /> <span id="logreg-logo-down2">PTN</span></h1>
</div>
);
function LoginForm() {
return (
<div id="logreg-form-container">
<h1 id="form-header">Log in</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Email"
type="text"
id="login"
name="email"
value={form.email}
onChange={changeHandler}
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Password"
type="password"
id="password"
name="password"
value={form.password}
onChange={changeHandler}
required />
<div id="logreg-button-container">
<button
onClick={registerHandler}
id="logreg-form-button"
>Login</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={() => setTypeOfForm('register')}>Register</a>
</div>
</div>
)
}
function RegisterForm() {
return (
<div id="logreg-form-container">
<h1 id="form-header">Register</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Введите email"
value={form.email}
onChange={changeHandler}
type="text"
id="login"
name="email"
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Введите пароль"
value={form.password}
onChange={changeHandler}
type="password"
id="password"
name="password"
required />
<div id="logreg-button-container">
<button
type="submit"
id="logreg-form-button"
>Register</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={() => setTypeOfForm('login')}>Login</a>
</div>
</div>
)
}
}
export default AuthPage;
Problems:
Focus is being lost because currently, input changes the state of a higher level component. The automatically causes a re-rendering of its child (the login or sign up form), because it is being completely defined again.
This causes an automatic re-render since React and browser think it
got a COMPLETELY NEW component.
Solutions:
Move the form state, and changeHandler function, to each respective form component, and allow them to manage their state independently. That way, this won't happen.
Recommended Approach:
If you want to form and changleHandler in a higher level component, then define the child components (Login and Sign Up) separately from AuthPage. Then just pass them the form state, and changeHandler function, as props.
Below if the 2nd approach being implemented
Since you would define both components separately, ensure you pass all the variables and functions in AuthPage, that are needed in each form, as props/parameters too. This is for functional purposes, and because it is best practice for maintenance on react apps.
Let me know if it helps :)
import React, { useContext, useEffect, useState } from 'react'
import { AuthContext } from '../context/AuthContext'
import axios from 'axios';
import { render } from '#testing-library/react';
function LoginForm({form, changeFormType, changeHandler, registerHandler}) {
return (
<div id="logreg-form-container">
<h1 id="form-header">Log in</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Email"
type="text"
id="login"
name="email"
value={form.email}
onChange={changeHandler}
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Password"
type="password"
id="password"
name="password"
value={form.password}
onChange={changeHandler}
required />
<div id="logreg-button-container">
<button
onClick={registerHandler}
id="logreg-form-button"
>Login</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={changeFormType}>Register</a>
</div>
</div>
)
}
function RegisterForm({form, changeFormType, changeHandler}) {
return (
<div id="logreg-form-container">
<h1 id="form-header">Register</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Введите email"
value={form.email}
onChange={changeHandler}
type="text"
id="login"
name="email"
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Введите пароль"
value={form.password}
onChange={changeHandler}
type="password"
id="password"
name="password"
required />
<div id="logreg-button-container">
<button
type="submit"
id="logreg-form-button"
>Register</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={changeFormType}>Login</a>
</div>
</div>
)
}
const AuthPage = () => {
const auth = useContext(AuthContext)
const [typeOfForm, setTypeOfForm] = useState('login')
const [form, setForm] = useState({
email: '', password: ''
})
const loginHandler = async () => {
try {
var config = {
headers: { 'Access-Control-Allow-Origin': '*' }
};
axios.post('http://localhost:5000/api/login', { ...form }, { headers: { 'Authorization': `Bearer ${auth.token}` } })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const registerHandler = async () => {
try {
var config = {
headers: { 'Authorization': `Bearer ${auth.token}` }
};
axios.post('http://localhost:5000/api/register', { ...form })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value })
}
const changeFormType = event =>{
//add your condition based of e.target
setTypeOfForm('login')
//add your condition based of e.target
setTypeOfForm('register')
}
return (
<div className="App" key="editor2">
<div className="logreg-bg"></div>
<a href="/">
<h1 id="logreg-logo">Animal Assistance <br /> <span id="logreg-logo-down">save nature togehter</span></h1>
</a>
{typeOfForm == 'login' ? <LoginForm
changeHandler={changeHandler}
form={form}
changeFormType={changeFormType}
registerHandler={registerHandler}/>
: <RegisterForm
changeHandler={changeHandler}
form={form}
changeFormType={changeFormType}
/>}
<h1 id="logreg-logo2"> Created by: <br /> <span id="logreg-logo-down2">PTN</span></h1>
</div>
);
}
export default AuthPage;
In my register form my radio buttons don't work, when I press the create button nothing happens, it doesn't activate the onSubmit function, but if I remove them it gets activated.
Here is my code:
import React from "react";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
const male = props => (
<input type="radio" value="male" name="gender" {...props} />
);
const female = props => (
<input type="radio" value="female" name="gender" {...props} />
);
export class RegisterPage extends React.Component {
render() {
let { initialValues } = this.state;
return (
<div>
<div>
<h1>Sign Up</h1>
<Formik
initialValues={initialValues}
onSubmit={(
{ email, password, gender },
{ setStatus, setSubmitting }
) => {
setStatus();
authenticationservice.newuser({ email, password, gender }).then(
user => {
const { from } = this.props.location.state || { from: { pathname: "/" } `};`
this.props.history.push(from);
},
error => {
setSubmitting(false);
setStatus(error);
}
);
}}
render={({ errors, status, touched, isSubmitting }) => (
<Form>
<div>
<label htmlFor="email">Email Address</label>
<Field name="email" type="text" />
<ErrorMessage name="email" component="div" />
</div>
<div>
<label htmlFor="gender">Gender</label>
<label>Male</label>
<Field name="gender" as={male} />
<label>Female</label>
<Field name="gender" as={female} />
</div>
<div>
<button type="submit" disabled={isSubmitting}>
Create
</button>
{isSubmitting && <img alt="" src="data:image" />}
</div>
{status && <div>{status}</div>}
</Form>
)}
/>
</div>
</div>
);
}
}
I'm not sure what happens because I don't get any error codes, there is just not happening anything
I'm working on an app that uses strapi as the backenbd and react as the front
I'm using react hooks to build a login form. However my form submit does not call the submit handler
import React, { useState } from "react";
const Login = () => {
const [state, setState] = React.useState({ identifier: '', password: '' });
const handleChange = ({ target: { name, value } }) =>
setState(prevState => ({ ...prevState, [name]: value }));
const handleSubmit = async() => {
console.log('handleSubmit')
try {
const response = await fetch('./auth/local', { method: 'POST', body: state})
console.log(response)
} catch(err) {
console.log(err)
}
}
return (
<div>
<label htmlForm="identifier">identifier</label>
<input
id="identifier"
name="identifier"
onChange={handleChange}
value={state.identifier}
/>
<label htmlForm="password">password</label>
<input
id="password"
name="password"
onChange={handleChange}
value={state.password}
/>
<button onClick={() => handleSubmit}></button>
</div>
);
};
export default Login;
the handleSubmit function is never called.
You'd need to trigger the submit.
You can add a button to trigger a submit as shown below.
<div>
<form onSubmit={handleSubmit}>
<label htmlForm="identifier">identifier</label>
<input
id="identifier"
name="identifier"
onChange={handleChange}
value={state.identifier}
/>
<label htmlForm="password">password</label>
<input
id="password"
name="password"
onChange={handleChange}
value={state.password}
/>
👇
<button type="submit">Submit</button>
</form>
</div>
You can try it out out this Sandbox.
<div>
<label htmlForm="identifier">identifier</label>
<input
id="identifier"
name="identifier"
onChange={handleChange}
value={state.identifier}
/>
<label htmlForm="password">password</label>
<input
id="password"
name="password"
onChange={handleChange}
value={state.password}
/>
<button onClick={handleSubmit}></button>
</div>
Getting this error when render the app.
SignIn(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
SignIn.js
import React, { useState, useRef } from "react";
import axios from "axios";
import swal from "sweetalert";
import "./SignUp.css";
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: "", password: "" });
const usernameFieldRef = useRef();
const passwordFieldRef = useRef();
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value });
};
const handleSubmit = event => {
event.preventDefault();
console.log('login');
const username = usernameFieldRef.current.value;
const password = passwordFieldRef.current.value;
axios
.post("https://foodiefun-api.herokuapp.com/api/auth/login", {
username,
password
})
.then(res => {
console.log("DATA", res.data)
localStorage.setItem('token', res.data.token)
swal(
"Welcome to Foodie Fun!",
"You are now signed in, enjoy your stay!",
"success"
);
})
.catch(err => {
console.log('LOGIN FAILED', err.response); // There was an error creating the data and logs to console
});
return (
<div class="page-content">
<div class="form-v6-content">
<div class="form-left">
<img className="form-image" style={{ linearGradient: "red, blue", opacity: ".6" }} src={image} alt="form" />
</div>
<form
onSubmit={handleSubmit}
class="form-detail"
method="post">
<h2>Register Form</h2>
<div class="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
class="input-text"
placeholder="Enter Desired User Name"
required />
</div>
<div class="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
class="input-text"
placeholder="Password"
required />
</div>
<div class="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
class="input-text"
placeholder="Comfirm Password"
required />
</div>
<div class="form-row-last">
<input type="submit"
name="register"
class="register"
value="Register" />
</div>
</form>
</div>
</div>
)
}
}
export default SignIn
App.js
import React, { useState } from "react";
import "./App.css";
import Form from "./Components/SignIn";
import ReviewForm from "./Components/ReviewForm/ReviewForm";
import UserInfo from "./Components/userInfo";
import mockarray from "./Components/mockarray";
import Navbar from "./Components/Navbar";
import RecipeApp from "./recipes/RecipeApp";
import SignUp from "./Components/SignUp";
import SignIn from "./Components/SignIn";
const App = () => {
const [reviews, setReviews] = useState([]);
const addReview = restaurant => {
setReviews([...reviews, { ...restaurant, id: Date.now() }]);
};
return (
<div className="App">
<Navbar />
<SignUp />
<SignIn />
{/* <RecipeApp /> */}
{/* <ReviewForm /> */}
{/* <ReviewForm addReview={addReview} /> */}
{console.log(reviews)}
{/* <UserInfo data = {mockarray} /> */}
</div>
);
};
export default App;
Two forms should be rendering on the screen but when I comment in the SignIn page I get this error. A couple of people have looked at it and they both say everything is right. I'm stumped!
Your return statement is inside the handleSubmit function.
You need to return your state outside handleSubmit function :
import React, { useState, useRef } from "react";
import axios from "axios";
import swal from "sweetalert";
import "./SignUp.css";
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: "", password: "" });
const usernameFieldRef = useRef();
const passwordFieldRef = useRef();
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value });
};
const handleSubmit = event => {
event.preventDefault();
console.log('login');
const username = usernameFieldRef.current.value;
const password = passwordFieldRef.current.value;
axios
.post("https://foodiefun-api.herokuapp.com/api/auth/login", {
username,
password
})
.then(res => {
console.log("DATA", res.data)
localStorage.setItem('token', res.data.token)
swal(
"Welcome to Foodie Fun!",
"You are now signed in, enjoy your stay!",
"success"
);
})
.catch(err => {
console.log('LOGIN FAILED', err.response); // There was an error creating the data and logs to console
});
}
return (
<div class="page-content">
<div class="form-v6-content">
<div class="form-left">
<img className="form-image" style={{ linearGradient: "red, blue", opacity: ".6" }} src={image} alt="form" />
</div>
<form
onSubmit={handleSubmit}
class="form-detail"
method="post">
<h2>Register Form</h2>
<div class="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
class="input-text"
placeholder="Enter Desired User Name"
required />
</div>
<div class="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
class="input-text"
placeholder="Password"
required />
</div>
<div class="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
class="input-text"
placeholder="Comfirm Password"
required />
</div>
<div class="form-row-last">
<input type="submit"
name="register"
class="register"
value="Register" />
</div>
</form>
</div>
</div>
)
}
export default SignIn
Working code : https://codesandbox.io/s/divine-field-kkfd6
Not sure if it's a typo on the code of your question or in your acctual code but the return is inside handleSubmit.
import React, { useState, useRef } from 'react'
import axios from 'axios'
import swal from 'sweetalert'
import './SignUp.css'
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: '', password: '' })
const usernameFieldRef = useRef()
const passwordFieldRef = useRef()
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value })
}
const handleSubmit = event => {
event.preventDefault()
console.log('login')
const username = usernameFieldRef.current.value
const password = passwordFieldRef.current.value
axios
.post('https://foodiefun-api.herokuapp.com/api/auth/login', {
username,
password
})
.then(res => {
console.log('DATA', res.data)
localStorage.setItem('token', res.data.token)
swal(
'Welcome to Foodie Fun!',
'You are now signed in, enjoy your stay!',
'success'
)
})
.catch(err => {
console.log('LOGIN FAILED', err.response) // There was an error creating the data and logs to console
})
}
return (
<div className="page-content">
<div className="form-v6-content">
<div className="form-left">
<img
className="form-image"
style={{ linearGradient: 'red, blue', opacity: '.6' }}
src={image}
alt="form"
/>
</div>
<form onSubmit={handleSubmit} className="form-detail" method="post">
<h2>Register Form</h2>
<div className="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
className="input-text"
placeholder="Enter Desired User Name"
required
/>
</div>
<div className="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
className="input-text"
placeholder="Password"
required
/>
</div>
<div className="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
className="input-text"
placeholder="Comfirm Password"
required
/>
</div>
<div className="form-row-last">
<input
type="submit"
name="register"
className="register"
value="Register"
/>
</div>
</form>
</div>
</div>
)
}
export default SignIn
I was trying to implement contactUS form in react using hooks.Contact us form is placed inside hooks.When I first submit the form the state in hooks are not updated ,when I click 2nd time states are set .and I am returning state to class component there api call are made.
//contactushook.js
import React, { useState } from 'react';
const ContactUshook = ({ parentCallBack }) => {
const [data, setData] = useState([]);
const handleSubmit = (event) => {
event.preventDefault();
setData({ name: document.getElementById('name').value, email: document.getElementById('email').value, message: document.getElementById('message').value });
console.log(data);
parentCallBack(data);
}
return <React.Fragment>
<div className="form-holder">
<form onSubmit={handleSubmit}>
<div>
<input id="name" type="text" placeholder="enter the name"></input>
</div>
<div>
<input id="email" type="email" placeholder="enter the email"></input>
</div>
<div>
<textarea id="message" placeholder="Type message here"></textarea>
</div>
<button type="submit" >Submit</button>
</form>
</div>
</React.Fragment >
}
export default ContactUshook;
//contactus.js
import React, { Component } from 'react';
import ContactUshook from './hooks/contactushook';
import '../contactUs/contactus.css';
class ContactComponent extends Component {
onSubmit = (data) => {
console.log('in onsubmit');
console.log(data);
}
render() {
return (
<div>
<h4>hook</h4>
<ContactUshook parentCallBack={this.onSubmit}></ContactUshook>
</div>
);
}
}
export default ContactComponent;
Stop using document queries and start using state instead!
Your ContactUshook component should look like this:
const ContactUshook = ({ parentCallBack }) => {
const [data, setData] = useState({ name: '', email: '', message: '' });
const handleSubmit = () => {
event.preventDefault();
parentCallBack(data);
}
const handleChange = (event, field) => {
const newData = { ...data };
newData[field] = event.target.value;
setData(newData);
}
return (
<div className="form-holder">
<form onSubmit={handleSubmit}>
<div>
<input
id="name"
type="text"
value={data.name}
placeholder="enter the name"
onChange={(e) => handleChange(e,'name')} />
</div>
<div>
<input
id="email"
type="email"
value={data.email}
placeholder="enter the email"
onChange={(e) => handleChange(e,'email')} />
</div>
<div>
<textarea
id="message"
value={data.message}
placeholder="Type message here"
onChange={(e) => handleChange(e,'message')} />
</div>
<button type="submit" >Submit</button>
</form>
</div>
);
}