Following my first React tutorial. My code seems to be exactly like the tutorial, but my input doesn't reset within a form component. The first time I submit, everything works fine, but the state holds onto the first value. Even when calling setState with a console.log in a callback, it seems like setState doesn't even fire. this is bound in my constructor function.
import React, { Component } from 'react';
import TenantActions from '../actions/TenantActions';
export default class AddTenantForm extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
}
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(event) {
event.preventDefault();
console.log('1. On Submit click, sending addNewTenant action w/', this.state);
TenantActions.addNewTenant(this.state);
this.setState = ({ name: '' });
}
render() {
return (
<form>
<div className="form-group">
<input type="text"
className="form-control"
id="tenantName"
placeholder="Bob Smithers"
value={this.state.name}
onChange={e => this.setState({ name: e.target.value })}
/>
</div>
<button className="btn btn-default"
onClick={this.onSubmit}
>Submit</button>
</form>
)
}
}
this.setState is a function. You have a typo (= extra) in the function onSubmit.
Replace this.setState = ({...}) with this.setState({name: ''})
More about setState
Related
import React, { Component } from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
console.log(this.state.value);
this.setState({ value: event.target.value });
}
render() {
return (
<form>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
console log screenshot
I'm getting first input value empty. I have different app. I'm basically try to doing tip calculator app. I don't need submit button. The user will enter a value, but it does not calculate correctly because the first value is empty. At the same time, it does not show the last value entered, only when clicked, all the entered values are correct. By the way, i got this form from React own site, but it's the same error that i encountered. Thank you!
Your console.log logs the value before you change it. Thus it will always be the previous value.
You also have to keep in mind that the Component.setState method might not execute immediately.
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
Therefore you should use a callback. E.g.
handleChange(event) {
this.setState({ value: event.target.value }, () => {
console.log(this.state.value);
});
}
Here is an executable example. Click Run code snippet.
class App extends React.Component {
constructor(props) {
super(props);
this.state = { value: "" };
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value }, () => {
console.log(this.state.value);
});
}
render() {
return (
<form>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Set initial value to 0 so that it will not be empty.
this.state = { value: 0 };
Also move your console.log as callback function to setState so that you can see the updated value.
import React, { Component } from "react";
export default class App2 extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value }, () => {
console.log(this.state.value);
});
}
render() {
return (
<form>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
I tried to load a component to my web app after submitting a form. However, the value doesn't persist on the web page for more than a few seconds.
import React,{Component} from 'react';
import Load from './load'
class Form extends Component {
constructor(props) {
super(props);
this.state = {value: '',
showComponent: false,
};
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);
this.setState({
showComponent: true,
});
}
render() {
return (
<div>
<form onSubmit={this._handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
{this.state.showComponent ?
<Load /> :
null
}
</div>
);
}
}
export default Form
The code for Load is as follows
import React,{Component} from 'react';
class Load extends Component {
render() {
return (
<p>hello</p>
)
}
}
export default Load
As I had said, the value of hello doesn't stay on my screen for more than a few seconds. Please help. I am very new to react
Just try preventing default Submit Event of the form this will initiate a GET request and your URL will reload and this will lead to your main component ReRendering and showComponent is being set to false again.
_handleSubmit(event) {
event.preventDefault(); // Add this line to prevent your form's default event.
//alert('A name was submitted: ' + this.state.value);
this.setState({
showComponent: true,
});
}
I implemented a simple Login Form in React with Redux following this tutorial: https://jslancer.com/blog/2017/04/27/a-simple-login-flow-with-react-and-redux/
Everything works, but when I add cookies I get the error:
Warning: Cannot update during an existing state transition (such as
within render). Render methods should be a pure function of props
and state.
and also:
Uncaught Invariant Violation: Maximum update depth exceeded. This can
happen when a component repeatedly calls setState inside
componentWillUpdate or componentDidUpdate. React limits the number of
nested updates to prevent infinite loops.
I did some debugging and if I remove onChange={e => this.setState({password: e.target.value})} from the inputs in the code below the error disappears.
Any ideas why the following code is not working?
import { connect } from 'react-redux';
import { withCookies } from 'react-cookie'
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: ''
};
}
render() {
let {username, password} = this.state;
let { cookies, allCookies, isLoginPending, isLoginSuccess, loginError} = this.props;
cookies.set('username', 'Ross', { path: '/', secure: true, httpOnly: true});
console.log(cookies.get('username'));
return (
<form name="loginForm" onSubmit={this.onSubmit}>
<div className="form-group-collection">
<div className="form-group">
<label>Username:</label>
<input type="text" name="username" onChange={e => this.setState({username: e.target.value})} value={username}/>
</div>
<div className="form-group">
<label>Password:</label>
<input type="password" name="password" onChange={e => this.setState({password: e.target.value})} value={password}/>
</div>
</div>
</form>
)
}
}
const mapStateToProps = (state) => {
return {
isLoginPending: state.isLoginPending,
isLoginSuccess: state.isLoginSuccess,
loginError: state.loginError,
};
}
export default withCookies(connect(mapStateToProps, null)(LoginForm));```
My guess is that because your component it connected to the cookies HoC and then you are calling cookies.set in the render method, it is updating itself every time, creating an infinite loop. Please try moving cookies.set to componentDidMount.
I tried to create a custom input component with inputRef (material ui Input component). Looks like the component reference is working but I'm unable to enter any value in the text field after i set the value attribute. I think it's because of the way i implemented the onchange event. I'm not sure what am i missing. Please help.
Here is the codesandbox url
https://codesandbox.io/s/pjlwqvwrvm
Actually you don't need a onChange prop to for get the changed value..
Just get the value from onchange and set the value in state value.
Another mistake is you are not created the constructor, and gave this.props.value to the value prop. That's it not get updated..
Now I created the constructor and give the this.state.value to the value props.
Now you get your onchanged value in custominput component and your submit function also..
import React from "react";
import { render } from "react-dom";
import { Input } from "material-ui-next";
import trimStart from "lodash/trimStart";
import PropTypes from "prop-types";
const defaultProps = {
state: "",
onChange: () => {} // no need
};
const propTypes = {
state: PropTypes.string,
onChange: PropTypes.func
};
class App extends React.Component {
constructor() {
super();
this.state = {
value:''
}
}
handleSubmit(event) {
event.preventDefault();
console.log("state: " + this.state.value); //shows onChanged value in console
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
<CustomInput
labelText="State"
id="state"
value={this.state.value}
onChange={e=> {
this.setState({value:e.target.value})
}}
/>
</form>
</div>
);
}
}
App.propTypes = propTypes;
App.defaultProps = defaultProps;
class CustomInput extends React.Component {
render() {
const {
classes,
formControlProps,
value,
onChange,
labelText,
id,
labelProps,
inputRef,
inputProps
} = this.props;
return (
<div {...formControlProps}>
{labelText !== undefined ? (
<div htmlFor={id} {...labelProps}>
{labelText}
</div>
) : null}
<Input
classes={{
root: labelText !== undefined ? "" : classes.marginTop
}}
id={id}
value={value} ///////// Fixed ////////
onChange={onChange}
inputRef={inputRef}
{...inputProps}
/>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Here is code in sandbox check it..
https://codesandbox.io/s/84rjk4m8l8
You can either go on inputRef - then your value and onChange event are extra - it is called uncontrolled Component. You can see more about it here: https://reactjs.org/docs/uncontrolled-components.html
Or you can do it with value & onChange event - and work with controlled components, you can find more about controlled components here: https://reactjs.org/docs/forms.html#controlled-components
How to solve it (uncontrollable) with inputRef:
class App extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
console.log("input value: ", this.input.value); // will now show you correct input value
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<CustomInput
labelText="State"
id="state"
inputRef={input => {
this.input = input;
}}
/>
<Button onClick={this.handleSubmit} color='primary'>Submit</Button>
</form>
</div>
);
}
}
Instead of "this.state = input", bind input to something else, because this.state is reserved for local state of React Component, and it won't work with it, not like that.
How to solve it (controllable) with state, value & onChange event:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.state || ''
}
}
handleSubmit = (event) =>{
event.preventDefault();
console.log("state: ", this.state.value); // will now show you correct input value
}
handleChange = (event) => {
this.setState({value: event.target.value});
}
render() {
const {value} = this.state;
return (
<div>
<form onSubmit={this.handleSubmit}>
<CustomInput
labelText="State"
id="state"
onChange={this.handleChange}
value={value}
/>
<Button onClick={this.handleSubmit} color='primary'>Submit</Button>
</form>
</div>
);
}
}
Note that I added the constructor and defined the local state for component, and I'm changing value inside of state with this.setState (because state is immutable, and that's the right way to update it).
In both examples, you are able to get input value inside of handleSubmit method, will you work with controllable or uncontrollable components, it's up to you :)
Use value={this.state} or value={this.value}
Here is Your sandbox code Updated
https://codesandbox.io/s/qqk2qoxmlj
In my case, I was mistakenly using state from parent component in child component, since I had declared child component inside parent itself. Moving whole state to child component solved the problem.
i am just trying first something simple like only printing the this.state.validForm in the handleSubmit function, but i cant seem to access this.state.validForm. First i tried directly then with this function, but to no avail. I am new to react.
import React, { Component } from 'react';
import TextInput from './TextInput';
class RequestForm extends Component {
constructor(props) {
super(props);
this.state = {validForm : "false"};
this.getInfoForm = this.getInfoForm.bind(this);
}
getInfoForm() {
return this.state.validForm;
}
handleSubmit(event) {
event.preventDefault();
console.log('submit values are');
console.log(event.target.src.value);
console.log(event.target.email.value);
console.log(this.state.validForm);
console.log(this.getInfoForm());
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<TextInput
uniqueName="email"
name="email"
text="Email Address"
required={true}
minCharacters={6}
validate="email"
errorMessage="Email is invalid"
emptyMessage="Email is required"
/>
<TextInput
text="User"
name="User src"
required={true}
minCharacters={3}
validate="notEmpty"
errorMessage="Name is invalid"
emptyMessage="Name is required"
/>
<button type="submit">Submit</button>
</form>
);
}
}
export default RequestForm;
The issue is with your render method. Your onSubmit event has its own context so when you do this.handleSubmit, you're going to be passing the wrong context to handleSubmit. Simply bind this and you'll be set!
<form onSubmit={this.handleSubmit.bind(this)}>
Or with the proposed bind operator:
<form onSubmit={::this.handleSubmit}>