I have created a basic form in react.js where I am able to get the values after the user submits the form.
However, when I try to change the values using the handleSubmit function, I don't see the changes made in the state.
I have made a copy of a state and changes are being reflected in the Copied State. But when I set the old state equal to the updated state, the changes are not reflected
My code is as follows
state = {
name: null,
ContactNumber: null
}
handleChange = (event) => {
this.setState({
[event.target.name] : event.target.value
})
}
handleSubmit = (event) => {
event.preventDefault()
let Copystate = JSON.parse(JSON.stringify(this.state))
Copystate.ContactNumber = 100
console.log(Copystate) // displaying the contact number as 100
this.setState({
state : Copystate
})
console.log(this.state) // displays the number which was submitted in the form
}
render(){
return(
<div>
<h2>Form</h2>
<form onSubmit={this.handleSubmit}>
<div>
<label>Name</label>
<input type="text" name="name" required = {true} onChange = {this.handleChange}/>
<label>Contact Number</label>
<input type="number" name="ContactNumber" required = {true} onChange = {this.handleChange}/>
<button type="submit" label="submit" >Submit</button>
</div>
</form>
</div>
);
}
}
Can anyone please let me know where I am going wrong? Thanks
Notice: setState is asynchronous: document state-updates-may-be-asynchronous
You can use a callback function to get the updated state
this.setState({state: Copystate}, () => {console.log(this.state)});
Or you can choose to use async/await
handleSubmit = async (event) => {
await this.setState({state: Copystate});
console.log(this.state);
}
Those two methods won't affect re-render since once the state is been updated, the re-render would proceed.
If you console in the render() you would find that it should always be updated finally.
render() {
console.log(this.state);
return (
...
)
}
setState is asynchronous.
So, you can do one of the following -
1. make a callback in setState to log the state or
2. write your console statement in the render function.
Why do you do this?
let Copystate = JSON.parse(JSON.stringify(this.state))
Copystate.ContactNumber = 100
You can change the handleSubmit to be like the following:
handleSubmit = (event) => {
event.preventDefault();
let { ContactNumber } = this.state;
ContactNumber = 100;
console.log(ContactNumber); // displaying the contact number as 100
this.setState({
ContactNumber: ContactNumber
}, () => {
console.log(this.state) // displays the number which was submitted in the form
})
}
Related
I'm trying to display the value of my inputs from a from, in a list. Everytime I hit submit, I expect that it should display the inputs in order.
The problem I'm having is that when I try to submit my form and display inputs in a list, it display an empty value first. On the next submit and thereafter, it displays the previous value, not the new one on the input field.
There's also an error message but i'm not understanding how to relate it to the problem. It's a warning message regarding controlled/uncontrolled components.
I've tried to add if statements to check for empty values in each functions but the problem persists.I've tried to manage the error massage by being consistent with all input to be controlled elements using setState, but nothing works.
I looked through todo list examples on github. I guess i'm trying to keep it in one functional component versus multiple ones, and I'm not using class components. I tried to follow the wesbos tutorial on Javascript 30 day challenge, day 15: Local Storage and Event Delegation. I'm trying to use React instead of plain JS.
Here's what my component looks like.
import React, { useEffect, useState } from "react";
import "../styles/LocalStorage.css";
export const LocalStorage = () => {
const [collection, setCollection] = useState([]);
const [value, setValue] = useState();
const [item, setItem] = useState({ plate: "", done: false });
const [display, setDisplay] = useState(false);
//set the value of the input
const handleChange = (e) => {
if (e.target.value === "") return;
setValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (value === "" || undefined) return;
setItem((prevState) => {
return { ...prevState, plate: value };
});
addItem(item);
setDisplay(true);
setValue("");
};
const addItem = (input) => {
if (input.plate === "") return;
setCollection([...collection, input]);
};
return (
<div>
<div className="wrapper">
<h2>LOCAL TAPAS</h2>
<ul className="plates">
{display ? (
collection.map((item, i) => {
return (
<li key={i}>
<input
type="checkbox"
data-index={i}
id={`item${i}`}
checked={item.done}
onChange={() =>
item.done
? setItem((state) => ({ ...state, done: false }))
: setItem((state) => ({ ...state, done: true }))
}
/>
<label htmlFor={`item${i}`}>{item.plate}</label>
</li>
);
})
) : (
<li>Loading Tapas...</li>
)}
</ul>
<form className="add-items" onSubmit={handleSubmit}>
<input
type="text"
name="item"
placeholder="Item Name"
required
value={value}
onChange={handleChange}
/>
<button type="submit">+ Add Item</button>
</form>
</div>
</div>
);
};
Since the setState function is asynchronous, you cannot use the state value item right after you fire the setItem(...). To ensure you get the latest value for your addItem function:
setItem((prevState) => {
const newItem = { ...prevState, plate: value };
addItem(newItem); // Now, it's getting the updated value!
return newItem;
});
And regarding the controlled and uncontrolled components, you can read the docs about it here. To fix your problem, you can initialize the value state with an empty string:
const [value, setValue] = useState('');
I'm trying to use ReactJS, and I have encountered this problem:
I have a simple for with one field. And when I click on the submit button the page complete the code but immediately reload (i don't event have the time to read the console).
const INITIAL_STATE = {
teamName: '',
error: null,
};
class SearchingForm extends Component {
constructor(props){
super(props);
this.state = {
...INITIAL_STATE,
results: []
};
}
onSubmit = event => {
const { teamName } = this.state;
this.searching(this.state.teamName)
event.preventDefaul();
}
searching(teamName){
console.log("teamName: ", teamName)
}
onChange = event => {
this.setState({ [event.target.name]: event.target.value });
console.log(this.state)
};
render() {
const {
teamName,
error
} = this.state;
const isInvalid = teamName === '';
return (
<form onSubmit={this.onSubmit}>
<input
name="teamName"
value={teamName}
onChange={this.onChange}
type="text"
placeholder="Team Name"
/>
<button type="submit">Search</button>
</form>
);
}
}
Why do I have this behaviour?
Thank you.
There is a typo in your code
event.preventDefaul();
instead of
event.preventDefault();
and it should be the first line in the onSubmit function.
there is a typo instead of event.preventDefaul(); it should be
event.preventDefault().
and it used to be in the first line of your method.
Firstly you have to call event.preventDefault(); at first line of onsubmit function.
secondly their is typo error in preventDefault
Please use under given code:
onSubmit = event => {
event.preventDefaul();
const { teamName } = this.state;
this.searching(this.state.teamName);
}
The input doesn't change it's text. It comes pre-filled from the database. For example, if it comes with the text: example, if I press for example the s key, it console logs examples but in the DOM in is still example. Here is the handle code:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
console.log(event.target.name);
console.log(event.target.value);
};
and the input field:
<input
type="text"
className="form-control"
name="note"
id=" note"
value={this.state.insurance.note}
onChange={this.handleChange}
/>
EDIT (fixed the render problem, but I don't get the data that I want when I submit the form)
Here is the code for my form:
handleSubmit = event => {
event.preventDefault();
var state = this.state;
axios
.put(`${API_URL}/` + state.id + `/update`, {
tip: state.tip,
date_exp: state.date_exp,
date_notif: state.date_notif,
note: state.note
})
.then(response => {
console.log(response.data);
// window.location = "/view";
})
.catch(error => {
console.log(error);
});
}
and my button is a simple submit button:
<button className="btn btn-success" type="submit">Save</button>
imjared's answer is correct: your problem is in the handleChange function, where you wrongly update the state.
That function should be something like the following one:
handleChange = event => {
const insurance = Object.assign({}, this.state.insurance);
insurance[event.target.name] = event.target.value;
this.setState({insurance});
};
In the first line of the function, you create a deep copy of the current object insurance saved in the state. Then, you update the copied object, and finally update the state.
You're changing this.state.note based on the name property of your input so it makes sense that this.state.insurance.note wouldn't see any updates.
If you try console.logging this.state above your <input>, I bet you'll see what you're after.
I am trying out with a small react app, with a form based data capture, after keying in the values, when user clicks submit button, values need to be captured in state variable. But, state variable contains null value in handleSubmit function. For clarity, code snippets are given below,
Constructor code, for the sake of completeness/clarity,
constructor(props)
{
super(props);
this.state = {
username : '',
};
}
handleChange function is where I set state variable,
handleChange = (event) => {
this.setState( [event.target.username]: event.target.value );
}
handleSubmit function is where, I print state variable, which contains null value, instead of user inputted value.
handleSubmit = () => {
console.log(this.state.username);
}
Component's render function is given below, which invokes handleChange
and handleSubmit.
render() {
return(
<div>
<form>
<label>
Title:
<input
type = "text"
name="username"
onChange={event => this.handleChange(event)}/>
</label>
<button
label="Submit"
onClick={this.handleSubmit}>
Submit
</button>
</form>
</div>
)};
I am missing on something. I am new to react. Kindly advise.
you need setState's argument to be an object.
handleChange = (event) => {
this.setState({ [event.target.username]: event.target.value });
}
Given the source code for a simple login form, see below. You see I want to use the username text field's value when I click the form's submit button. Since I need a reference to the actual DOM node to retrieve the value, I'm setting the usernameElement variable to that node.
const Login = ({ onLogin }) => {
let usernameElement
const handleSubmit = event => {
event.preventDefault()
onLogin(usernameElement.value)
}
return <form onSubmit={handleSubmit}>
<input
type="text"
name="username"
ref={node => { usernameElement = node }}
/>
<button type="submit">Login</button>
</form>
}
So, how would I make an functional approach to that problem, or simply get rid of the let variable?
Apparently, the correct approach to this is to make use of the component's state, meaning you need a stateful component instead of the stateless one.
// untested
class Login extends Component {
state = { username: '' }
handleChange = event => {
this.setState({ username: event.target.value })
}
handleSubmit = event => {
event.preventDefault()
this.props.onLogin(this.state.username)
}
render = () =>
<form onSubmit={this.handleSubmit}>
<input
type="text"
name="username"
value={this.state.username}
onChange={this.handleChange}
/>
<button type="submit">Login</button>
</form>
}
Using this, the username is always bound to this.state.username. The handleSubmit method can just use the username from the component's state.
See this page for further information: https://facebook.github.io/react/docs/forms.html