Skip to content
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

[ui] Change tag collection size-to-fit timing to avoid jank #26834

Merged
merged 2 commits into from
Jan 7, 2025

Conversation

bengotow
Copy link
Collaborator

@bengotow bengotow commented Jan 4, 2025

Summary & Motivation

We discussed this previously in #26122 — using a useEffect + requestAnimationFrame is technically the ideal time to perform the DOM sizing code in the asset tag collections, but it performs badly on the runs page due to interactions with react-virtual.

The tag collection appears within each row of a virtualized table, and I think that the useEffect + requestAnimationFrame combo causes our layout to happen after the rows have been measured, and the height changes cause them all to be re-measured after a visible re-paint.

How I Tested These Changes

The bad traces look like this:
image

After:

(note this is a key-up event causing a big scroll to lots of new rows all at once)

image

@bengotow bengotow requested review from salazarm and hellendag January 4, 2025 03:03
Copy link

github-actions bot commented Jan 4, 2025

Deploy preview for dagit-core-storybook ready!

✅ Preview
https://dagit-core-storybook-ecesq17sz-elementl.vercel.app
https://bengotow-2025-01-fix-jank.core-storybook.dagster-docs.io

Built with commit ec7b548.
This pull request is being automatically deployed with vercel-action

Copy link
Contributor

@salazarm salazarm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

owow I didn't realize this code was here when I accepted that PR since it was hidden by the "Large diffs not rendered by default" message :(

Does useLayoutEffect + requestAnimationFrame not work?

Copy link
Contributor

@salazarm salazarm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a shame that React doesn't give us a way to schedule when it mutates the DOM :(. Batching DOM queries/mutations app-wide is key to avoiding jank and reducing the number of reflows. Though I guess in this case useVirtualizer itself probably schedules its own RAF so we'd need to coordinate with it too and make sure we happen after it.

@salazarm
Copy link
Contributor

salazarm commented Jan 4, 2025

Hmm might be worth trying:

useLayoutEffect(() => {
  requestAnimationFrame(() => {
    setTimeout(() => {
       evaluate()
    }, 0);
  });
});

@bengotow
Copy link
Collaborator Author

bengotow commented Jan 7, 2025

Will try useLayoutEffect + requestAnimationFrame just to confirm! That seems like it's closer to the right implementation 🤔

Re the setTimeout one, I think I want to perform the layout sooner than it is currently happening - ideally there are no animation frames at all in which the incorrect height is rendered. I think that one might be going in the other direction.

@bengotow
Copy link
Collaborator Author

bengotow commented Jan 7, 2025

Confirmed that using useLayoutEffect + window.requestAnimationFrame is also better (5 renders => 3), going to go with that.

@bengotow bengotow changed the title Change tag collection size-to-fit timing to avoid jank [ui] Change tag collection size-to-fit timing to avoid jank Jan 7, 2025
@bengotow bengotow force-pushed the bengotow-2025-01/fix-jank branch from 88d575b to 830d208 Compare January 7, 2025 04:12
bengotow added 2 commits January 6, 2025 22:13
We discussed this previously in #26122 — using a `useEffect + requestAnimationFrame` is technically the ideal time to perform the DOM sizing code in the asset tag collections, but it performs really badly on the runs page.

This is because the tag collection appears within each row of a virtualized table, and the `useEffect + requestAnimationFrame` combo causes our layout to happen _after_ the rows have been measured, and the changes cause them to be re-measured.
@bengotow bengotow force-pushed the bengotow-2025-01/fix-jank branch from 830d208 to ec7b548 Compare January 7, 2025 04:13
bengotow added a commit that referenced this pull request Jan 7, 2025
## Summary & Motivation

This is a small follow-up to
#26834

I've noticed that sometimes with MiddleTruncate, there is a very slight
flicker when the text is first rendered. There's a single frame where
the rendered text is `null`, and you can see it before the text appears.

I'm not sure if my computer is just running slow today (looking for
excuses to get an M4 now...), or if it's the volume of MiddleTruncates
on this page (there are at least 50 rendering all at the same time), but
here's an example if you watch the tag on the right:


https://github.com/user-attachments/assets/4a05049d-9e70-4aaf-883a-eb448a905b01

Looking at the code for this, I don't think there's a reason for the
sizing to update React state and set the text through a React render.
The text is just used to set the span content, and the component doesn't
re-render unless the text changes (in which case `calculateTargetStyle`
changes and the effect runs again.) Setting the textContent directly
removes the flicker shown in the video.

## How I Tested These Changes

Tested in FF + Chrome manually

---------

Co-authored-by: bengotow <[email protected]>
@bengotow
Copy link
Collaborator Author

bengotow commented Jan 7, 2025

Build errors here seem unrelated, going to merge this!

@bengotow bengotow merged commit a9c31ce into master Jan 7, 2025
1 of 2 checks passed
@bengotow bengotow deleted the bengotow-2025-01/fix-jank branch January 7, 2025 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants