Skip to content

ContextualMenu: Improve perf and allow buttons to benefit.#4524

Merged
joschect merged 12 commits intomicrosoft:masterfrom
joschect:improve-contextualmenu-perf
Apr 13, 2018
Merged

ContextualMenu: Improve perf and allow buttons to benefit.#4524
joschect merged 12 commits intomicrosoft:masterfrom
joschect:improve-contextualmenu-perf

Conversation

@joschect
Copy link
Copy Markdown
Contributor

Pull request checklist

  • Addresses an existing issue: Fixes #0000
  • Include a change request file using $ npm run change

Description of changes

Improve perf by removing a non-async sizing check and made max-height inline to reduce reflows. Also added the ability to have contextualmenus render hidden like callouts and button menus to render hidden as well.

Focus areas to test

(optional)

* impact overall perf by having more elemnts in the dom. Should only be used
* when perf is important.
*/
persistMenu?: boolean;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not quite sure what to name this and I am open to suggestions.


private _onMenuClosed() {
this._events.off(this._targetWindow, 'resize', this.dismiss);
setTimeout(() => this._previousActiveElement!.focus(), 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is _previousActiveElement guaranteed to not be null/undefined here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is not. I'll add a check

this.props.onMenuOpened && this.props.onMenuOpened(this.props);
}

private _onMenuClosed() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need a similar call to this.props.onMenuDismissed here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We do not, onDismiss is a callback that would have triggered the hidden prop change farther up the tree.

* Max height applied to the content of a callout.
*/
contentMaxHeight?: number;
contentMaxHeight?: number
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

shouldn't the semicolon still be here?

this._maxHeight = getMaxHeight(this._target, this.props.directionalHint!, totalGap, this._getBounds());
this._async.requestAnimationFrame(() => {
if (this._target) {
this._maxHeight = getMaxHeight(this._target, this.props.directionalHint!, totalGap, this._getBounds());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we need to trigger a new render after this RAF call to actually set the max height?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point, I really should have had this been setstate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

So I ended up reverting this, to not use setstate. Ideally the maxHeight should be set as soon as possible, which can happen during the first available animation frame.

/**
* Menu will not be created or destroyed when opened or closed, instead it
* will be hidden. This will improve perf of the menu opening but could potentially
* impact overall perf by having more elemnts in the dom. Should only be used
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would be expected to impact the time it takes to mount the button, perhaps that is worth calling out?

@christiango
Copy link
Copy Markdown
Member

Thanks for taking a look at this issue so quickly!


private _onMenuClosed() {
this._events.off(this._targetWindow, 'resize', this.dismiss);
this._previousActiveElement && setTimeout(() => this._previousActiveElement!.focus(), 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we do a null check here on _previousActiveElement?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We do, that's what this._previousActiveElement && does.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But the value can change when the callback in the set timeout gets invoked, cant it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a good point. I'll fix it.

@joschect joschect merged commit 4ea06e5 into microsoft:master Apr 13, 2018
@microsoft microsoft locked as resolved and limited conversation to collaborators Aug 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants