Cannot clear state and getting wrong response from useState form - javascript

I'm strugling with my form in typescript react. Basicly I created 2 simple components Button and Input and add them to the another component Form where I created a whole form.
After submit I should get something like this:
telephone: "323423234"
email: "tress#wess.com"
message: "weklfnwlkf"
name: "less"
surname: "mess"
But after submit I get weird response like this:
"": "323423234"
email: "tress#wess.com"
message: "weklfnwlkf"
name: "less"
surname: "mess"
telephone: ""
It is a little bit werido because I done something like this couple days ago and now idk what to do.
There is sample of my Form code
const Form = () => {
interface FormDataType {
telephone: string;
name: string;
surname: string;
email: string;
message: string;
}
const formData: FormDataType = {
telephone: '',
name: '',
surname: '',
email: '',
message: '',
};
const [responseBody, setResponseBody] = useState<FormDataType>(formData);
const clearState = () => {
setResponseBody({ ...formData });
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setResponseBody({ ...responseBody, [name]: value });
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(responseBody);
clearState();
};
return (
<>
<form onSubmit={handleSubmit}>
{FormData.map((option) => (
<Input
key={option.name}
label={option.label}
type={option.type}
className={option.className}
name={option.name}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleChange(e)
}
/>
))}
<div className='div'>
<Button
type='submit'
title={'Simple test'}
className={'btn-primary'}
/>
</div>
</form>
</>
);
};
export default Form;
And when I'm invoking in handleSubmit function clearState() it doesn't refresh states in webpage inputs.

I hope this is what it needs, I made some changes, but you can adapt it to your project
export default function App() {
interface FormDataType {
telephone: string;
name: string;
surname: string;
email: string;
message: string;
}
const formData: FormDataType = {
telephone: "",
name: "",
surname: "",
email: "",
message: ""
};
const [values, setValues] = useState<FormDataType | any>(formData);
// reset
const reset = (newFormState = formData) => {
setValues(newFormState);
};
// handleInputChange
const handleInputChange = ({ target }: any) => {
setValues({ ...values, [target.name]: target.value });
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(values);
reset();
};
const data = [
{
type: "text",
name: "name"
},
{
type: "text",
name: "surname"
},
{
type: "email",
name: "email"
},
{
type: "tel",
name: "telephone"
},
{
type: "text",
name: "message"
}
];
return (
<>
<form onSubmit={handleSubmit}>
{data.map((option) => (
<input
key={option.name}
value={values[option.name]}
type={option.type}
name={option.name}
placeholder={option.name}
onChange={handleInputChange}
/>
))}
<div className="div">
<button type="submit">Simple test</button>
</div>
</form>
</>
);
}

Your reset doesn't work because your inputs are uncontrolled.
To have them reset properly, you should make them controlled by passing them a value prop. It would look something like this:
<Input
key={option.name}
label={option.label}
type={option.type}
className={option.className}
name={option.name}
value={responseBody[option.name]} // Add this
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleChange(e)
}
/>
This will connect the responseBody form data with the input values.
As to the odd console logged value, it would appear that at least one of the option.name values is empty/undefined (looks like the telephone object). Verify that the FormData contains complete and correct values.

Related

How to change a "sub value" from an initial value?

I'm using Next.js with typescript.
I have a form with multiple inputs. I didn't want to make a useState for each input for obvious reasons and I didn't want to use a form-ready library either. I just wanted to find the solution to this.
How can I get the handleInputChange function to change the value of the director's name, for example, in the "initial state"?
const formInitialValues = {
teamName: "",
bornAt: "",
logo: "",
director: {
name: "",
email: "",
phone: "",
},
};
const [formData, setFormData] = useState(formInitialValues);
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});
};
...
<input
type="text"
placeholder="Director name"
name="directorName"
id="directorName"
required
value={formData.director.name}
onChange={handleInputChange}
/>
...
You can do it like below:
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormData(() => {
...formData,
director: {
...formData.director,
[name]: value
}
});
};
or using callback of setter method:
setFormData((prevFormData) => ({
...prevFormData,
director: {
...prevFormData.director,
[name]: value
}
}));

problem with custom form handler in react

I'm trying to create a custom hook that'll can be used in any form but i have a problem which i am not sure of what it is. whenever i start typing into the fields it loses focus, to type into it again you'd have to click into it and it goes on like that. this isn't good and i would appreciate it if anyone can help me solve this error.
useForm.js
import { useState } from "react";
const useForm = () => {
const [values, setValues] = useState({
// contact form
});
const [errors, seterrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
// console.log(name, value);
};
const validate = (data) => {};
const handleSubmit = (e) => {
e.preventDefault();
// console.log(e);
};
// console.log(values);
return {
handleChange,
values,
handleSubmit
};
};
export default useForm;
Form.js
import InputGroup from "./InputGroup";
import useForm from "./useForm";
const Form = () => {
const fields = [
{
label: "First Name",
className: "input-group",
name: "firstName",
placeholder: "John",
type: "text"
},
{
label: "Last Name",
className: "input-group",
name: "lastName",
placeholder: "Doe",
type: "text"
},
{
label: "Email",
className: "input-group",
name: "email",
placeholder: "JohnDoe#example.com",
type: "email"
},
{
label: "Phone Number",
className: "input-group",
name: "Phone",
placeholder: "+234 (0)81 234 5678",
type: "text"
// pattern: "/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-s./0-9]*$/g"
},
{
label: "Comments",
className: "input-group",
name: "comment",
placeholder: "Message",
type: "textarea"
}
];
const { values, handleChange, handleSubmit } = useForm();
//funtion to generate id based on fields lenght
const id = () => {
const head = Date.now.toString(36);
const tail = Math.random().toString(36).substr(2);
return head + tail;
};
console.log(id);
return (
<form onSubmit={handleSubmit}>
{fields.map((field) => (
<InputGroup
key={id}
value={values}
onChange={handleChange}
{...field}
/>
))}
<button>submit</button>
</form>
);
};
export default Form;
Input
const Input = ({ ...props }) => {
return <input {...props} />;
};
export default Input;
You are not using your id function properly, you are only referring to it, not invoking it, change -
<InputGroup
key={id}
to
<InputGroup
key={id()}
or better still, a better name, using a verb would have highlighted the problem easier, as it now looks like a function and not a variable
<InputGroup
key={buildId()}
or whatever, but better still, you should use a static unique value for the key (i.e unique but would not change between renders, so using timestamps is a bad idea), so you could add a unique id to each field and use it -
const fields = [
{
id: <some unique ID>, <!---- here
label: "First Name",
className: "input-group",
name: "firstName",
placeholder: "John",
type: "text"
}
...
]
...
<InputGroup
key={field.id}

How to submit a new post?

Hi everyone so I am making an application for hosting events and when I try to add and event the submit button doesn't do anything. Please help me.
THIS IS THE HANDLE SUBMIT FUNCTION
handleSubmit = e => {
e.preventDefault();
const errors = this.validate();
this.setState({ errors: errors || {} });
if (errors) return;
this.doSubmit();
};
THIS IS THE BUTTON
renderButton(label) {
return (
<button disabled={this.validate()} className="btn btn-primary">
{label}
</button>
);
}
THIS IS THE THE EVENTFORM
import React from "react";
import Form from "./form";
import Joi from "joi-browser";
import { getEvent, saveEvent } from "../services/fakeEvents";
import { getCategories } from "../services/fakeCategories";
class EventForm extends Form {
state = {
data: {
title: "",
eventPicture: "",
categoryId: "",
eventTime: "",
numberOfAtendies: "",
location: "",
details: ""
},
categories: [],
errors: {}
};
schema = {
_id: Joi.string(),
title: Joi.string()
.required()
.label("Event Title"),
categoryId: Joi.string()
.required()
.label("Choose Category"),
eventTime: Joi.number()
.required()
.label("Choose Event Time"),
numberOfAtendies: Joi.number()
.required()
.min(1)
.max(100000)
.label("Numeber of Attendies"),
location: Joi.string()
.required()
.label("Event Location"),
details: Joi.string()
.required()
.label("Event Details")
.min(250)
.max(300)
};
componentDidMount() {
const categories = getCategories();
this.setState({ categories });
const eventId = this.props.match.params.id;
if (eventId === undefined) return;
const event = getEvent(eventId);
if (!event) return this.props.history.replace("/not-found");
this.setState({ data: this.mapToViewModel(event) });
}
mapToViewModel(event) {
return {
_id: event._id,
title: event.title,
categoryId: event.category._id,
eventTime: event.eventTime,
numberOfAtendies: event.numberOfAtendies,
location: event.location,
details: event.details
};
}
doSubmit = () => {
saveEvent(this.state.data);
this.props.history.push("/home");
console.log(this.state)
};
render() {
return (
<div>
<h1>Create Event</h1>
<form onSubmit={this.handleSubmit}>
{this.renderInput("title", "Title")}
{this.renderSelect("categoryId", "Category", this.state.categories)}
{this.renderInput("eventTime", "Event Time")}
{this.renderInput("numberOfAtendies", "Number of Attendies")}
{this.renderInput("location", "Location")}
{this.renderInput("details", "Details")}
{this.renderButton("Create")}
</form>
</div>
);
}
}
export default EventForm;
Not sure if this makes sense I'm new to this so please let me know if further information is needed.
Your problem is here, it should be something like this :
renderButton(label) {
return (
<button disabled={this.validate() ? true : false} className="btn btn-primary">
{label}
</button>
);
}

