Here is a React class I'm working on:
import React from 'react';
export default class ExpenseForm extends React.Component {
state = {
title: ''
};
onTitleChange = (e) => {
const title = e.target.value;
this.setState(() => ({title}));
};
render() {
return (
<div>
<form>
<input
type='text'
placeholder='title'
value={this.state.title}
onChange={(e) => this.setState(() => ({title: e.target.value}))}
required autoFocus/>
<textarea placeholder='Add a note for your expense'/>
<input type='number' placeholder='amount' required/>
<input type='submit' value='Add Expense'/>
</form>
</div>
);
}
}
This throws an error Uncaught TypeError: Cannot read property 'value' of null when executing onChange.
But when I restructure inner js of onChange into a separate function onTitleChange and calling that function: onChange={this.onTitleChange}, it works perfectly. What could be the reason behind this behavior?
Here you assigned onchange event as onChange={(e) => this.setState(() => ({title: e.target.value}))}, here e.target.value will not work, because its inside the setState() scope.
On expanding your function, we will get
function(e){
this.setState(function(){
return {
title: e.target.value
}
})
}
Here there is no e in function inside setSate(), so e.target.value will be error;
Since you dont want to compare with previous value and only need to set the value to title, you can use like
onChange={(e) => this.setState({title: e.target.value})}
There is no need for an extra function inside setState
I would guess, that your parameter e is not known in the inner arrow function.
You could write it like this:
<input
type='text'
placeholder='title'
value={this.state.title}
onChange={e => this.setState({ title: e.target.value })}
required
autoFocus
/>
That is because of React is utilizing event pooling and setState is a function executed in asynchronous context, so you observe them as nulls in the asynchronous setState callback.
You need to either persist event using e.persist() or save the value of event to variable, as in your method.
You don't need to use arrow function inside setstate.
change
onChange={(e) => this.setState(() => ({title: e.target.value}))}
to:
onChange={(e) => this.setState({title: e.target.value})}
Related
I am having a form that passes values to a useState
I have this showrefid its value is set to either true or false
I want to pass the value of inputs into setAllValues based on true or false of showrefid
if showrefid is false I want to pass a default value that is already prefixed as value sony
{showrefid ? (
<input
name="userid"
onChange={handleChange}
style={styles.input}
type="text"
placeholder="userid"
/>
) : (
<input
name="userid"
value="sony"
onChange={handleChange}
type="text"
readonly="readonly"
/>
)}
const handleChange = (e) => {
setAllValues({ ...allValues, [e.target.name]: e.target.value });
};
You can set a default value to useState whenever the component gets rendered for the first time
const [allValues, setAllValues] = useState(showrefid ? { userid: "sony" } : {})
After that, you can set it directly to the input field
<input
name="userid"
value={allValues.userid}
onChange={handleChange}
type="text"
readonly="readonly"
/>
If showrefid can be modified from other places and you want to update your state accordingly, you can call useEffect
useEffect(() => {
if(!showrefid) {
setAllValues({ ...allValues, userid: "sony" })
}
}, [showrefid])
maybe consider using showrefid variable inside your handleChange function?
const handleChange = (e) => {
setAllValues(showrefid
? { ...allValues, [e.target.name]: e.target.value }
: { /* whatever value you want to set when false */ });
};
I have a simple Input field which gets a value from onComponentMount. Now I want the user to be able to change value but Its not working. Here is my code:
componentDidMount = async () => {
const IPAddress = await publicIp.v4();
this.setState({ Client_IP: IPAddress })
}
eventHandler = () => (e: any) => {
e.persist()
this.setState((prevState: any) => ({
IPObject: {
...prevState.IPObject,
IPList: e?.target?.value
}
}));
}
<Input placeholder="IP address" required={true}
value={this.state.Client_IP} onChange={this.eventHandler()}></Input>
Change your input onChange to:
onChange={this.eventHandler}
When you use parantheses, you have to call it like an arrow function:
onChange={() => this.eventHandler()}
And make sure you change the field you want, in that eventHandler
Your code is constantly calling eventHandler function.
See here docs for eventHandling with JSX in react
The correct syntax will be
<Input placeholder="IP address" required={true} value={this.state.Client_IP} onChange={() => this.eventHandler()}></Input>
Or
<Input placeholder="IP address" required={true} value={this.state.Client_IP} onChange={this.eventHandler}></Input>
After months without reactjs I forgot how to solve this situation. I have a incremental input for numbers:
HTML:
<input
type="number"
value={stockQuantity}
defaultValue="1"
onChange={() => bookQuantity(stockQuantity)}
/>
React
const [stockQuantity, setStockQuantity] = useState(1);
const bookQuantity = (e) => {
setStockQuantity({ ...stockQuantity, [e.target.name]: e.target.value });
};
I just get errors I don't find the solution and I didn't find any previous work were I handle it.
Any idea?
You should define stockQuantity as an object initially:
const [stockQuantity, setStockQuantity] = useState({books: 1});
Then you can just setState in onChange event or create a separate function as you have already made.
You don't have to set the value prop
<input
type="number"
name="books"
defaultValue="1"
onChange={(e) => setStockQuantity({...stockQuantity, [e.target.name]: e.target.value})}
/>
You need to pass the event to your onChange handler and also add name to your input:
<input
type="number"
name="stockQuantity" // will be passed in e.target.name
value={stockQuantity}
defaultValue="1"
onChange={bookQuantity} // the same as onChange={(e) => bookQuantity(e)}
/>
I have found a little linear solution:
const [stockQuantity, setStockQuantity] = useState(1); // just numbers
const bookQuantity = (e) => {
setStockQuantity({ ...stockQuantity, [e.target.name]:
e.target.value });
};
HTML:
<input
type="number"
name="stock"
value={stockQuantity.books}
defaultValue="1"
onChange={bookQuantity}
// if you want you can use a placeholder
/>
I am trying to add some state data into local storage in a method but I get the error:
'handleFormSubmit' function is not defined no-undef
This is my code:
class App extends React.Component {
state = {
noteTitle: 'sample title',
noteDescription: 'sample desc'
}
handleFormSubmit = () => {
const { noteTitle, noteDescription } = this.state;
localStorage.setItem('noteTitle', noteTitle);
localStorage.setItem('noteDescription', noteDescription);
};
render() {
return (
<input
type="text"
className="form-control"
placeholder="Title"
onChange={(e) => { this.setState({ noteTitle: e.target.value }) }}
/>
<textarea
type="text"
className="form-control my-4"
placeholder="Description"
onChange={(e) => { this.setState({ noteDescription: e.target.value }) }}
/>
<button onClick={handleFormSubmit} className="form-control">Save</button>
I have looked through other post's regarding this issue, it seems so simple but most other issues deal with an extra thing and I don't quite understand why my code shouldn't work.
You need to use both this and () to identify that it is local to the class and that it is a function. Change this...
<button onClick={handleFormSubmit} className="form-control">Save</button>
To this...
onClick={() => this.handleFormSubmit()}
Take a look at a working demo with this fixed.
If you fork the code above, and change it back to the way you had it, I get the same error as you had...
'handleFormSubmit' function is not defined no-undef
I'm still relatively new to React/Javascript & working with its functions. I created a component that takes user input and renders a button that allows a user to link to an outside URL.
The button title is created by the user and then the URL is added.
However, when a url is pasted or I begin typing it, the onChange handler automatically creates the button without using the onSubmit function. So if I begin typing a paste a url (even if the data is wrong), the onChange event takes whatever I've input without allowing me to click "submit first".
I'm following this tutorial as a guideline for creating my onChange/onSubmit functions: https://www.youtube.com/watch?v=qH4pJISKeoI&t=304s. His demo does not have the same issue and his input fields solve a different problem.
onChange & onSubmit Functions
this.state = {
links: [],
url: '',
title: ''
}
}
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault(e)
}
...
render() {
if (this.state.url === '') {
return (
<>
<form>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placholder="your-link.com"
onClick={(e) => { e.stopPropagation() }}
disabled={this.state.title === ''}
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button onClick={this.onSubmit}>Submit</button>
</>
)
} else {
return (
<>
<div>
<p>{this.state.title}</p>
</div >
</>
)
}
}
}
I've tried separating the onChange events using onChange={this.title} and {this.url} , disabling the URL field until the title is added, and adding onClick={(e) => { e.stopPropagation() }} in the url input field to prevent autosubmission as shown in the code above.
Any help understanding what causes this problem would be appreciated.
Let's check what is happening:
We have onChange on input with url.
When anything is being changed in this input field,
On change is called and it triggers render method.
In render if (this.state.url === '') { this is no longer true so it creates link without needing to submit.
Prevent default will not work while you have params in it:
e.preventDefault(e)
// probably this may be a typo instead?
// it's preventing you to go further line due to error.
Remove e param and it should be fine:
e.preventDefault()
<form onSubmit={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.onChange(e)}
/>
<input
name="url"
type="url"
placholder="your-link.com"
disabled={this.state.title === ''}
onChange={e => this.onChange(e)}
/>
<br />
<button type="submit">Submit</button>
</form>
do changes like this and check