I have an input field where the user enters a name, and I then want this name to be display at all times on the navbar. After entering a name the user presses a button that takes them to a new screen via react-router-dom like this
<Link to="/events">
<button type="submit" className="btn btn-primary">Sign in</button>
</Link>
This is what I have right now
In my component with the input field
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
console.log(this.state);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="email"
className="form-control"
id="inputEmail3"
placeholder="Enter your username"
onChange={this.handleChange}/>
)
}
}
I removed anything that doesn't have to do with the particular input field, which is why the return statement looks the way it does.
With what I have now, I get the input field value as a state, but I'm not sure how to get that value in another component.
I then have a Navbar component where I have a simple <p className="">Username</p> where I want the name to be displayed.
Any help on how to achieve this?
Related
The handleSubmit function seems to refresh the page without firing any of the internal logic. I've set up a few console.log's along the way to test out if the internally declared const that's set to the venue property in the state would log, but nothing appears.
I've commented on various parts of the function stepwise starting with setting the scheduling variable to my Firebase schedule table.
After that, I changed the handleSubmit function from an arrow function to just handleSubmit(e) (sorry, I'm new to this so I'm not familiar with the terminology)
import React, {Component} from 'react';
import FrontNav from './nav.js';
import firebase from '../Firebase';
class FrontSchedule extends Component {
constructor () {
super();
this.state = {
venue:'',
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
e.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
return(
<div>
<FrontNav/>
<h1>Schedule</h1>
<form>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<button onSubmit={this.handleSubmit}> Enter Event </button>
</form>
</div>
);
}
}
export default FrontSchedule;
Herein lies the crux of the problem. The page refreshes and the input bar clears, but no error message is provided. At this point, I'm really confused about what is going on here. Any feedback is appreciated!
Let us consider the following example:-
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
Now, when we press on submit button the default behavior to browse to a new page. If you want this behavior it works out of the box in ReactJS. But in cases where you need more sophisticated behavior like form validations, custom logic after the form is submitted you can use controlled components.
We can do so by using following:-
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
Now coming to your solution it can be implemented as follows:-
class FrontSchedule extends React.Component {
constructor () {
super();
this.state = {
venue:'',
}
/* this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); */
}
handleChange = (e) => {
e.preventDefault();
this.setState ({
venue: e.target.value,
});
}
handleSubmit = (e) => {
event.preventDefault();
// let schedule = firebase.database().ref('schedule')
const item = {
venue: this.state.venue,
}
console.log(item);
// schedule.push(item);
// console.log(firebase.database().ref('schedule'));
console.log(this.state.venue);
// this.setState({
// venue:'',
// })
}
render(){
console.log(this.state);
return(
<div>
<h1>Schedule</h1>
<form onSubmit={this.handleSubmit}>
<input type="text"
name="venue"
onChange={this.handleChange}
onSubmit={this.handleSubmit}
value={this.state.venue}/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
ReactDOM.render(<FrontSchedule />, document.querySelector("#app"))
Hope it helps :)
You can read more at react documentationhere
Based on the React Forms documentation, I am wondering why the following example is valid ?
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
As this.setState is asynchronous, you could have a change and a submit event that follow each other, so you would obtain the following senario : :
change event emitted
submit event emitted
handleChange is called, so this.setState is called, as it's asynchronous the state is not updated immediately
handleSubmit is called, this.state.name doesn't refer to the last value typed into the input field as the state update hasn't been applied yet.
The state is updated
So if my understanding is correct, in this example, the handleSubmit is not guaranteed to revrieve the last value typed into the input field ?
I currently have an input field set up so the inputs value will be console logged when a button is pressed, I am trying to render a component instead of this console.log.
I can get it to sorta work but it re-renders every time I type a single character because I'm not sure how to check for the click within the render method, I read through some of the docs but couldn't figure out how do to it. How could I go about achieving this?
here is the code
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
console.log(this.state.input)
}
render() {
//Not sure how to check for this
if (this.state.input) {
return <Fetch username={this.state.input} />
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
let me know if you need anymore information. Thanks!
Edit: By the way, I want to be able to submit the form many times, sorry, I should have been more descriptive of my problem. I want the Form component to stay rendered and I want the Fetch component to get rendered on clicked
A solution depends on your needs and there might be a lot of them. The simplest way, just to demonstrate:
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false, // adding the flag
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true }); // set the flag on submit
console.log(this.state.input)
}
render() {
//Not sure how to check for this
if (this.state.submitted) { // show the component by the flag
return <Fetch username={this.state.input} />
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
Obviously, in real application it's too simple logic. You have to define first, what are you trying to reach.
UPDATE:
If you want to keep the input field and the component simultaneously, you can do it like this:
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false, // adding the flag
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true }); // set the flag on submit
console.log(this.state.input)
}
render() {
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
{this.state.submitted && (
<Fetch username={this.state.input} />
)}
</form>
);
}
}
Actually what you are doing is every time the user type a character, you are displaying Fetch component with the input's value passed in props.
With this and with the handleChange method
if (this.state.input) {
return <Fetch username={this.state.input} />
}
The condition here return true if input is different from "". So when a character is type it becomes true and displays it.
In your case what you want to do is to display the Fetch component when you are clicking on the submit button.
What you can do is create a state to manage it.
For example you could have this in your state :
this.state = {
input: '',
fetchIsVisibile: false,
};
Then in your handleSubmit just do this:
handleSubmit(e) {
this.setState({ fetchIsVisible: true }),;
e.preventDefault();
}
And the condition for display your fetch component would be using this new state instead of input state
if (this.state.fetchIsVisible) {
return <Fetch username={this.state.input} />
}
You can add state whether the form is submitted in the state and to check for it when rendering the component
if you want to check whether the form is submitted and the input is not empty you can use (this.state.submitted && this.state.input) instead
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
this.setState({
submitted: true
});
}
render() {
//Not sure how to check for this
if (this.state.submitted) {
return <div>
<div>FETCH COMPONENT</div>
<div>input: {this.state.input}</div>
</div>
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<div>input: {this.state.input}</div>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
ReactDOM.render(<Form />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
I have 2 React parent/child components. The Child Component has a button that adds +1 to the previous state of the Parent Component, and a Form that triggers a handleChange function for the onChange event.
The Problem
From the Form input, I want to trigger a function that sets the State to the previous State, + the input in the Form.
For example, if I write 50 in input and hit submit I want the new state be 100
Here is a codesandbox: https://codesandbox.io/s/30mz2vvyo1
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 50
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState((prevState) => {
return { value: prevState.value + 1 }
});
}
handleSubmit(event) {
event.preventDefault();
}
render() {
return (
<div>
<Child value={this.state.value} handleChange={this.handleChange} handleSubmit={this.handleSubmit} />
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<div>
<button onClick={this.props.handleChange}>Count + 1</button>
<div>{this.props.value}</div>
<form onSubmit={this.props.handleSubmit}>
<label>
Name:
<input type="text" onChange={this.props.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
The problem you are facing can be mitigated by;
You need to have two different variables in state. value, can hold your value. You also need to hold the current value of the input, let's call it inputNumber.
You need to provide an onClick function to your button. In said function, set your state in the following fashion;
Code:
this.setState({
value: this.state.value + this.state.inputNumber,
})
After doing these things, it should work as expected.
I have updated your codesandbox, you can take a look at it here.
Am trying to build form inputs in reactjs. the code below works for just one form inputs.
Now I want to add two more form inputs as per
Firstname <input type="text" id="fname" name="fname"><br>
Lastname <input type="text" id="lname" name="lname"><br>
below is the working code that I want to implement the two form inputs above.
source
https://reactjs.org/docs/forms.html
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
The best way I've found to manage forms in React is to make sure each of your <input> tags has a name value. Then ensure that your component's state has fields for each input that matches the name exactly.
In your onChange handler, you can then say:
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
This will update the state with change to any of the inputs, and apply the change to that specific state value.
Then for handleSubmit, you send those values from state to where ever you need to process the form information.
try this one
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}