mui / mui/material-ui

[tooltip] Preventing from unnecessarily rerendering the children component

Open
#41,144 9 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

performance scope: tooltip
Dominant language
JavaScript
Stars
99.1k
Forks
32.5k
Avg merge
2d 17h
Merged PRs (30d)
106

Description

Summary

This RFC concerns the React Tooltip component and potential performance issues.

Problem

The React Tooltip component unnecessarily rerenders the provided children component ~2-3 times on initial Tooltip render and every time the tooltip's visibility state toggles.

Cause

There are a considerable number of code paths leading up to the final cloneElement call here that create a large number of new references. This leads to the observed unnecessary rerendering behavior.

Experimentation

I have tested this and confirmed that Tooltip indeed causes the children component to unnecessarily render at least 2-3 additional times.

As a PoC, I have also tested with a reduced-complexity (but-otherwise like-for-like) Tooltip component that proves that leveraging React memoization utils eliminates the problem. For example, the ultimate cloneElement call ends up looking something like this:

image

I do not however possess the resources to delve any deeper into this (e.g. in-depth perf benchmarks). Apologies.

Open Questions
  1. Would the (likely significant) refactors be worth-it?
  2. Would the performance gain of less children renders outweigh the performance loss of memoization?
What are the requirements?

Zero unnecessary rerenders of the provided children component.

What are our options?

With my current understanding, there is only one accepted way to achieve this - refactor Tooltip to use React memoization utils to prevent childrenProps from being a new reference or containing new references.

Proposed solution

The crux of the solution is to extract out the cloneElement call and place it inside a useMemo call with the properties of childrenProps as the memoization dependencies.

This may require some additional uses of useCallback in order to ensure the event handler functions such as handleEnter and onMouseEnter are not new references.

Resources and benchmarks

N/A

Search keywords: tooltip, react, performance, memoization

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/mui-material/src/Tooltip/Tooltip.js around the final cloneElement call at line 668. Profile the Tooltip's initial render and visibility toggles, then evaluate whether memoization changes prevent unnecessary children renders without creating a larger performance cost; done means meeting the stated zero-unnecessary-rerenders requirement with supporting benchmarks.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
frontend, performance
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.