Page MenuHomePhabricator

[native] Refactor TypeaheadTooltip component
ClosedPublic

Authored by patryk on Aug 22 2023, 1:56 AM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Nov 14, 8:07 PM
Unknown Object (File)
Sat, Nov 9, 10:48 PM
Unknown Object (File)
Sat, Nov 9, 10:40 AM
Unknown Object (File)
Sun, Nov 3, 2:27 PM
Unknown Object (File)
Sun, Nov 3, 5:17 AM
Unknown Object (File)
Sun, Nov 3, 4:57 AM
Unknown Object (File)
Sun, Nov 3, 4:54 AM
Unknown Object (File)
Sun, Nov 3, 4:46 AM
Subscribers

Details

Summary

This diff refactors TypeaheadTooltip component on native to be more generic.

Depends on D8896.

Test Plan

Check if mention TypeaheadTooltip works on native.

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

patryk held this revision as a draft.
patryk edited the test plan for this revision. (Show Details)
patryk added reviewers: tomek, inka.

Why did you refactor this component?

Well, I had two options while writing solution for showing chats in typeahead tooltip:

  1. Add suggestedChats prop and don't refactor typeahead tooltip
  2. Make this component more generic.

Decided to take extra steps and made this component reusable in the future.

web/utils/typeahead-utils.js
110 ↗(On Diff #30189)

This line will be changed when I will be refactoring TypeaheadTooltip on web.

We use getTypeaheadTooltipActions to extract user info and getTypeaheadTooltipButtons as typeahead button renderer on web, so extracting typeaheadTooltipButton and typeaheadTooltipSuggestionTextExtractor to typeahead utils seems like a better idea.

I'm confused about your usage of parameters everywhere (<SuggestionItemType>). Is the tooltip ever rendering only one of TypeaheadUserSuggestionItem or TypeaheadChatSuggestionItem (as I'm guessing it will be called)? Why don't you just use TypeaheadSuggestionItem (that I'm guessing will be TypeaheadUserSuggestionItem | TypeaheadChatSuggestionItem)? Is it ever an incorrect type in any way?

Could you also explain what the execute in TypeaheadTooltipActionItem is?

native/chat/chat-input-bar.react.js
576–577 ↗(On Diff #30285)

Why are you importing them just to pass them down? Will any other function ever be passed to typeaheadButtonRenderer and typeaheadTooltipActionsGetter?

native/utils/typeahead-utils.js
77 ↗(On Diff #30285)

Why isn't this a component?

I'm confused about your usage of parameters everywhere (<SuggestionItemType>). Is the tooltip ever rendering only one of TypeaheadUserSuggestionItem or TypeaheadChatSuggestionItem (as I'm guessing it will be called)? Why don't you just use TypeaheadSuggestionItem (that I'm guessing will be TypeaheadUserSuggestionItem | TypeaheadChatSuggestionItem)

TypeaheadSuggestionItem will be equal to (as you correctly guessed) TypeaheadUserSuggestionItem | TypeaheadChatSuggestionItem in the next diff: renderer function needs to decide what avatar to render since we use separate components to render user and thread avatars.

Could you also explain what the execute in TypeaheadTooltipActionItem is?

See this. execute is a onPress handler. TypeaheadTooltipActionItem is a copy of this type, which is moved to lib.

We discussed offline whether this diff is truly necessary. While I could refactor this component into MentionTypeaheadTooltip, doing so would also require changes to other elements, such as comments within this component. Given that this component effectively resolves numerous issues associated with displaying the typeahead tooltip, renaming all of its parts might not be worthwhile. Is there a possibility of future reuse? Well, I have an idea: we could introduce some commands in the input bar. For instance, by typing !kick inka, we could initiate the removal of the user inka from the chat. Upon typing ! in the input bar, all possible commands would become visible.

