Formik use debounce on change input - reactjs

I have this simple example using useDebouncedCallback from use-debounce. When i write to input it remains the same with no value. What iam doing wrong?
const SignupForm = () => {
const formik = useFormik({
initialValues: {
firstName: "",
},
});
const debounced = useDebouncedCallback(
// function
(event) => {
formik.handleChange(event);
},
// delay in ms
1000
);
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
onBlur={formik.handleBlur}
onChange={(e) => {
e.persist();
debounced(e);
}}
value={formik.values.firstName}
/>
<button type="submit">Submit</button>
</form>
);
};

It's not working because you have a controlled component (due to value={formik.values.firstName}).
When formik.handleChange is called (in an debounced way), e.target.value is empty because React keeps the input field in sync with formik.values.firstName which remains empty (its initial value is firstName: "").
To make it work, you can use the formik setFieldValue and pass the input name and value to the debounced function like this :
const debounced = useDebouncedCallback(
(field, value) => formik.setFieldValue(field, value),
1000
);
...
<input
id="firstName"
name="firstName"
type="text"
onBlur={formik.handleBlur}
onChange={(e) => {
const { name, value } = e.target;
debounced(name, value);
}}
value={formik.values.firstName}
/>
Here is a stackblitz example

Related

Input value is not being cleared after submit

I am building a to-do list in react and when adding a new task to the list, the input value is not being cleared from the form after submit, I'm trying to achieve this using setInput('');
const Form = (props) => {
const [input, setInput] = useState('');
const handleChange = e => {
setInput(e.target.value);
}
const handleSubmit = e => {
e.preventDefault();
const newTask = {
id: uuidv4(),
text: input,
completed: false
};
props.onSubmit(newTask);
setInput('');
}
return (
<form
className='task-form'
>
<input
className='task-input'
type='text'
placeholder='Enter a task'
name='text'
onChange={handleChange}
/>
<button className='task-btn' onClick={handleSubmit}>Add Task</button>
</form>
)
}
export default Form
You aren't using the input state anywhere except when creating the newTask object. You need to pass it as a prop to the <input> component to make it fully controlled and for calls to the state setter to result in changes to the DOM.
<input
className='task-input'
type='text'
placeholder='Enter a task'
name='text'
onChange={handleChange}
/>
should be
<input
className='task-input'
type='text'
placeholder='Enter a task'
name='text'
onChange={handleChange}
value={input}
/>

How can i put value in input?

Why can't I put a value in the input? The problem is: I need to put a 'name' in <Form.Item> to apply the rules. Without that, the rules will not be able to work, but if you remove the name="userName" from <Form.Item the value appears at the input.
How can i solve that?
<Form autoComplete="off" layout="vertical" onFinish={handleFinish}>
<Form.Item name="userName" rules={getTextRule('name')}>
<Input value={fields?.firstName} name="firstName" onChange={(e) => {
handleInputChange(e)
}} />
</Form.Item>
</Form.Item>
simple we can code like
const [text,setText] = useState('')
return(
<input type='text' value={text} onChange={e=>setText(e.target.value)}/>
)
If you use the form you can let Ant Form manage the state by removing the value & the onChange props on the <Input />.
Else if you manage the state by yourself make sure to get the value from the e.target.value.
ex:
const [fields, setFields] = useState({})
const handleOnChange = (e) => {
setFields((state) => {
...state,
[e.target.name]: e.target.value,
})
}
return (
<Input
name="firstName"
value={fields.firstName}
onChange={handleOnChange}
/>
)

react-hook-form: unregister doesnt clear component value

i have one text field which i am manually unregistering. it is successfully getting unregister and data is excluded from formdata, however user entered value still stays in the text field. i am expecting value also get cleared from component as well. i even tried
setValue('fieldName',"")
is not working. not sure if i am doing something wrong.
so if i re register my text field and trigger validation, you will see required field validation but value is still present in text field
code below:
const App = () => {
const { register, handleSubmit, unregister, errors, setValue } = useForm();
const onSubmit = (data) => {
alert(JSON.stringify(data));
};
useEffect(() => {
register("person.firstName", { required: true });
register("person.lastName", { required: true });
// }
}, [register]);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First Name</label>
<input
type="text"
name="person.firstName"
onChange={(e) => setValue("person.firstName", e.target.value)}
/>
{errors?.person?.firstName && <p> First name required</p>}
<label>Last Name</label>
<input
type="text"
name="person.lastName"
onChange={(e) => setValue("person.lastName", e.target.value)}
/>
{errors?.person?.lastName && <p> Last name required</p>}
<button
type="button"
onClick={() => {
setValue("person.lastName", "");
unregister("person.lastName");
}}
>
unregister lastName
</button>
<input type="submit" />
</form>
);
};
here is my CSB
i would appreciate any help
the error occurs because you apply your register at useEffect:
useEffect(() => {
register("person.firstName", { required: true });
register("person.lastName", { required: true });
// }
}, [register]);
instead, if you apply to ref at your input fields setValue("person.lastName", "") will clear the field as expected:
<input
ref={register({ required: true })}
type="text"
name="person.firstName"
onChange={(e) => setValue("person.firstName", e.target.value)}
/>

