-
Notifications
You must be signed in to change notification settings - Fork 841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] Fixed isLoading
logic in EuiConfirmModal
docs
#7026
Conversation
* Updated isLoading prop to check for input string value.
@@ -49,12 +49,12 @@ export default () => { | |||
buttonColor="danger" | |||
initialFocus="[name=delete]" | |||
confirmButtonDisabled={value.toLowerCase() !== 'delete'} | |||
isLoading={isLoading} | |||
isLoading={value.toLowerCase() !== 'delete' ?? isLoading} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bandaid fix, it doesn't address the root issue above as to why setIsLoading(false)
up above does not correctly work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take another run at it, and focus on the setIsLoading
logic.
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026_buildkite/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026_buildkite/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026/ |
const searchTimeout = setTimeout(() => { | ||
// Simulate a remotely-executed search. | ||
setIsLoading(false); | ||
}, 1200); | ||
|
||
clearTimeout(searchTimeout); | ||
useEffect(() => { | ||
if (value === 'delete') { | ||
setIsLoading(false); | ||
} | ||
}, [value]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trevor, I'm not sure you're understanding the intention of the demo and its code. :)
Take a look at the demo's description to help understand what the goal of this demo should be. Particularly: "This is helpful to indicate the fetching of data".
With that in mind, it becomes clear that the original setTimeout()
was mocking an production async API call that takes 1.2 seconds to complete.
When writing code for demos/examples, we need to be conscious of "does this make sense as a scenario that a consumer might run into? And if so, how can we demonstrate to them the right UX to apply?" In this case, the UX you've written does not make sense. We don't want to represent a loading state when a user hasn't entered in the correct text. A loading state only makes sense for async data that isn't yet available.
Per the demo description again: "wait for a user's input before enabling the confirm action". We want to represent a disabled state when delete
has not yet been typed. This logic was already being handled by the previous code:
confirmButtonDisabled={value.toLowerCase() !== 'delete'} |
So again, let's take this all the way from the top. The setTimeout
is not the issue, it's the fact that it's never actually getting called.
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026_buildkite/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026/ |
const closeModal = () => { | ||
setIsModalVisible(false); | ||
setIsLoading(false); | ||
clearTimeout(searchTimeout); | ||
setValue(''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch on this - I really like this addition!
setTimeout(() => { | ||
// Simulate a remotely-executed search. | ||
setIsLoading(false); | ||
}, 1200); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be curious to hear your rationale for inlining the setTimeout
vs leaving searchTimeout
and the clearTimeout
s in place. I don't strongly object to it/wouldn't consider it a blocker, but I'd like to hear the reasoning for changing it from the previous code.
I will note it does lead to potential race conditions: if a user opens the modal and then quickly closes it and re-opens it - the setTimeout
will still be running in the background and the modal will render on 2nd open as loaded as opposed to loading.
The reason I wouldn't consider this a blocker is because this is a pretty basic demo and doesn't necessarily need to account for such edge cases. However, it seems odd to go from accounting for that behavior in code to no longer accounting for that behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been refactoring it after thinking more about. I added a useEffect
and this is the code I'm working with locally that properly clears the timeout:
const [isLoading, setIsLoading] = useState(false);
const [isModalVisible, setIsModalVisible] = useState(false);
const [value, setValue] = useState('');
const showModal = () => {
setIsModalVisible(true);
setIsLoading(true);
};
const closeModal = () => {
setIsModalVisible(false);
setIsLoading(false);
setValue('');
};
useEffect(() => {
const searchTimeout = setTimeout(() => {
// Simulate a remotely-executed search.
setIsLoading(false);
}, 1200);
return () => {
clearTimeout(searchTimeout);
};
}, [isModalVisible]);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify what exactly about the clearTimeout
wasn't working? I'm not understanding why simply adding searchTimeout()
to the old openModal
call wasn't working, and why all this extra logic is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha I did totally miss the part where searchTimeout
isn't actually a function, apologies.
Why not make it as such? Would that not simplify/negate having to use a useEffect
? e.g.
let timeoutId;
const searchTimeout = () => setTimeout(() => setIsLoading(false), 1200));
const openModal = () => {
// ...
timeoutId = searchTimeout();
});
const closeModal = () => {
// ...
clearTimeout(timeoutId);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rewrote the solution to use this suggestion. I was having a time figuring out how to declare, then call the setTimeout()
. Your suggestion here makes the logic simpler and removes the two run useEffect()
which is much cleaner.
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026_buildkite/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026/ |
}, 1200); | ||
|
||
clearTimeout(searchTimeout); | ||
let timeOutId: ReturnType<typeof setTimeout>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[not a change request, just a nit] I personally would stick to the casing of the existing API, e.g. timeoutId
since setTimeout
does not capitalize the out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, sorry, your timeout name changes reverted re-adding the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, I wasn't asking for the comment to be restored in exactly the format it was before - above the const searchTimeout
was also fine. It just needed to still be there :)
Not a big deal either way, let's get this in
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026_buildkite/ |
Preview documentation changes for this PR: https://eui.elastic.co/pr_7026/ |
💚 Build Succeeded
History
cc @1Copenut |
Summary
Fixed the confirmation modal where users are asked to type
delete
into an input to enable the red confirm delete button. Closes #7013.QA
Remove or strikethrough items that do not apply to your PR.
General checklist