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

fix(Tree): use context to supply generated props to items #12182

Merged
merged 16 commits into from
Mar 9, 2020
Merged

fix(Tree): use context to supply generated props to items #12182

merged 16 commits into from
Mar 9, 2020

Conversation

silviuaavram
Copy link
Contributor

@silviuaavram silviuaavram commented Mar 4, 2020

Pull request checklist

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

Description of changes

  • Passing onFocusParent, onTitleClick, onFocusFirstChild and onSiblingsExpand through context from Tree to TreeItem. Removed them from overrideProps.
  • Creating contentRef only once.
  • Removing itemsForRender and generating the props relevant for accessibility directly in renderItems.
  • Removed siblings prop and compute it only when needed.

Fixes microsoft/fluent-ui-react#2295.

Focus areas to test

(optional)

Microsoft Reviewers: Open in CodeFlow

@size-auditor
Copy link

size-auditor bot commented Mar 4, 2020

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: d2abb5be48d5bdd44bcd2d593d31441fe45d35e8 (build)


return [...renderedItems, renderedItem, ...(isSubtreeExpanded ? renderItems(item['items']) : ([] as any))];
const elementRef = React.createRef<HTMLElement>();
const contextValue: TreeItemRenderContextValue = {
Copy link
Member

Choose a reason for hiding this comment

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

This will not work 😨 https://smykhailov.github.io/react-patterns/#/context

So, even if consumers will inject React.memo() around TreeItem they will still receive updates as context value will always change.

const contextValue: TreeItemRenderContextValue = {
level,
index: index + 1,
size: items.length,
Copy link
Member

Choose a reason for hiding this comment

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

I don't see any benefits from passing level, index & size via context as they are plain.


I proposed to use Context because I want to avoid creation of new functions in overrideProps, it's done ✔️
Now we need:

  • find a way to avoid elementRef, onSiblingsExpand, onFocusFirstChild, onFocusParent creation on each render, i.e. remove dependency on exact item
  • TreeItemContext should TreeContext, we obviously don't want to wrap each item with own Provider, it will be easy doable after previous item will be solved

@msft-github-bot
Copy link
Contributor

msft-github-bot commented Mar 4, 2020

Perf Analysis

No significant results to display.

All results

Scenario Master Ticks PR Ticks Status
BaseButton 671 704
BaseButton (experiments) 933 885
DefaultButton 946 996
DefaultButton (experiments) 1766 1847
DetailsRow 3298 3221
DetailsRow (fast icons) 3229 3285
DetailsRow without styles 3058 3010
DocumentCardTitle with truncation 1578 1592
MenuButton 1221 1262
MenuButton (experiments) 3410 3407
PrimaryButton 1088 1119
PrimaryButton (experiments) 1876 1856
SplitButton 2696 2773
SplitButton (experiments) 6673 6681
Stack 433 437
Stack with Intrinsic children 1043 1043
Stack with Text children 3858 3829
Text 348 347
Toggle 761 782
Toggle (experiments) 2122 2096
button 64 51

Perf Analysis (Fluent)

Perf comparison
Status Scenario Fluent TPI Fabric TPI Ratio Iterations Ticks
🔧 Avatar.Fluent 0.55 0.47 1.17:1 2000 1107
🦄 Button.Fluent 0.15 0.22 0.68:1 1000 149
🔧 Checkbox.Fluent 0.75 0.4 1.88:1 1000 749
🔧 Dialog.Fluent 0.37 0.22 1.68:1 5000 1836
🔧 Dropdown.Fluent 3.59 0.47 7.64:1 1000 3590
🔧 Icon.Fluent 0.16 0.05 3.2:1 5000 816
🦄 Image.Fluent 0.06 0.1 0.6:1 5000 322
🔧 Slider.Fluent 1.61 0.4 4.03:1 1000 1607
🔧 Text.Fluent 0.07 0.02 3.5:1 5000 362
🦄 Tooltip.Fluent 0.12 18.47 0.01:1 5000 597

🔧 Needs work     🎯 On target     🦄 Amazing

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
DropdownManyItemsPerf.default 377 334 1.13:1
ButtonSlotsPerf.default 807 745 1.08:1
ImageMinimalPerf.default 343 317 1.08:1
RadioGroupMinimalPerf.default 545 511 1.07:1
TreeMinimalPerf.default 1207 1152 1.05:1
AttachmentSlotsPerf.default 3731 3591 1.04:1
HeaderMinimalPerf.default 552 531 1.04:1
LabelMinimalPerf.default 377 361 1.04:1
ListMinimalPerf.default 449 432 1.04:1
ToolbarMinimalPerf.default 1105 1062 1.04:1
TooltipMinimalPerf.default 874 844 1.04:1
TreeWith60ListItems.default 239 230 1.04:1
VideoMinimalPerf.default 922 884 1.04:1
ListNestedPerf.default 960 932 1.03:1
LoaderMinimalPerf.default 1128 1098 1.03:1
StatusMinimalPerf.default 339 329 1.03:1
TableMinimalPerf.default 654 632 1.03:1
Checkbox.Fluent 749 730 1.03:1
AnimationMinimalPerf.default 654 641 1.02:1
DialogMinimalPerf.default 1859 1819 1.02:1
DropdownMinimalPerf.default 3595 3531 1.02:1
ListCommonPerf.default 1049 1025 1.02:1
MenuButtonMinimalPerf.default 1894 1858 1.02:1
TextMinimalPerf.default 369 362 1.02:1
Avatar.Fluent 1107 1083 1.02:1
Icon.Fluent 816 801 1.02:1
ChatDuplicateMessagesPerf.default 435 431 1.01:1
HierarchicalTreeMinimalPerf.default 1025 1017 1.01:1
ReactionMinimalPerf.default 2547 2515 1.01:1
SliderMinimalPerf.default 1589 1579 1.01:1
SplitButtonMinimalPerf.default 13239 13053 1.01:1
Button.Fluent 149 148 1.01:1
Text.Fluent 362 359 1.01:1
BoxMinimalPerf.default 356 355 1:1
EmbedMinimalPerf.default 6482 6450 1:1
ItemLayoutMinimalPerf.default 2119 2116 1:1
LayoutMinimalPerf.default 652 652 1:1
RefMinimalPerf.default 200 201 1:1
AttachmentMinimalPerf.default 950 960 0.99:1
FormMinimalPerf.default 901 913 0.99:1
GridMinimalPerf.default 843 854 0.99:1
InputMinimalPerf.default 1094 1107 0.99:1
ListWith60ListItems.default 185 187 0.99:1
CustomToolbarPrototype.default 3927 3983 0.99:1
Slider.Fluent 1607 1628 0.99:1
AlertMinimalPerf.default 616 629 0.98:1
CarouselMinimalPerf.default 2095 2140 0.98:1
ChatMinimalPerf.default 551 565 0.98:1
IconMinimalPerf.default 401 409 0.98:1
TextAreaMinimalPerf.default 3196 3257 0.98:1
Dialog.Fluent 1836 1876 0.98:1
Dropdown.Fluent 3590 3656 0.98:1
ButtonMinimalPerf.default 149 154 0.97:1
CheckboxMinimalPerf.default 3290 3400 0.97:1
FlexMinimalPerf.default 251 259 0.97:1
MenuMinimalPerf.default 2019 2087 0.97:1
PopupMinimalPerf.default 394 407 0.97:1
SegmentMinimalPerf.default 1076 1105 0.97:1
Image.Fluent 322 333 0.97:1
AvatarMinimalPerf.default 552 573 0.96:1
DividerMinimalPerf.default 959 996 0.96:1
HeaderSlotsPerf.default 1619 1681 0.96:1
Tooltip.Fluent 597 622 0.96:1
PortalMinimalPerf.default 282 297 0.95:1
ProviderMergeThemesPerf.default 1321 1392 0.95:1
ProviderMinimalPerf.default 637 669 0.95:1
AccordionMinimalPerf.default 236 251 0.94:1
ChatWithPopoverPerf.default 579 629 0.92:1


setActiveItemIds = (e: React.SyntheticEvent, activeItemIds: string[]) => {
_.invoke(this.props, 'onActiveItemIds', e, { ...this.props, activeItemIds });
_.invoke(this.props, 'onActiveItemIdsChange', e, { ...this.props, activeItemIds });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

sometimes my coding is simply bad.

}),
overrideProps: this.handleTreeItemOverrides
parent,
level,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to refactor level, index, treeSize in a subsequent PR. I think it makes sense to just call them ariaPosInSet, ariaSetSize, ariaLevel since that's their only use. Opinions?

Copy link
Member

Choose a reason for hiding this comment

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

aria-level in this case. But makes sense only if they are used only for attributes...

onTitleClick: (e: React.SyntheticEvent, treeItemProps: TreeItemProps) => void;
}

export const TreeItemContext = React.createContext<TreeItemRenderContextValue>(null);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export const TreeItemContext = React.createContext<TreeItemRenderContextValue>(null);
export const TreeContext = React.createContext<TreeContextValue>(null);

I would say that this is TreeContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool!

onFocusFirstChild: (itemId: string) => void;
onFocusParent: (itemId: string) => void;
onSiblingsExpand: (e: React.SyntheticEvent, itemProps: TreeItemProps) => void;
onTitleClick: (e: React.SyntheticEvent, treeItemProps: TreeItemProps) => void;
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
onTitleClick: (e: React.SyntheticEvent, treeItemProps: TreeItemProps) => void;
onTitleClick: (e: React.SyntheticEvent, itemProps: TreeItemProps) => void;

nit

@silviuaavram silviuaavram merged commit 96be7ad into microsoft:master Mar 9, 2020
@silviuaavram silviuaavram deleted the fix/tree-item-context-props branch March 9, 2020 17:28
@layershifter layershifter mentioned this pull request May 26, 2020
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fluent UI react-northstar (v0) Work related to Fluent UI V0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Custom renderer for Tree element shorthands is called with referentially unstable props.
5 participants