native/chat/chat-input-bar.react.js
576–577 ↗(On Diff #30285)

Right now no other function will be ever passed, because we only use typeahead tooltip for mentioning.

native/chat/typeahead-tooltip.react.js
76 ↗(On Diff #30285)

Nit, can be simplified

native/utils/typeahead-utils.js
24–25 ↗(On Diff #30285)

Should be SuggestionItemType to maintain naming convention.

77 ↗(On Diff #30285)
  1. Maintaining web convention: see this.
  2. FlatList renderItem requires an function and not a component, so just to match function signature.

I think that this part should be changed so I see two potential solutions:

  1. Convert this function to component -> it would be rendered where typeaheadButtonRenderer is called in typeahead tooltip component. I personally don't like this solution.
  2. Move renderTypeaheadButton function from typeahead tooltip component outside: we would pass a renderer function as we do right now, but <Button> part would be moved to this rendered function too.

I believe that first option should be applied.

Change renderTypeaheadButton to component since this function does not return an array of components like on web

This solution is a bit overengineered, but I think there is no point in reverting it

This revision is now accepted and ready to land.Sep 6 2023, 12:55 AM
native/chat/chat-input-bar.react.js
509–513 ↗(On Diff #30189)

Nit: shorthand

native/utils/typeahead-utils.js
38 ↗(On Diff #30624)

This condition should be reversed to reduce indentation

tomek requested changes to this revision.Sep 12 2023, 7:27 AM
tomek added inline comments.
lib/shared/mention-utils.js
31 ↗(On Diff #30624)

I guess we're going to introduce new types later, right?

33 ↗(On Diff #30624)

Should we add a bound on type parameter?

35 ↗(On Diff #30624)

It's a good practice to declare the return type as mixed when we don't care about it

native/chat/typeahead-tooltip.react.js
19 ↗(On Diff #30624)

Should we add a bound on type parameter?

native/utils/typeahead-utils.js
27 ↗(On Diff #30624)

Wondering if this is a good approach. We probably can improve performance here by creating a component that directly consumes suggestion and is memoized. The problem with the current approach is that after every change, we generate an array of actions from scratch - every item is a new object (and even within the objects, we're creating the actions / objects on every computation). Our testing might show us if we really should optimize here.

This revision now requires changes to proceed.Sep 12 2023, 7:27 AM
lib/shared/mention-utils.js
31 ↗(On Diff #30624)

Yes, see D8909.

33 ↗(On Diff #30624)

I don't think it's necessary since TypeaheadSuggestionItem will be renamed to MentionTypeaheadSuggestionItem here: D8898 and in the future TypeaheadSuggestionItem might be a little bit different.

native/utils/typeahead-utils.js
27 ↗(On Diff #30624)

Yes, it might be an performance issue, but if you look closely, every time we enter a new character, getNewTextAndSelection and focusAndUpdateTextAndSelection in execute (in mentionTypeaheadTooltipActions) are going to be "recalculated" since we pass textPrefix (or query) parameter, which is obviously being changed every time we type sth in input bar, thus all memoized components would be recalculated again. We could move execute to the typeahead button component and achieve O(n) time complexity rather than O(2n) but I don't think it would bring a significant improvement. Also look at previous code. useCallback was also executed every time user has entered a character (see usernamePrefix). We probably should refactor getNewTextAndSelection and focusAndUpdateTextAndSelection to avoid passing query every time user inputs a new character in the future.

38 ↗(On Diff #30624)

I agree, but I will introduce new else-if for suggestion.type === 'chat'. I could handle one case earlier and reduce indentation for the second case, but I personally don't think it will be more readable.

ashoat added a subscriber: atul.

Adding @atul as a reviewer in case he has any comments about React performance here

native/utils/typeahead-utils.js
27 ↗(On Diff #30624)

I haven't looked too closely here, and I trust @tomek and @patryk can figure this out. But two quick notes I'd like to share:

  1. If we are reducing the number of renders by 2x, that is definitely worthwhile. On the other hand, if it's just improving the performance of a simple algorithm, it's not as important.
  2. We should ask ourselves if it's really necessary to rerender every single TypeaheadTooltipActionItem<TypeaheadSuggestionItem>. Is there something there that justifies a rerender – in other words, does it look different after? If not, then we should search for a way to avoid the rerender.
tomek added inline comments.
native/utils/typeahead-utils.js
27 ↗(On Diff #30624)

It seems that @patryk is right - the fact that actions depend on the query causes it to change on every input change. The biggest performance gain we could have might be to avoid execute being dependent on query - then the action item can be rendered just once and memoized.

This revision is now accepted and ready to land.Sep 20 2023, 3:00 AM