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

[Lens] Embeddable entering loading state when component re-renders #203020

Open
Heenawter opened this issue Dec 4, 2024 · 1 comment
Open

[Lens] Embeddable entering loading state when component re-renders #203020

Heenawter opened this issue Dec 4, 2024 · 1 comment
Labels
bug Fixes for quality problems that affect the customer experience Feature:Lens project:embeddableRebuild regression Team:Visualizations Visualization editors, elastic-charts and infrastructure

Comments

@Heenawter
Copy link
Contributor

Heenawter commented Dec 4, 2024

Describe the bug:

The Lens embeddable is unnecessarily entering a loading state via calling the update method on the expression loader via the useUpdateEffect hook in src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts - this is because the expressionParams object is not being memoized properly before sending it in as a prop to ExpressionWrapper. Using an object as a dependancy to a hook strikes again! I think this is also being caused by the fact that expressionParams isn't serializable - i.e. it contains functions, which don't have an easy comparison even via useShallowMemo.

Steps to reproduce:

  1. Add a Lens embeddable to a dashboard and save the dashboard
  2. Switch from edit mode to view mode to trigger a re-render of LensEmbeddableComponent
  3. Notice that the Lens panel briefly shows the loading state from the expression renderer (src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts) despite not loading anything 🔥
Screen.Recording.2024-12-04.at.2.17.46.PM.mov

Expected behavior:

We should only enter a loading state when we actually have to refetch data.

Any additional context:

I found a hacky workaround via the following:

  • I created a hacky memoize that compares only the keys of two objects:

    export function useHackedMemo(value: object | null): object | null {
       const previousRef = useRef(value);
       
       if (!deepEqual(Object.keys(previousRef.current ?? {}), Object.keys(value ?? {}))) {
         previousRef.current = value;
       }
     
       return previousRef.current;
    }
  • I used this hacked memoize for expressionParams in the LensEmbeddableComponent:

    const [
      <....>
      expressionParams,
      latestViewMode,
    ] = useBatchedPublishingSubjects( 
      <....>
      internalApi.expressionParams$,
      api.viewMode
    );
    
    const memoizedExpressionParams = useShallowMemo(expressionParams);
    
    <....>
    
     <div <....>>
        {memoizedExpressionParams == null || blockingErrors.length ? null : (
          <ExpressionWrapper {...memoizedExpressionParams} />
        )}
        <....>
     </div>
  • Which removes the loading state on view mode change because the keys of expressionParams being consistent stops memoizedExpressionParams from referencing a new object every time useBatchedPublishingSubjects updates:

    Screen.Recording.2024-12-04.at.2.29.34.PM.mov
@Heenawter Heenawter added bug Fixes for quality problems that affect the customer experience Feature:Lens project:embeddableRebuild regression Team:Visualizations Visualization editors, elastic-charts and infrastructure labels Dec 4, 2024
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-visualizations (Team:Visualizations)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Fixes for quality problems that affect the customer experience Feature:Lens project:embeddableRebuild regression Team:Visualizations Visualization editors, elastic-charts and infrastructure
Projects
None yet
Development

No branches or pull requests

2 participants