I have small class in react, i want to display the result on the screen after i click on the button, but before the display happens, the page reload.
how do i do it?
what am I missing?
import React, {Component} from 'react';
class InputFieldWithButton extends Component{
constructor(props){
super();
this.state = {
message: ''
};
}
handleChange(e){
this.setState({
message: e.target.value
});
}
doSomething(e){
return(
<h1>{this.state.message}</h1>
)
}
render(){
return (
<div>
<form >
<input type="text" placeholder="enter some text!" value=
{this.state.message}
onChange={this.handleChange.bind(this)}/>
<button onClick={this.doSomething.bind(this)}>Click me</button>
</form>
</div>
)
}
}
export default InputFieldWithButton;
Your button is inside a form and triggering a submit.
You can use the preventDefault() method to stop it from doing so:
doSomething(e) {
e.preventDefault();
return (
<h1>{this.state.message}</h1>
)
}
By the way, your return statement of this click handler makes no sense at the moment.
Edit
As a followup to your comment:
Can you explain me what is my mistake in the return?
Not really a mistake, but it is useless in this context as your are not doing anything with the returned object.
Where and how do you expect to use the <h1>{this.state.message}</h1> that you are returning?
If you intend to show / hide the input message in your screen you could do it with conditional rendering.
Just store a bool like showMessage in your state and render the message only if it's set to true.
Here is a small example:
class InputFieldWithButton extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
showMessage: false
};
}
handleChange = (e) => {
this.setState({
message: e.target.value
});
}
toggleMessage = (e) => {
e.preventDefault();
this.setState({ showMessage: !this.state.showMessage })
}
render() {
const { showMessage, message } = this.state;
return (
<div>
<form >
<input
type="text"
placeholder="enter some text!"
value={message}
onChange={this.handleChange}
/>
<button onClick={this.toggleMessage}>Toggle Show Message</button>
{showMessage && <div>{message}</div>}
</form>
</div>
)
}
}
ReactDOM.render(<InputFieldWithButton />, document.getElementById('root'));
<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="root"></div>
By the way, it is considered as bad practice to bind the functions inside the render method, because you are creating a new instance of a function on each render call. instead do it inside the constructor which will run only once:
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
Or you can use arrow functions which will reference this in a lexical context:
handleChange = (e) => {
this.setState({
message: e.target.value
});
}
This is what i've used in my example.
you're not specifying the buttons'type
<button type="button">
Set the type attribute on the button to be button. The default is submit since it is wrapped in a form. So your new button html should look like this:
<button type="button" onClick={this.doSomething.bind(this)}>Click me</button>
Related
I am simply trying to get the text from the input field for which handler function is attached to a button and then just trying to store in input value into the state object.
But the state object doesn't store that value
class EditTextArea extends React.Component {
constructor() {
super();
this.state = {
message: "",
};
this.handleButton = this.handleButton.bind(this);
}
handleButton(e) {
const text = e.target.previousElementSibling.value;
this.setState({ message: text });
console.log(this.state);
}
render() {
return (
<div>
<form>
<input type="text" name="customText" />
<button type="button" onClick={this.handleButton}>
Send
</button>
</form>
</div>
);
}
}
ReactDOM.render(<EditTextArea />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
Nothing in your render is using this.state.message, so you're not going to see anything happen. (Note that if you're wondering about the console.log of state, see this question's answers; the update is asynchronous.)
If you actually use message, you see that it works:
class EditTextArea extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "",
};
this.handleButton = this.handleButton.bind(this);
}
handleButton(e) {
const text = e.target.previousElementSibling.value;
this.setState({ message: text });
}
render() {
return (
<div>
<div>
Message is: {this.state.message}
</div>
<form>
<input type="text" name="customText" />
<button type="button" onClick={this.handleButton}>
Send
</button>
</form>
</div>
);
}
}
ReactDOM.render(<EditTextArea />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
Also note that you need to accept a parameter in your constructor and pass it to super(); see above. That wasn't the problem, but it still still incorrect.
That said, I wouldn't do it that way. If you want an uncontrolled input, use a ref to access its value so you don't have to do the DOM traversal, which is easily broken with a small change to render:
class EditTextArea extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "",
};
this.handleButton = this.handleButton.bind(this);
this.inputRef = React.createRef(null);
}
handleButton() {
const text = this.inputRef.current.value;
this.setState({ message: text });
}
render() {
return (
<div>
<div>
Message is: {this.state.message}
</div>
<form>
<input type="text" name="customText" ref={this.inputRef} />
<button type="button" onClick={this.handleButton}>
Send
</button>
</form>
</div>
);
}
}
ReactDOM.render(<EditTextArea />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
Or you might consider a controlled component.
More about controlled vs. uncontrolled components hrere. More about refs here.
I run your script so initially, your message state taking an empty state just add a text and click a couple of times so Your message state is updating the second time.
So if you need to dynamic change on input so I suggest you right an input handler and call it into the input change function and handle it separately.
onInputchange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
I tried your code and it actually worked. But the problem is you cant change state and get changed state in same function, it reads the previus state. Just try to click button 2 times, you will see it works
In react states are updated asynchronously. To check your updated state you can check it by logging in render or in react developer tools.
According to you code you can check code given below
class EditTextArea extends React.Component {
constructor() {
super();
this.state = {
message: "",
};
this.handleButton = this.handleButton.bind(this);
}
handleButton(e) {
const text = e.target.previousElementSibling.value;
this.setState({ message: text });
console.log(this.state);//It will show you old value
}
render() {
console.log("check your updated state",this.state)
return (
<div>
<form>
<input type="text" name="customText" />
<button type="button" onClick={this.handleButton}>
Send
</button>
</form>
</div>
);
}
}
please help me wit this code. I am struggling to update state right away after input is inserted. I was trying to do it with onSubmit method at least to sync input === submit after clicking on Button but still no luck as per console log.
See console picture:
enter image description here
How should I do it?
import React from 'react';
import './Search.css';
const results = ["Balaton", "Zamardi", "Sound", "Madarsko", "Sziget", "Hungary"]
class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
submit: ''
};
this.onInput = this.onInput.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onInput(event) {
this.setState({
input: event.target.value,
submit: this.state.input});
console.log(this.state.input)
console.log(this.state.submit)
}
onSubmit(event) {
event.preventDefault()
if (results.includes(this.state.input)){
return alert("This is correct")
} else {
return alert("This not correct")
}
}
render() {
return(
<div>
<form className="search-form" onSubmit={this.onSubmit}>
<input type="text" value={this.state.input} placeholder="Our great memory" onChange={this.onInput}/>
<button type="submit">Try that!</button>
</form>
</div>
)
}
};
export default Search;
I re-wrote your component for readability, I believe you error is simply that setstate is async. This means that when you tried to set the state of submit at the same time as input, submit would always be one behind. By adding the callback in onInput after input has been set you should get the correct value ready to be submitted
import React, { Component } from 'react';
const results = ["Balaton", "Zamardi", "Sound", "Madarsko", "Sziget", "Hungary"]
class Search extends Component {
state = {
input: '',
submit: ''
};
// Added callback after input setstate
onInput = (event) => {
this.setState({
input: event.target.value}, () => this.setState({submit: this.state.input));
console.log(this.state.input)
console.log(this.state.submit)
}
onSubmit = (event) => {
event.preventDefault()
if (results.includes(this.state.input)){
return alert("This is correct")
} else {
return alert("This not correct")
}
}
render() {
return(
<div>
<form className="search-form" onSubmit={this.onSubmit}>
<input
type="text"
value={this.state.input}
placeholder="Our great memory"
onChange={this.onInput}/>
<button type="submit">Try that!</button>
</form>
</div>
)
}
};
export default Search;
onInput(event) {
this.setState({
input: event.target.value,
submit: event.target.value});,() =>
console.log(this.state.input)
console.log(this.state.submit)
}
This will let you see the correct values in log too.
Your submit state doesn't update as you assign the old value of this.state.input to it rather you should assign event.target.value.
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
I was trying to handle changing of states whenever I type something inside the two text boxes and then when the user click the button, it will set the state to it's state and then console.log the current change state to the console.
Basically I have this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
catname: '',
catamt: 0
};
this.addBudget = this.addBudget.bind(this);
}
addBudget(e) {
e.preventDefault();
this.setState({
catname: e.target.value,
catamt: e.target.value
});
console.log('console log catname here.....', this.state.catname);
console.log('console log catamt here.....', this.state.catamt);
}
}
And then inside my component where the form is sitting:
import React from 'react';
export default class AddBudget extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="cat-input">
<input
type="text"
name="categoryname"
placeholder="Budget Category"
/>
<input
type="number"
name="categoryamount"
placeholder="Target Budget"
/>
</div>
<button onClick={this.addBudget}>+</button>
);
}
}
How do I pass along my input value to my function and console log the change of state?
Something more like that, I recommended using controlled input with react.
You can read more about it here https://reactjs.org/docs/forms.html
An example for you :) https://codesandbox.io/s/2486wxkn9n
First you need to keep track on the value with the state. Second with the form you can handle the submit. This way if a user click the button or press enter you can handle the submit method.
Inside the _handleChange method you receive the event. So this is the input change. If you console.log this value you can see he have the name, the name you pass in the input. This way you can use it as a key variable for your object. So one function for 2 :).
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
catname: '',
catamt: 0
};
this.addBudget = this.addBudget.bind(this);
}
addBudget = (e) => {
e.preventDefault();
console.log('console log catname here.....', this.state.catname);
console.log('console log catamt here.....', this.state.catamt);
}
_handleChange = e => {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
return (
<AddBudget handleChange={this._handleChange} addBudget={this.addBudget} />
)
}
}
export default class AddBudget extends React.Component {
render() {
return (
<div className="cat-input">
<form onSubmit={this.props.addBudget}>
<input
type="text"
name="catname"
onChange={this.props.handleChange}
placeholder="Budget Category"
/>
<input
type="number"
name="catamt"
placeholder="Target Budget"
onChange={this.props.handleChange}
/>
<button type="submit">+</button>
</form>
</div>
);
}
}
Not able to get values of input type using this.refs...
how to get that values from input type
export class BusinessDetailsForm extends Component {
submitForm(data) {
console.log(this.refs.googleInput.value)
}
}
reder() {
return(
<form onSubmit={this.submitForm}>
<Field type="text"
name="location"
component={GoogleAutoComplete}
id="addressSearchBoxField"
ref="googleInput"
/>
</form>
)
}
}
You should avoid ref="googleInput" as it is now considered legacy. You should instead declare
ref={(googleInput) => { this.googleInput = googleInput }}
Inside of your handler, you can use this.googleInput to reference the element.
Then inside of your submitForm function, you can obtain the text value with
this.googleInput._getText()
String refs are legacy
https://facebook.github.io/react/docs/refs-and-the-dom.html
If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput", and the DOM node is accessed as this.refs.textInput. We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. If you're currently using this.refs.textInput to access refs, we recommend the callback pattern instead.
Edit
From React 16.3, the format for creating refs are:
class Component extends React.Component
{
constructor()
{
this.googleInput = React.createRef();
}
render()
{
return
(
<div ref={this.googleInput}>
{/* Details */}
</div>
);
}
}
using ref={ inputRef => this.input = inputRef } is considered legacy now. In React 16.3 onwards, you can use the code below,
class MyForm extends React.Component {
constructor(props) {
//...
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
EDIT: thanks for the comment #stormwild
In case any one is wondering how to implement ref with hooks :
// Import
import React, { useRef } from 'react';
const Component = () => {
// Create Refs
const exampleInput = useRef();
const handleSubmit = (e) => {
e.preventDefault();
const inputTest = exampleInput.current.value;
}
return(
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={exampleInput} />
</label>
<input type="submit" value="Submit" />
</form>
}
getValue: function() {
return this.refs.googleInput.value;
}
I think the more idiomatic way is to use state instead of refs, although it's a little more code in this case since you only have a single input.
export class BusinessDetailsForm extends Component {
constructor(props) {
super(props);
this.state = { googleInput: '' };
this.defaultValue = 'someValue';
this.handleChange = this.handleChange.bind(this);
this.submitForm = this.submitForm.bind(this);
}
handleChange(e) {
const { field, value } = e.target;
this.setState({ [field]: value });
}
submitForm() {
console.log(this.state.googleInput);
}
render() {
return (
<Formsy.Form onSubmit={this.submitForm} id="form_validation">
<Field type="text"
name="googleInput"
onChange={this.handleChange}
component={GoogleAutoComplete}
floatingLabelText="location"
hintText="location"
id="addressSearchBoxField"
defaultValue={this.defaultValue}
onSelectPlace={this.handlePlaceChanged}
validate={[ required ]}
/>
</Formsy.Form>
);
}
}
See https://facebook.github.io/react/docs/forms.html#controlled-components.
Using RN 0.57.8 when tried this.googleInput._getText(), It resulted in error _getText is not a function so i printed this.googleInput in console and found that _getText() is a function inside _root
this.googleInput._root._getText()
this.googleInput._root._lastNativeText - This will return the last state not the current state please be careful while using it.
In 2018 you should write in constructor this:
In constructor of class you should add something like
this.input = React.createRef()
Examples here:
https://reactjs.org/docs/uncontrolled-components.html
I tried the answer above (https://stackoverflow.com/a/52269988/1978448) and found it only worked for me when I put the refs in the state, but not when I just made them properties of the component.
Constructor:
this.state.refs={
fieldName1: React.createRef(),
fieldName2: React.createRef()
};
and in my handleSubmit I create a payload object to post to my server like this:
var payload = {
fieldName1: this.state.refs.fieldName1.current.value,
fieldName2: this.state.refs.fieldName2.current.value,
}
The react docu explains it very well: https://reactjs.org/docs/refs-and-the-dom.html
this is considered legacy:
yourHandleMethod() {
this.googleInput.click();
};
yourRenderCode(){
ref={(googleInput) => { this.googleInput = googleInput }}
};
whereas, this is considered the way to go:
constructor(props){
this.googleInput = React.createRef();
};
yourHandleMethod() {
this.googleInput.current.click();
};
yourRenderCode(){
<yourHTMLElement
ref={this.googleInput}
/>
};
From React 16.2, you can use: React.createRef
See more: https://reactjs.org/docs/refs-and-the-dom.html
1. using ref={ inputRef => this.input = inputRef }
Exam:
import React, { Component } from 'react';
class Search extends Component {
constructor(props) {
super(props);
this.name = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onSearch(`name=${this.name.value}`);
}
render() {
return (
<div>
<input
className="form-control name"
ref={ n => this.name = n }
type="text"
/>
<button className="btn btn-warning" onClick={ this.handleClick }>Search</button>
</div>
);
}
}
export default Search;
ref={ n => this.name = n } Use Callback Refs -> see
Or:
2. this.name.current.focusTextInput()
class Search extends Component {
constructor(props) {
super(props);
this.name = React.createRef();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onSearch(`name=${this.name.current.value}`);
}
render() {
return (
<div>
<input
className="form-control name"
ref={this.name}
type="text"
/>
<button className="btn btn-warning" onClick={ this.handleClick }>Search</button>
</div>
);
}
}
export default Search;
Hope it will help you.