I need to empty an input field in my react component after the content has been stored to the DB. This is what I did so far:
addPost (event) {
const content = event.target.value
methodInsert.call(
{ content },
(error) => {
if (!error) {
event.target.value = ''
}
}
)
}
render()
<Input
onBlur={this.addPost.bind(this)}
/>
I am getting the error
Warning: This synthetic event is reused for performance reasons.
If you're seeing this, you're accessing the property `target` on a released/nullified synthetic event. This is set to null.
If you must keep the original synthetic event around, use event.persist().
You will need an onChange handler on your input that updates the state of the component when anything changes. You'll also need a onSubmit handler to handle your submit logic and then clear the input by using this.setState to set it's value to empty.
I recommend you read about Controlled Components in the React documentation.
Here is an example of how this can be accomplished:
class Example extends React.PureComponent {
constructor( props ) {
super( props );
this.state = {
inputValue = ""
}
this.handleChange = this.handleChange.bind( this );
this.handleSubmit = this.handleSubmit.bind( this );
}
handleChange( e ) {
this.setState({
inputValue: e.target.value
});
}
handleSubmit( e ) {
e.preventDefault();
// .. do your stuff and then
this.setState({
inputValue: ""
});
}
render() {
<form onSubmit={ this.handleSubmit }>
<input type="text"
placeholder="Controlled input"
onChange={ this.handleChange }
value={ this.state.inputValue } />
<button>Submit</button>
</form>
}
}
Related
I created a simple form here https://codesandbox.io/s/xenodochial-frog-7squw
It says You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue.
But there is an onChange handler being passed, so I don't understand. In addition the page reloads when I hit submit, even though preventDefault() is called
Thank you
The issue is this line:
const { str, handleChange, handleSubmit } = this.state;
handleChange and handleSubmit are not part of the state, but are instance methods, so you can pass them like so:
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
On line 25 you do:
const { str, handleChange, handleSubmit } = this.state;
Because of this, handleChange will be bound to this.state.handleChange which will be undefined as you have no property handleChange in your state.
You also forgot to pass the prop name to your Table-component.
I forked your code and updated it here: https://codesandbox.io/s/modest-meninsky-y1sgh
here is the correct Code for you:
import React from "react";
import "./styles/styles.css";
import Form from "./components/Form";
import Table from "./components/Table";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { str: "", desc: false };
console.log(4444);
this.handleChange = this.handleChange.bind(this); //<-- this binding
}
handleSubmit = event => {
event.preventDefault();
console.log("submitted");
};
handleChange = event => {
this.setState({ str: event.target.value });
};
render() {
const { str } = this.state; // <-- FIXED THIS
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
}
}
export default App;
I am looking at a tutorial for binding input in react with state. What I don't understand is why do I need to bind it to the state vs just a local vairable since it won't cause renders.
In my case I have a login form, in the tutorial it is sending message form. The idea is that the value is send to the App.js(parent) on submit using inverse data flow. It looks like this:
class Login extends Component{
constructor(){
super()
this.state = {
username: ''
};
this.login = this.login.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({
username: e.target.value
});
}
//here I make a post request and then I set the user in app.js
handleSubmit(e) {
e.preventDefault();
fetch('http://localhost:8080/login', {
method: 'post',
body: JSON.stringify(username)
}).then(data => data.json())
.then(data => {
this.props.setUser(data)
this.setState({
username: ''
})
}
}
render(){
return (
<section>
<form onSubmit={this.submit}>
<input placeholder="username"
onChange={this.changeInput} type="text"
value={this.state.username}/>
</form>
</section>
)
}
Is there a reason to use setState vs just a local variable which won't cause a rendering?
You don't have to, you could make it work without ever storing username in the state. All you have to do is listen for a submit event and fetch the input value at that time, using a ref.
class Login extends Component {
handleSubmit(e) {
e.preventDefault();
console.log(this.refs.username.value)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input ref="username" type="text" />
<button type="submit">Submit</button>
</form>
);
}
});
However the usual way to do that with React is to store the input value in the state and update the state every time the value change. This is called a controlled component and it ensures that the input value and the state are always consistent with each other.
class Login extends Component {
constructor() {
super()
this.state = {
username: ''
};
}
handleChange(e) {
this.setState({
username: e.target.value
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input onChange={e => this.setState({ username: e.target.value })} type="text" value={this.state.username} />
<button type="submit">Submit</button>
</form>
</div>
)
}
}
Among other things, it makes things easier to validate the input value or modify it if you need. For instance, you could enforce uppercase by converting the state to uppercase whenever the state changes.
The value of the input field has to change to the new value, that is why for the on change event you set the state to the next event value. If you don't set state, the value will be the same even though it is entered by user.
Hope this helps,
Happy Learning.
I have an input field component that meets these conditions:
Upon first focus, nothing happens until the field is valid, then a valid class is applied
Upon first blur, if the field is invalid, apply an invalid class.
After the first blur, upon any further engagement with the field, a class is applied whenever the value of the field changes from valid to invalid or vice versa.
To achieve this I have done this:
import React, { Component } from "react";
class Input extends Component {
constructor(props) {
super(props);
this.state = {
touched: false,
valid: false,
focused: false,
value: ""
};
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleFocus() {}
handleBlur() {
if (!this.state.touched) {
this.setState({
touched: true
});
} else if (this.state.touched) {
this.setState({
focused: true
});
}
}
handleChange(e) {
const val = e.target.value
this.setState({ value: val }, () => {
this.validateField();
}
);
}
validateField() {
const touched = this.state.touched;
const focused = this.state.focused;
const valid = this.state.valid;
const value = this.state.value;
if (value.length >= 5) {
this.setState({
valid: true,
touched: true
});
} else {
this.setState({ valid: false });
}
}
render() {
return (
<div>
<input
id={this.props.id}
name={this.props.name}
type="text"
className={`form-control ${styles["kyi-input"]} ${
this.state.valid ? "is-valid" : ""
} ${this.state.touched && !this.state.valid ? "is-invalid" : ""}`}
required
spellCheck="false"
autoComplete="off"
onFocus={this.handleFocus}
onChange={this.handleChange}
value={this.state.value}
onBlur={this.handleBlur}
placeholder={this.props.placeholder}
/>
</div>
);
}
}
class Parent extends Component {
handleInput(val, name) {
// Can get value of input here
this.setState({
[name]: val
});
}
render() {
<Input placeholder="Test" onChange={(val) => {this.handleInput(val, 'inputName')}}/>
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
It works, but this means that the state of the field lives in the child component and not the parent.
The input field's onBlur function is reliant on the state of the field.
Is there a way to refactor this so that the input state lives in the parent component while the onBlur function lives in the child component?
I think you should get all your State in the Parent component, you should also get all the functions that modify it in the Parent Component. This would allow you to have a 'single source of truth' that keeps track of state's changes and pass it to all your child components.
Check out Lifting state up
I have 3 inputs whose value I save and click on my btn, I would like to clear these inputs.......
my function that saves the value of one of my inputs:
onChangeIdentity = (event) => {
this.newPlayer = Object.assign({}, this.newPlayer, { strPlayer:
event.target.value})
}
my input:
<Input style={{width:'30%'}} onChange={ this.onChangeIdentity }
ref='myFormRef' value={ this.newPlayer.strPlayer } type='text'
placeholder='Nom & Prenom'/>
and the function that must clear my input:
addPlayer = () => {
console.log('my new Player: ' , this.newPlayer);
this.setState({
teamPlayers: [...this.state.teamPlayers, this.newPlayer]
})
this.refs.myFormRef.value = ""
}
I tried several ways to declare my refs but nothing works.....
any ideas?
You input's values are driven by the state of the component value={this.newPlayer.strPlayer}. If you want to clear the input's value you need to clear the state which maps to it, for example:
this.setState({newPlayer: {strPlayer: ''}});
After setting the state, the component updates automatically and renders the input as empty.
Here is a full example component:
class MyComponent extends Component {
state = {
inputValue: ""
};
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
onChange={event => this.setState({ inputValue: event.target.value })}
/>
<button
onClick={() => {
/* submit this.state.inputValue */
this.setState({ inputValue: "" }); // reset input value
}}
>
submit
</button>
</div>
);
}
}
I am new to React and learning it on my own, I am trying to implement a simple form where the user can provide a name and it will then be store is the state. Once he stop typing and clink on send the the name is store and the fields is
in the input is reset not the state.
This is what i tried and i get
an error saying that cannot read property "then"
changeFun = (e) => {
this.setState({name: e.target.value})
}
submitFun = (e) => {
e.preventDefault()
this.setState({ name: e.target.value})
}
render() {
return (
<input type = "text" value={this.state.name}/>
<button
onSubmit = {(e) =>
this.submitFun(e).then(
() => reset()
)
onchange ={this.changeFun}}>
SEND
</button>
)
}
submitFun is not returning a promise. So you can't use .then after it.
submitFun = (e) => {
e.preventDefault()
// this.setState({name: e.target.value}) should not be here
// because e.target is <button/>
this.setState({name: ''}) // This will reset the input value
}
<button onClick = {this.submitFun} onchange ={this.changeFun}>SEND</button>
In addition you need to use onClick instead of onSubmit for <button> tag.
onSubmit will be used for <form> tag.
what are you trying to achieve is called Controlled Component! more info here.
the base of Controlled Component is basically you have a property in your state and a form element (i.e and input element). then you chain that input value to your state by a function, and that function is going to run on onChange event, to update the state on every change.
something like this:
class App extends React.Component {
constructor(props) {
super()
this.state = {
inputValue: ""
}
}
handleChange = e => {
const _tempValue = e.target.value
e.preventDefault()
this.setState({inputValue: _tempValue})
}
handleSubmit = e => {
const {inputValue} = this.state
e.preventDefault()
// here is your data
// save it to redux or do what ever you want to
console.log(inputValue)
// last thing here is gonna be to reset state after submition
this.setState({inputValue: ""})
}
render() {
const {inputValue} = this.state
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
value={inputValue}
onChange={this.handleChange}
placeholder="type something"
/>
<input type="submit" />
</form>
<p>{inputValue}</p>
</div>
)
}
}
this is a basic implementation of what you want to do, its here: https://codesandbox.io/s/m39w10olnp
on the example that you provide though , you using then that is basically used when that you returning a promise from a function, something like this:
export const giveMeArray= () => {
return new Promise( (res,rej) => {
setTimeout(() => {
res(Object.assign([], myArray))
}, delay);
})
}
so as you can see there is no need to use then here, check my simple example to implement in a better way!