useEffect not triggered on react hook form change - reactjs

looking to use react hook form with useEffect to get changes in real time (as the user is filling out the form), is there a reason why useEffect isn't triggered here and if so is there a way to trigger it whenever the form data changes? example here is from https://remotestack.io/react-hook-form-set-update-form-values-with-useeffect-hook/
import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
export default function SimpleForm() {
const { register, handleSubmit, reset, formState } = useForm();
const [student, initStudent] = useState(null);
useEffect(() => {
setTimeout(
() =>
initStudent({
name: "Little Johnny",
email: "lil#johnny.com",
grade: "3rd",
}),
1200
);
}, []);
useEffect(() => {
console.log("updating.,..");
reset(student);
}, [reset, student]);
function onFormSubmit(dataRes) {
console.log(dataRes);
return false;
}
return (
<div>
<h2 className="mb-3">
React Initiate Form Values in useEffect Hook Example
</h2>
{student && (
<form onSubmit={handleSubmit(onFormSubmit)}>
<div className="form-group mb-3">
<label>Name</label>
<input
type="text"
name="name"
{...register("name")}
className="form-control"
/>
</div>
<div className="form-group mb-3">
<label>Email</label>
<input
type="email"
name="email"
{...register("email")}
className="form-control"
/>
</div>
<div className="form-group mb-3">
<label>Grade</label>
<input
type="text"
name="grade"
{...register("grade")}
className="form-control"
/>
</div>
<button type="submit" className="btn btn-dark">
Send
</button>
</form>
)}
{!student && (
<div className="text-center p-3">
<span className="spinner-border spinner-border-sm align-center"></span>
</div>
)}
</div>
);
}

You can use watch mode of react hook form to get every change.
const { register, handleSubmit, reset, formState, watch } = useForm();
useEffect(() => {
watch((value, { name, type }) => console.log(value, name, type));
}, [watch]);
Read more about watch mode form here

You need to trigger a state change whenever your input field value changes, and you do so using onClick event attribute like so:
import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
export default function SimpleForm() {
const { register, handleSubmit, reset, formState } = useForm();
const [student, initStudent] = useState(null);
useEffect(() => {
setTimeout(
() =>
initStudent({
name: "Little Johnny",
email: "lil#johnny.com",
grade: "3rd",
}),
1200
);
}, []);
useEffect(() => {
console.log("updating.,..");
reset(student);
}, [reset, student]);
function onFormSubmit(dataRes) {
console.log(dataRes);
return false;
}
return (
<div>
<h2 className="mb-3">
React Initiate Form Values in useEffect Hook Example
</h2>
{student && (
<form onSubmit={handleSubmit(onFormSubmit)}>
<div className="form-group mb-3">
<label>Name</label>
<input
type="text"
name="name"
{...register("name")}
onClick={(e)=>initStudent({...student, name: e.target.value})}
className="form-control"
/>
</div>
<div className="form-group mb-3">
<label>Email</label>
<input
type="email"
name="email"
{...register("email")}
onClick={(e)=>initStudent({...student, email: e.target.value})}
className="form-control"
/>
</div>
<div className="form-group mb-3">
<label>Grade</label>
<input
type="text"
name="grade"
{...register("grade")}
onClick={(e)=>initStudent({...student, grade: e.target.value})}
className="form-control"
/>
</div>
<button type="submit" className="btn btn-dark">
Send
</button>
</form>
)}
{!student && (
<div className="text-center p-3">
<span className="spinner-border spinner-border-sm align-center"></span>
</div>
)}
</div>
);
}

Related

Clicking on react button asks me to leave site

