Reputation: 85
I want the useEffect to occur multiple times. For example in the below example, everything works correctly the first time round.
If the input field is empty, and you click on 'Next', the focus then shifts to another button. When you click this button, the focus then shifts to the incomplete question. However this only works on the first render. How do I get it to work so that the useEffect occurs each time the button is clicked?
https://codepen.io/theinteractivedom/pen/ZExpqBy
const Summary = () => {
const [hasErrors, setHasErrors] = useState(false);
const [message, setMessage] = useState("");
const goToQuestionButton = useRef();
const inputRef = useRef();
const handleClick = () => {
if (message.trim().length !== 0) {
console.log("input value is NOT empty");
} else {
setHasErrors(true);
}
};
const handleClickTwo = () => {
inputRef.current.focus();
};
const handleChange = (event) => {
setMessage(event.target.value);
};
useEffect(() => {
if (hasErrors === true) {
goToQuestionButton.current.focus();
}
}, [hasErrors]);
return (
<div className='questions'>
<p>What is your name?</p>
<input
onChange={handleChange}
ref={inputRef}
id="firstName"
name="firstName"
></input>
<button onClick={handleClickTwo} ref={goToQuestionButton}>
Go to incomplete question
</button>
<button onClick={handleClick}>Next</button>
</div>
);
};
Upvotes: 1
Views: 409
Reputation: 1790
useEffect
will trigger any time the value of hasErrors
changes. You never reset the hasErrors
value after the input is focused.
useEffect(() => {
if (hasErrors === true) {
goToQuestionButton.current.focus();
setHasErrors(false);
}
}, [hasErrors]);
Setting hasErrors
to false after focusing the question will reset everything and allow it to be triggered again the next time hasErrors
is set to true.
Upvotes: 2
Reputation: 848
You need to move goToQuestionButton.current.focus()
inside handleClick
function and remove from useEffect. like this:
const handleClick = () => {
if (message.trim().length !== 0) {
console.log("input value is NOT empty");
} else {
setHasErrors(true);
goToQuestionButton.current.focus()
}
};
useEffect(() => {
}, [hasErrors]);
Upvotes: 1
Reputation: 371
Right now you have [hasErrors]
as a dependency for useEffect. That means that useEffect
will only run if hasErrors
changes. Right now you are only changing hasErrors
to false in handleClick
. On subsequent clicks, it is still false so useEffect doesn't think anything changed and therefore doesn't run. If you want it to run depending on hasErrors
, you will need to keep changing hasErrors
back and forth from true to false. But since inside useEffect
you are checking for false only, you could instead just remove the dependency and let useEffect
run every single render, like this:
useEffect(() => {
if (hasErrors === true) {
goToQuestionButton.current.focus();
}
});
Upvotes: 1
Reputation: 258
The useEffect always triggers, when the state in the dependency array changes. If you set the state on true again, it does not change. Therefore, the useEffect is not triggered. You have to setHasErrors(false) after resolving the error or focusing the question Button.
Upvotes: 1