'How to disable button according to input length by using React useState?
I have a simple page with input fields and a button and I want to make button disabled when both field length is less than 3. It is simple thing but I am confused about the hook because it is going into infinite loop. Here is code:
function TableFooterPanel(props) {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
// const [isButtonDisabled, setIsButtonDisabled] = useState(true);
const addNewCustomer = async (name, surname) => {
await service.addCustomer(name, surname);
props.funcParam();
}
var isButtonDisabled = false;
if (firstName <= 3 || lastName <= 3) {
isButtonDisabled = true;
}
else {
isButtonDisabled = false;
}
return (
<>
<Card className='buttonFooter'>
<Form className='buttonFooter'>
<input type="text" placeholder="First Name" defaultValue={firstName} onChange={e => setFirstName(e.target.value)}></input>
<input type="text" placeholder="Last Name" defaultValue={lastName} onChange={e => setLastName(e.target.value)}></input>
<Button disabled={isButtonDisabled} onClick={() => addNewCustomer(firstName, lastName)}>Add</Button>
</Form>
</Card>
</>
);
}
export default TableFooterPanel;
With this code, the boxes only check whether they are empty or filled.
If I uncomment useState hook and try to set it in if-else condition then this time infinite-loop is happening and page is crashing.
How can I check the input length without falling into infinite-loop?
Solution 1:[1]
I suggest you to not write code directly in component's body: you don't know how many times that code will be exected. Much better use a useEffect hook:
function TableFooterPanel(props) {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [isButtonDisabled, setIsButtonDisabled] = useState(true);
const addNewCustomer = async (name, surname) => {
await service.addCustomer(name, surname);
props.funcParam();
}
useEffect(() => {
if (firstName.length <= 3 || lastName.length <= 3) {
setIsButtonDisabled(true);
}
else {
setIsButtonDisabled(false);
}
}, [firstName, lastName]);
return (
<>
<Card className='buttonFooter'>
<Form className='buttonFooter'>
<input type="text" placeholder="First Name" defaultValue={firstName} onChange={e => setFirstName(e.target.value)}></input>
<input type="text" placeholder="Last Name" defaultValue={lastName} onChange={e => setLastName(e.target.value)}></input>
<Button disabled={isButtonDisabled} onClick={() => addNewCustomer(firstName, lastName)}>Add</Button>
</Form>
</Card>
</>
);
}
export default TableFooterPanel;
As you can see, I have used an useEffect hook with firstName and lastName in deps list: this means that, every time firstName or lastName change, useEffect will be fired.
And don't forget that, to check string length you have to use length property =).
Solution 2:[2]
Try :
if (firstName.length <= 3 || lastName.length <= 3) {
isButtonDisabled = true;
}
else {
isButtonDisabled = false;
}
Solution 3:[3]
Here you go: Codesandbox demo
You could simple add the disabled argument inline like this:
<button
disabled={firstName.length < 3 || lastName.length < 3}
onClick={() => addNewCustomer(firstName, lastName)}
>
Add
</button>
Solution 4:[4]
function TableFooterPanel(props) {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const addNewCustomer = async (name, surname) => {
await service.addCustomer(name, surname);
props.funcParam();
}
return (
<>
<Card className='buttonFooter'>
<Form className='buttonFooter'>
<input type="text" placeholder="First Name" defaultValue={firstName} onChange={e => setFirstName(e.target.value)}></input>
<input type="text" placeholder="Last Name" defaultValue={lastName} onChange={e => setLastName(e.target.value)}></input>
<Button disabled={!(firstName.length < 3 || lastName.length < 3)} onClick={() => addNewCustomer(firstName, lastName)}>Add</Button>
</Form>
</Card>
</>
);
}
export default TableFooterPanel;
Solution 5:[5]
Less than 3 is < 3, not <= 3
There's no need for an if condition here, just set the value of isButtonDisabled directly:
const isButtonDisabled = firstName.lenght < 3 || lastName.lenght < 3;
Or just do it inline:
<Button disabled={firstName.lenght < 3 || lastName.lenght < 3} />
Solution 6:[6]
You need to put them inside a useEffect otherwise it will re-run when anything on this page changes and make the isButtonDisabled variable as a state.
const [isButtonDisabled, setIsButtonDisabled] = useState(true)
useEffect(()=>{
if (firstName.length <= 3 || lastName.length <= 3) {
setIsButtonDisabled(true);
} else {
setIsButtonDisabled(false);
}
},[firstName, lastName])
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Giovanni Esposito |
| Solution 2 | yanir midler |
| Solution 3 | Reinier68 |
| Solution 4 | kennarddh |
| Solution 5 | |
| Solution 6 | Thanveer Shah |