Saving object in React.useState

I have a form in my react project, and I want the value of each field to be stored in the state.
instead of having multiple states for each field, how can I store the form value as an object in the state? and more importantly how can I access it? (with react hooks)
import React from 'react';
export const UserData = () => {
return(
<form>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<button>Confirm</button>
</form>
)
}
React Hooks allows you to define a JavaScript Object using useState. See
https://daveceddia.com/usestate-hook-examples/
function LoginForm() {
const [form, setState] = useState({
username: '',
password: ''
});
Update the form using the function :
const updateField = e => {
setState({
...form,
[e.target.name]: e.target.value
});
};
Call the function onSubmit of the button
<form onSubmit={updateField}>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<Button >Confirm</button>
</form>
You can use useState hook. Check this
const [state, setState] = useState({ name, email });
To set the state similar to setState in class based component:
setState({name: 'react', email: 'react'})
To access the state value:
import React, { useState } from 'react';
export const UserData = () => {
const [state, setState] = useState({ name, email });
return(
<form>
<input type="text" placeholder="Name" value={state.name} />
<input type="email" placeholder="Email" value={state.email} />
<button>Confirm</button>
</form>
)
}
You should create an initial state value if you want to store the form values as an object using useState, so you can rollback to the initial state after an error. Example,
const initialState = {
name: "",
email: ""
};
export const UserData = () => {
const [formState, setFormState] = useState(initialState);
const submitHandler = event => {
event.preventDefault();
console.log(formState);
};
return (
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Name"
value={formState.name}
onChange={e => {
setFormState({ ...formState, name: e.target.value });
}}
/>
<input
type="email"
placeholder="Email"
value={formState.email}
onChange={e => {
setFormState({ ...formState, email: e.target.value });
}}
/>
<button>Confirm</button>
</form>
);
};
Working demo in codesandbox.

Template doesn't react to the change of variable React

I have a component in which I want to display another component after form submit.
When I'm running function on form submit I'm changing submitted value to true and if I do console.log(submitted) it changes to true but in the template it is still false so Alert component doesn't show up.
I'm trying to learn hooks and maybe the problem with how I'm using them?
My component looks like this
export const SignupForm = () => {
let name:any = handleUserInput('');
let email:any = handleUserInput('');
let password:any = handleUserInput('');
let submitted:any = false;
function registerUser(event: React.FormEvent<HTMLFormElement>): void {
event.preventDefault();
submitted = true;
const registerInfo = Object.assign({}, {
email: email.value,
password: password.value,
name: name.value
});
axios.post('/register', registerInfo)
.then(response => {
errors = response.data.errors
})
.catch(error => console.log(error))
}
function handleUserInput(initialValue: string): object {
const [value, setValue] = useState(initialValue);
function handleChange(event: Event): void {
let element = event.target as HTMLInputElement;
setValue(element.value);
}
return {
value,
onChange: handleChange
}
}
return (
<div>
<div dangerouslySetInnerHTML={{__html: submitted}}></div>
{submitted ? <Alert /> : ''}
<div className="form-holder">
<form action="POST" className="form" onSubmit={(e) => registerUser(e)}>
<label htmlFor="Email">Email</label>
<input type="text" id="email" className="form__input" {...email} required />
<label htmlFor="password">Password</label>
<input type="password" id="password" className="form__input" {...password} required />
<label htmlFor="name">Name</label>
<input type="text" id="name" className="form__input" {...name} required />
<button type="submit" className="form__button">Signup</button>
</form>
</div>
</div>
);
}
submitted local variable is assigned asynchronously. This won't result in component update.
It should be:
...
const [submitted, setSubmitted] = useState(false);
function registerUser(event: React.FormEvent<HTMLFormElement>): void {
event.preventDefault();
setSubmitted(true);
...

Resources