Warning: "unstable_flushDiscreteUpdates" on formik custom input - reactjs

I am trying to create a custom input, so I can use it in my formik form, and I get this warning.
For the custom input I used this example: https://formik.org/docs/api/useField
P.S before adding this custom input, there wasn't any error.
My code:
const Input = (props) => {
const [meta] = useField(props);
return (
<div className={classes.control}>
<label htmlFor={props.id || props.name}>{props.label}</label>
<Field name={props.name} {...props} />
{meta.touched && meta.error ? <div className="error">{meta.error}</div> : null}
</div>
);
};
export default Input;
const RegistrationForm = () => {
const { isLoading, t, submitHandlerRegister, registrationValues } = useAuth();
return (
<Formik
initialValues={registrationValues}
validationSchema={RegisterValidationSchema}
onSubmit={submitHandlerRegister}
enableReinitialize={true}
>
<Form>
<Input
label={t("Authentication.Email")}
name="email"
type="email"
placeholder={t("Authentication.Email")}
></Input>
<Input
label={t("Authentication.Password")}
name="password"
type="password"
placeholder={t("Authentication.Password")}
></Input>
<div className={classes.actions}>
<button type="submit" disabled={isLoading}>
{t("Authentication.CreateAccount")}
</button>
</div>
</Form>
</Formik>
);
};

Related

React keep focus on re-rendering input

I am building an e-commerce web app, and have run into a problem making an array of inputs. Inside DescHTML I am trying to handle onChange event, but on each update the focus on the element is lost, making it very annoying to type. Does anyone have any solution or different aproach to this whole problem? Thanks in advance.
import {useState} from 'react'
export default function UploadForm() {
const [name, setName] = useState('')
const [category, setCategory] = useState('')
const [film, setFilm] = useState('')
const [price, setPrice] = useState('')
const [descArr, setDescArr] = useState([''])
function DescHTML() {
return (
<div>
{ descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
} } /> )}
</div>
)
}
console.log(descArr)
return (
<div>
<form method="POST" action="http://localhost:3500/api/upload" encType='multipart/form-data'>
<input type="file" name="image" />
<input type="text" value={name} name="name" onChange={(e) => setName(e.target.value)} placeholder="Product name" />
<input type="text" value={category} name="category" onChange={(e) => setCategory(e.target.value)} placeholder="Category" />
<input type="text" value={film} name="film" onChange={(e) => setFilm(e.target.value)} placeholder="Film" />
<input type="text" value={price} name="price" onChange={(e) => setPrice(e.target.value)} placeholder="Price" />
<DescHTML />
<hr />
{/*<input type="submit" value="Submit" />*/}
</form>
<button onClick={() => setDescArr([...descArr, ''])}>+</button>
</div>
)
}
Move your descArr and button inside DescHTML check below code you can check more info here.
function DescHTML() {
const [descArr, setDescArr] = useState([""]);
return (
<div>
{descArr.map((item, i) => (
<input
key={i}
type="text"
placeholder="TEST"
value={item}
onChange={(e) => {
e.preventDefault();
const newArr = [...descArr];
newArr[i] = e.target.value;
setDescArr(newArr);
}}
/>
))}
<br />
<button onClick={() => setDescArr([...descArr, ""])}>+</button>
</div>
);
}
First of all - move DescHTML out of UploadForm:
function DescHTML({descArr, setDescArr}) {
return (
<div>
{descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
}}/>)}
</div>
)
}
and use it in <UploadForm> like this
<DescHTML descArr={descArr} setDescArr={setDescArr}/>
The other problem is the + button which steals the focus on click. Adding onMouseDown handler will fix this.
<button onMouseDown={(e) => e.preventDefault()} onClick={() => setDescArr([...descArr, ''])}>+</button>

Pass data from a form component to another component in react hook