I am learning react and I have a component which as a 2 input fields and a button, at the moment, clicking on the button will display a message in console log, but when the button is clicked it displays a popup Leave site?, Changes that you made may not be saved.
this is my code in this component
import React, { useRef, useState, Component } from 'react'
import { useAuthState } from 'react-firebase-hooks/auth';
import { useCollectionData } from 'react-firebase-hooks/firestore';
import { signOut } from 'firebase/auth';
class InfoLgnTest extends Component {
render() {
this.state = {
user: null
}
return (
<div>
<div className="App">
<SignInWithEmailPassword />
</div>
</div>
)
}
}
function SignInWithEmailPassword() {
const emailRef = useRef()
const passwordRef = useRef()
const signIn = () => {
console.log("InfoLgnTest singin clicked")
}
return (
<>
<div className="form">
<form>
<div className="input-container">
<label>Username </label>
<input
name="email"
type="text"
ref={emailRef}
required
placeholder ="something#gmail.com"
/>
</div>
<div className="input-container">
<label>Password </label>
<input
type="text"
name="pass"
ref={passwordRef}
required
placeholder ="..."
/>
</div>
<div className="button-container">
<input type="submit" onClick={signIn}/>
</div>
</form>
</div>
</>
)
}
export default InfoLgnTest
This code has a form, by default form send data as a request on the same page, for resolve this:
Add onSubmit to form,
call preventDefault method from event
call the function signIn
Change <input type="submit" ... /> to <button type="submit">Send</button>
function SignInWithEmailPassword() {
const emailRef = useRef()
const passwordRef = useRef()
const signIn = () => {
console.log("InfoLgnTest singin clicked")
}
// new function to handle submit
const submitForm = (event) => {
event.preventDefault();
signIn();
}
return (
<>
<div className="form">
{/* Add onSubmit */}
<form onSubmit={submitForm}>
<div className="input-container">
<label>Username </label>
<input
name="email"
type="text"
ref={emailRef}
required
placeholder ="something#gmail.com"
/>
</div>
<div className="input-container">
<label>Password </label>
<input
type="text"
name="pass"
ref={passwordRef}
required
placeholder ="..."
/>
</div>
<div className="button-container">
{/* Change input to button */}
<button type="submit">Send</button>
</div>
</form>
</div>
</>
)
}

Invalid hook call. How can I call dispatch?