How to add data to state object in react?

I created this.state.data object. Now I need to put this.state.email and this.state.password into this.state.data.email2 and this.state.data.password2
I want to create local storage. To do that I need an object where I could store data. this.state.email and this.state.password are inputs.
class Register extends Component {
constructor(props){
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
// This binding is necessary to make `this` work in the callback
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleEmailChange = (event) => {
this.setState({email: event.target.value});
}
handlePasswordChange = (event) => {
this.setState({password: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
})
}
When I activate handleSubmit method I expect to take this.state.email, and this.state.password. And put it into object this.state.data
Hope you need to pass this.state.email and this.state.password to this.state.data
You can do that in handleEmailChange and handlePasswordChange itself, and your using arrow functions, so don't need to bind this in constructor.
Check a code below:
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
}
handleEmailChange = (event) => {
this.setState({
email: event.target.value,
data: {
...this.state.data,
email2: event.target.value,
}
});
}
handlePasswordChange = (event) => {
this.setState({
password: event.target.value,
data: {
...this.state.data,
password2: event.target.value,
}
});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
console.log('object data');
console.log(this.state.data);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
}, () => console.log(this.state))
}
render() {
return (
<div>
<input type="text" onChange={this.handleEmailChange} value={this.state.email} />
<br/><br/>
<input type="text" onChange={this.handlePasswordChange} value={this.state.password} />
<br/><br/>
<button type="button" onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
Working demo
and don't need to write separate events for similar functionalities, Check the demo once, you can do it like below:
<input type="text" data-field = "email" onChange={this.handleChange} value={this.state.email} />
<input type="text" data-field = "password" onChange={this.handleChange} value={this.state.password} />
and in handleChange
handleChange = (event) => {
this.setState({
[event.target.getAttribute('data-field')]: event.target.value,
data: {
...this.state.data,
[`${event.target.getAttribute('data-field')}2`]: event.target.value,
}
});
}
Hope this helps.
Like this (assuming your setup supports spread operator ... )
handleEmailChange = event => {
this.setState({ email: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, email2: event.target.value } }));
};
handlePasswordChange = event => {
this.setState({ password: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, password2: event.target.value } }));
};
You can do like this
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
const {data} = this.state;
data.email2 = this.state.email;
data.password2 = this.state.password;
this.setState({ data });
// Reset form;
this.setState({
email: '',
password: '',
})
}
or without mutating the state (good practice)
this.setState(prevState => ({
data: {
...prevState.data,
[data.email2]: this.state.email
[data.password2]: this.state.password
},
}));

React JS How to reset a form

How do I reset the values in a form in React JS onClick?
class AddFriendForm extends Component {
constructor(props) {
super(props)
this.state = {
firstname: '',
lastname: '',
}
}
render() {
const { addFriend } = this.props
const setFirstName = add => this.setState({ firstname: add.target.value })
const setLastName = add => this.setState({ lastname: add.target.value })
return (
<div>
<div>
<Label label="First Name" />
<Field onChange={setFirstName} />
<Label label="Last Name" />
<Field onChange={setLastName} />
<SecondaryButton
name="Search"
onClick={() => addFriend(this.state)}
/>
<SecondaryButton
name="Reset"
onClick={() => ???}
/>
</div>
</div>
)
}
}
When the user presses the Reset button, I want an onClick event that resets all the fields in the form to blank. Is there a single line of code to do this?
First, create a function called resetForm
resetForm = () => {
this.setState({
...this.state,
firstname: '',
lastname: ''
})
}
Then trigger the function when reset button is clicked
onClick={this.resetForm}
Cheers mate
EDIT:
You have to assign the values to "Field" using value={this.state.firstname}
<Field value={this.state.firstname} onChange={...
Small tip: dont define your functions in your jsx code.
You can do this simply like this.
Before the render() add below part. This is a function to reset the fields.
reset = () => {
this.setState({ firstname: ''})
this.setState({ lastname: ''})
}
And this where the function is called. (In Button onPress.)
<Button
title='reset'
style={styles.button}
onPress={this.reset}
>
</Button>
Note:- use this one in functional component.
const handleReset = (e) => {
e.preventDefault();
setState(prevState => ({
...prevState,
name: '',
email: '',
password: ''
}))
}
handleReset = () => {
setState(({
name: '',
email: '',
}))
}

Categories