I have the following form, and I need that when submitting the form, its information is displayed in a new component.
Perhaps the issue of redirecting to the other component could be done by creating a route. But I don't know how said component obtains the information of the form
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import {useState, useRef} from 'React'
export default const FormX = () => {
const [formValues, setFormValues] = useState({
name: "",
priceUnitary: "",
size: "",
description: "",
});
const inputFileRef = useRef();
const handleChange = (event) => {
const { name, value } = event.target;
console.log(name, value);
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formValues);
console.log(inputFileRef.current.files);
};
return (
<>
<form id="formu" onSubmit={handleSubmit} className="row">
<h1>FORM SEND</h1>
<div className="col-md-6">
<label>Name</label>
<input
placeholder="Text input"
name="name"
value={formValues.name}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Size</label>
<input
type="number"
placeholder="Text input"
name="size"
value={formValues.size}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Price Unitary</label>
<input
type="number"
placeholder="Text input"
name="priceUnitary"
value={formValues.priceUnitary}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Description</label>
<input
placeholder="Text input"
name="description"
value={formValues.description}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>File / Image</label>
<input type="file" ref={inputFileRef} />
</div>
<button type="submit" className="color-primary">
Save
</button>
</form>
</>
);
};
Link:
https://codesandbox.io/s/send-form-dcj5v?file=/src/App.js
You can hide your form by change your state on form sumbit and display another component. You have to pass formValue as props in View component. Now think you have better idea what you have to do...
Here i added new component, that display form value on submit
App.js
import { useState, useRef } from "react";
import View from "./View";
const FormX = () => {
const [formValues, setFormValues] = useState({
name: "",
priceUnitary: "",
size: "",
description: ""
});
const [isFormVisible, setIsFormVisible] = useState(true);
const inputFileRef = useRef();
const handleChange = (event) => {
const { name, value } = event.target;
console.log(name, value);
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(formValues);
console.log(inputFileRef?.current?.files);
setIsFormVisible(false);
};
return (
<>
{isFormVisible ? (
<form id="formu" onSubmit={handleSubmit} className="row">
<h1>FORM SEND</h1>
<div className="col-md-6">
<label>Name</label>
<input
placeholder="Text input"
name="name"
value={formValues?.name}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Size</label>
<input
type="number"
placeholder="Text input"
name="size"
value={formValues.size}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Price Unitary</label>
<input
type="number"
placeholder="Text input"
name="priceUnitary"
value={formValues.priceUnitary}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>Description</label>
<input
placeholder="Text input"
name="description"
value={formValues.description}
onChange={handleChange}
/>
</div>
<div className="col-md-6">
<label>File / Image</label>
<input type="file" ref={inputFileRef} />
</div>
<button type="submit" className="color-primary">
Save
</button>
</form>
) : (
<View data={formValues} />
)}
</>
);
};
export default FormX;
View.js
import React from "react";
const View = ({ data }) => {
return (
<div>
<p>Name: {data?.name}</p>
<p>priceUnitary: {data?.priceUnitary}</p>
<p>description: {data?.description}</p>
</div>
);
};
export default View;

Onchange in React input causes the input to rerender on every letter

So I've created inputs in two functions and on Onchange it gets the value that is being input into them. But anytime I type into the inputs I can only type a letter at a time before it is unfocused and I believe this is because the component keeps on rendering.
I've also realized that whenever I remove the Onchange and value props then everything goes back to normal and I'm able to type everything easily. How would I fix this?
App.js
import style from "./auth.module.css";
import { useEffect, useRef, useState } from "react";
import { useAuthState } from 'react-firebase-hooks/auth';
import { auth, signInWithEmailAndPassword, signInWithGoogle, registerWithEmailAndPassword } from "../../firebase";
import { CSSTransition } from "react-transition-group";
function Auth() {
const [activeMenu, setActiveMenu] = useState("main");
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [user, loading, error] = useAuthState(auth);
const Emailform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Email:</label>
<form className={style.input}>
<input
type="email"
name="email"
required="true"
value={email}
onChange={(e) => setEmail(e.target.value)} />
</form>
</div>
);
}
const Passform = () => {
return (
<div className={style.formBox}>
<label className={style.label}>Password:</label>
<form className={style.input}>
<input
type="password"
name="password"
required="true"
value={password}
onChange={(e) => setPassword(e.target.value)} />
</form>
</div>
);
}
let domNode = useClickOutside(() => {
setActiveMenu(false);
});
return (
<div className={style.container}>
<Login />
<Signup />
</div>
);
function AuthType(props) {
return (
<a
href={props.link}
className={style.menuItem}
onClick={() => props.goToMenu && setActiveMenu(props.goToMenu)}
>
{props.children}
</a>
);
}
/* Login */
function Login() {
return (
<CSSTransition in={activeMenu === "main"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.login}>
<h1 className={style.title}>Clip It</h1>
{/* Email and Password */}
<Emailform/>
<Passform/>
<div className={style.button}>
<input
type="submit"
value="Login"
onClick={() => signInWithEmailAndPassword(email, password)} />
<input
type="submit"
value="Login with Google"
onClick={signInWithGoogle} />
</div>
<div className={style.text}>
<p className={style.plink}>Forgot Password</p>
<div>
Need an account?
<AuthType goToMenu="Signup">click here</AuthType>
</div>
</div>
</div>
</div>
</CSSTransition>
);
}
function Signup() {
return (
<CSSTransition in={activeMenu === "Signup"} unmountOnExit timeout={500}>
<div ref={domNode}>
<div className={style.signUp}>
<div className={style.title}> Clip It</div>
<Form label="First Name" type="text" />
<Form label="Last Name" type="Text" />
<Form label="Email" type="email"/>
<Form label="Date of Birth" type="date" />
<Form label="Password" type="password"/>
<Form label="Confirm Password" type="password" />
<div className={style.button}>
<input type="submit" value="Sign Up" />
</div>
<div className={style.text}>
have an
<AuthType goToMenu="main"> account</AuthType>
</div>
</div>
</div>
</CSSTransition>
);
}
}
let useClickOutside = (handler) => {
let domNode = useRef();
useEffect(() => {
let clickListener = (event) => {
if (domNode.current && !domNode.current.contains(event.target)) {
handler();
}
};
document.addEventListener("mousedown", clickListener);
return () => {
document.removeEventListener("mousedown", clickListener);
};
});
return domNode;
};
function Form(props) {
return (
<div className={style.formBox}>
<label className={style.label}>{props.label}:</label>
<form className={style.input}>
<input
type={props.input}
name={props.input}
required="true" />
</form>
</div>
);
}
export default Auth;
Don't put your component definition inside the other component. If you do it, you create a new component at every render.
You need to work around to move Emailform, Passform to outside of Auth.
Checkout this sandbox to experiment
function Auth() {
// 🚫 the bad place to define components
const Emailform = () => {
...
}
// 🚫 the bad place to define components
const Passform = () => {
...
}
}