I'm trying to send data from inputs to redax storage. Why does the dispatch(addChild(parent)) get an error?
Error: Invalid hook call. Hooks can only be called inside of the body of a function component
import {useDispatch} from "react-redux";
import { addChild} from "../../store/actions/actions";
const Form = () => {
const [parent, setParent] = useState([{name: "", age: ""}]);
const [childList, setChildList] = useState([{name: "", age: ""}])
const dispatch = useDispatch;
const handleChange = (e, index) => {
const { name, value } = e.target;
const child = [...childList];
child[index][name] = value;
setChildList(child)
}
const handleSubmit = (e) => {
e.preventDefault();
dispatch(addChild(parent))
}
const addChildElement = ()=> {
setChildList( [...childList, {name: "", age: ""}]);
}
return (
<form className="form" onSubmit={handleSubmit}>
<div className="form__parent">
<div className="form-title">Персональные данные</div>
<div className="form-item">
<input className="form-input" type="text"
value={parent.name}
onChange={(e) => setParent({...parent, name: e.target.value})}
/>
<label className="form-label">Имя</label>
</div>
<div className="form-item">
<input className="form-input" type="number"
value={parent.age}
onChange={(e) => setParent({...parent, age: e.target.value})}
/>
<label className="form-label">Возраст</label>
</div>
</div>
<div className="form__child">
<div className="form__child-head">
<div className="form-title">Дети (макс.5)</div>
<button className="btn add-child-btn" onClick={addChildElement}>Добавить ребенка</button>
</div>
<ul className="form__child-content">
{
childList.map((value, id) => {
return (
<li className="child-list" key={id}>
<div className="form-item">
<input className="form-input" type="text"
name="name"
value={value.name}
onChange={e => handleChange(e, id)}
/>
<label className="form-label">Имя</label>
</div>
<div className="form-item">
<input className="form-input" type="number"
value={value.age}
name="age"
onChange={e => handleChange(e, id)}
/>
<label className="form-label">Возраст</label>
</div>
<button className="remove-list">Удалить</button>
</li>
);
})
}
</ul>
<input className="btn submit" type="submit" value="Сохранить" />
</div>
</form>
);
}
export default Form;`
This is the mistake you have made. call brackets() are missing in your useDispatch declaration.
it should be corrected like below
const dispatch = useDispatch();
Error is totally valid because now your dispatch is not the output of useDispatch. It's useDispatch itself and error is due to useDispatch hook is used inside handleSubmit.

Unable to type in input field React

I am creating a simple todo list. In here there is a modal for the update form,I can take the relevant values from the state And set them to the input field values. then I can't edit the input fields. I think the problem is with the onChange function or value property
import React from 'react'
import {useRef,useState,useEffect} from 'react'
import {FaTimes} from 'react-icons/fa'
export const Modal = ({edData,showModal,setShowModal,onAdd,setEd,tasks}) => {
const [text,setText] = useState('')
const[day,setDay] = useState('')
const[reminder,setReminder] = useState(false)
useEffect(() => {
if(edData!=null){
for(let i=0;i<tasks.length;i++)
{
if(tasks[i].id===edData){
// console.log(tasks[i])
setText(tasks[i].text)
setDay(tasks[i].day)
setReminder(tasks[i].reminder)
}
}
}
// inputText.current.value = edData.text;
// inputDay.current.value = edData.day;
// inputReminder.current.value = edData.reminder;
});
const closeModal = () =>{
setEd(null)
setShowModal(prev=>!prev)
setText('')
setDay('')
setReminder(false)
}
const onSubmit = (e) =>{
e.preventDefault()
if (!text){
alert('Please add a task')
return
}
onAdd({text,day,reminder})
setText('')
setDay('')
setReminder(false)
setShowModal(prev=>!prev)
}
return (
<>
{showModal?
<div className="background">
<div className="ModalWrapper" >
<div className="ModalContent">
<h2 className="modalTitle">{edData==null? 'Add New Task':'Update Task'}</h2>
<form className="add-form" onSubmit={onSubmit}>
<div className="form-control">
<label htmlFor="">Task</label>
<input type="text" placeholder="Add Task" name="" id="" value={text} onChange={(e) => setText(e.target.value)}/>
</div>
<div className="form-control ">
<label htmlFor="">Date & Time</label>
<input type="text" placeholder="Add Date and Time" name="" id="" value={day} onChange={(e) => setDay(e.target.value)}/>
</div>
<div className="form-control form-control-check">
<label htmlFor="">Set Reminder</label>
<input type="checkbox" checked={reminder} name="" id="" value={reminder} onChange={(e) => setReminder(e.currentTarget.checked)}/>
</div>
<input className="btn btn-block" type="submit" value="Save Task" />
</form >
</div>
<div className="CloseModalButton" onClick={closeModal}>
<FaTimes/>
</div>
</div>
</div>
: null}
</>
)
}
If you don't pass a dependency array to useEffect it will be called on every render, calling setText inside of it and overwriting the input's value, pass an empty array to useEffect if you don't want it to run on every render :
useEffect(() => {
// ....
}, []);

Submit Form Using React Redux

I am using react-redux hooks.I want to dispatch an action after some validations when the form is submitted. But I cannot call usedispatch() hook outside function component. Is there any way I can dispatch an action using usedispatch() ?
My code looks as below:
import React, { Component } from 'react';
import { register } from '../../actions/auth';
import { useDispatch, useSelector } from "react-redux";
let state = {
username: '',
password1: '',
password2: '',
}
const onSubmit = (e) => {
e.preventDefault()
const dispatch = useDispatch();
if (state.password1 === state.password2) {
dispatch(register(state))
}
else {
console.log('Psw did not matched.')
}
}
const onChange = (e) => {
let field_name = e.target.name;
state[field_name] = e.target.value;
}
const Register = () => {
return (
<div className="col-md-6 m-auto">
<div className="card card-body mt-5">
<h2 className="text-center">Register</h2>
<form encType="multipart/form-data" onSubmit={onSubmit}>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={onChange}
required/>
</div>
<div className="form-group">
<label> Password</label>
<input
type="password"
className="form-control"
name="password1"
onChange={onChange}
required/>
</div>
<div className="form-group">
<label>Confirm Password</label>
<input
type="password"
className="form-control"
name="password2"
onChange={onChange}
required/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">Register</button>
</div>
</form>
</div>
</div>
);
}
export default Register;
I get an error that React Hooks cannot be used outside function component and it is obvious. I am looking for a way to dispatch register action after doing some validation when form is submitted.
Since you are writing a React component, it would make sense if you define your state within and other functions within the component. This way you would be able to use hook, useDispatch as well. Also you can make your input fields controlled instead of letting them be uncontrolled
import React, { Component } from 'react';
import { register } from '../../actions/auth';
import { useDispatch, useSelector } from "react-redux";
const Register = () => {
const [state, setState] = useState({
username: '',
password1: '',
password2: '',
});
const onChange = (e) => {
let field_name = e.target.name;
let field_value = e.target.value;
setState(prev => ({...prev, [field_name]: field_value});
}
const dispatch = useDispatch();
const onSubmit = (e) => {
e.preventDefault()
if (state.password1 === state.password2) {
dispatch(register(state))
}
else {
console.log('Psw did not matched.')
}
}
return (
<div className="col-md-6 m-auto">
<div className="card card-body mt-5">
<h2 className="text-center">Register</h2>
<form encType="multipart/form-data" onSubmit={onSubmit}>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
value={state.username}
onChange={onChange}
required/>
</div>
<div className="form-group">
<label> Password</label>
<input
type="password"
className="form-control"
name="password1"
value={state.password1}
onChange={onChange}
required/>
</div>
<div className="form-group">
<label>Confirm Password</label>
<input
type="password"
className="form-control"
name="password2"
value={state.password2}
onChange={onChange}
required/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">Register</button>
</div>
</form>
</div>
</div>
);
}
export default Register;

How to do routing by using Conditions in React

I am working on a React project, First I have to Signup then I stored Signup details in local storage so when I came to login screen after entering email and password and when I click submit button then it has to check the email and password from local storage. So if both are same then it should redirects to another page, I am trying to do this but it is showing some error so someone please help me to resolve this error
This is my code
This is Signup.js
import React, { useState, useRef } from 'react';
import './Signup.css';
const Signup = () => {
const [data, sendData] = useState({})
const handleChange = ({ target }) => {
const { name, value } = target
const newData = Object.assign({}, data, { [name]: value })
sendData(newData)
}
const handleSubmit = (e) => {
e.preventDefault()
localStorage.setItem('userInfo', JSON.stringify(data))
}
const myForm = useRef(null)
const resetForm = () => {
myForm.current.reset();
}
return (
<div className='container'>
<div className='row justify-content-center'>
<div className='col-4'>
<div className='registerForm'>
<form onSubmit={handleSubmit} ref={myForm}>
<div className="form-group mb-2">
<label htmlFor="firstname">Firstname</label>
<input type="text" className="form-control" onChange={handleChange} name='firstname' id="firstname" placeholder="Enter firstname"></input>
</div>
<div className="form-group mb-2">
<label htmlFor="lastname">Lastname</label>
<input type="text" className="form-control" onChange={handleChange} name='lastname' id="lastname" placeholder="Enter lastname"></input>
</div>
<div className="form-group mb-2">
<label htmlFor="email">Email</label>
<input type="email" className="form-control" onChange={handleChange} name='email' id="email" placeholder="Enter email"></input>
</div>
<div className="form-group mb-2">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" onChange={handleChange} name='password' id="password" placeholder="Enter password"></input>
</div>
<button onClick={resetForm} type="submit" className="btn btn-primary mt-3">Submit</button>
</form>
</div>
</div>
</div>
</div>
)
}
export default Signup
This is Login.js
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import './Login.css';
const Login = () => {
let history = useHistory();
if (login.email && login.password === signupCredentials.email && signupCredentials.password) {
var redirect = () => {
history.push('/dashboard')
}
}
const [login, setLogin] = useState({})
const handleChange = ({ target }) => {
const { name, value } = target
const newData = Object.assign({}, login, { [name]: value })
setLogin(newData)
}
const handleSubmit = (e) => {
e.preventDefault()
console.log(login)
}
const signupCredentials = JSON.parse(localStorage.getItem('userInfo'))
console.log(signupCredentials.email && signupCredentials.password)
return (
<div className='container'>
<div className='row justify-content-center'>
<div className='col-4'>
<form onSubmit={handleSubmit}>
<div className="form-group mb-2">
<label htmlFor="exampleInputEmail1">Email address</label>
<input type="email" className="form-control" onChange={handleChange} name='email' id="exampleInputEmail1" placeholder="Enter email"></input>
</div>
<div className="form-group mb-2">
<label htmlFor="exampleInputPassword1">Password</label>
<input type="password" className="form-control" onChange={handleChange} name='password' id="exampleInputPassword1" placeholder="Password"></input>
</div>
<button type="submit" onClick={redirect} className="btn btn-primary mt-3">Submit</button>
</form>
</div>
</div>
</div>
)
}
export default Login
If you have any questions please let me know

Resources