React Formik: My custom onBlur override default touched behavior and not displaying my ErrorMessage

I just started learning to code 2 months ago, this week I tried to work with Formik and had this issue where I can't display my ErrorMessage after I added onBlur on the field, before added it, was working normally.
Also, I didn't find another way to work with onBlur, that's why I code it on the field.
I appreciate it if have a hand.
import { Formik, Field, Form, ErrorMessage } from "formik";
import Schema from "./Schema";
import { Container, Row, Col } from "react-bootstrap";
import { useState } from "react";
import Result from "./Result";
import { BsEyeSlashFill } from "react-icons/bs";
const Register = () => {
const [data, setData] = useState(false);
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setConfirmShowPassword] = useState(false)
const [checkMarkName, setCheckMarkName] = useState(null)
const [checkMarkSurname, setCheckMarkSurname] = useState(false)
const [checkMarkEmail, setCheckMarkEmail] = useState(false)
const [checkMarkPass, setCheckMarkPass] = useState(false)
const [checkMarkConfirmPass, setCheckMarkConfirmPass] = useState(false)
const hidePassword = () => {
setShowPassword(!showPassword)
}
const hideConfirmPassword = () => {
setConfirmShowPassword(!showConfirmPassword)
}
function onSubmit(values, actions) {
setData(values)
}
return (
<Formik
validationSchema={Schema}
onSubmit={onSubmit}
validateOnMount
initialValues={{
name: "",
surname: "",
email: "",
password: "",
confirmPassword: "",
}}
>
{(props) => (
<Container>
<Row className="justify-content-center mt-3" >
<Col className="text-center d-flex justify-content-center" md={8}>
<Form className="mt-5 div-form w-100">
{console.log(props)}
<div className="errors mt-3">
<label>Nome</label>
<Field onBlur={() => {
if(!props.errors.name)(
setCheckMarkName(true)
)
}} name="name" className={checkMarkName ? "form-control form-control-green" : "form-control"} type="text" />
<div><ErrorMessage name="name" /></div>
</div>
<div className="errors mt-3">
<label>Surname</label>
<Field onBlur={() => {
if(!props.errors.surname)(
setCheckMarkSurname(true)
)
}} name="surname" className={checkMarkSurname ? "form-control form-control-green" : "form-control"} type="text" />
<div><ErrorMessage name="surname" /></div>
</div>
<div className="errors mt-3">
<label>Email</label>
<Field onBlur={() => {
if(!props.errors.email)(
setCheckMarkEmail(true)
)
}} name="email" className={checkMarkEmail ? "form-control form-control-green" : "form-control"} type="email" />
<div><ErrorMessage name="email" /></div>
</div>
<div className="errors mt-3 position-relative">
<label>Password</label>
<Field onBlur={() => {
if(!props.errors.password)(
setCheckMarkPass(true)
)
}}
name="password"
className={checkMarkPass ? "form-control form-control-green" : "form-control"}
type={showPassword ? 'text' : 'password'}
></Field>
<span className="position-relative eyes text-white"><BsEyeSlashFill onClick={() => hidePassword()} /></span>
<div className="position-relative error-msg"><ErrorMessage name="password" /></div>
</div>
<div className="errors mb-4 position-relative">
<label>Confirm Password</label>
<Field onBlur={() => {
if(!props.errors.confirmPassword)(
setCheckMarkConfirmPass(true)
)
}}
name="confirmPassword"
className={checkMarkConfirmPass ? "form-control form-control-green" : "form-control"}
type={showConfirmPassword ? 'text' : 'password'}
/>
<span className="position-relative eyesConfirm text-white"><BsEyeSlashFill onClick={() => hideConfirmPassword()} /></span>
<div className="position-relative error-msg"><ErrorMessage name="confirmPassword" /></div>
</div>
<button
className="btn btn-primary mb-3"
disabled={!props.isValid}
type="submit"
>
Enviar
</button>
<button
className="btn btn-primary mb-3 ml-3"
type="button"
onClick={() => setData(false)}
>
Reset
</button>
</Form>
</Col>
{
data &&
<Result data={data}/>
}
</Row>
</Container>
)}
</Formik>
);
};
export default Register;

How to implement radio buttons in ReactJS with Formik

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

Resources