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

Perf: remove Onyx usage from withLocalize #4253

Merged
merged 1 commit into from
Jul 30, 2021

Conversation

kidroca
Copy link
Contributor

@kidroca kidroca commented Jul 27, 2021

@marcaaron

Details

This component is one of the most used components and has more than 310 instances depending on chat size
Instead of creating a new connection for each withLocalize usage - use the already cached value in translate
This significantly reduces the Onyx.get load that is caused by all the connections

Fixed Issues (Related To)

Fixes #4268

Tests

  1. Measure performance (init time) before this change
  2. Measure performance (init time) with the change in this PR

I'm using Onyx.printMetrics() to monitor the Onyx.get calls that happen during init: https://github.com/Expensify/react-native-onyx#benchmarks

My Benchmarks

Before
Total: 123.80sec     Last 17.49sec     ReportID 71955477
method total time spent max min avg time last call completed calls made
Onyx:get 96.85sec 2.92sec 0.10ms 144.77ms 17.48sec 669
After
Total: 62.62sec     Last 12.27sec     ReportID 71955477
method total time spent max min avg time last call completed calls made
Onyx:get 40.44sec 1.79sec 0.08ms 139.94ms 12.27sec 289

QA Steps

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

image

Mobile Web

Desktop

iOS

Android

iwiznia
iwiznia previously approved these changes Jul 27, 2021
Copy link
Contributor

@iwiznia iwiznia left a comment

Choose a reason for hiding this comment

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

Nice improvement!!

@parasharrajat
Copy link
Member

When we update the locale, Will the app re render components. I don't think it will.

Comment on lines 78 to 79

function getPreferredLocale() {
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB: For consistency, we're missing a function doc here -- even though its function is obvious.

Nice optimization!

Copy link
Contributor

Choose a reason for hiding this comment

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

  • If it has a return value it needs a doc but not necessarily a description.

@Julesssss
Copy link
Contributor

When we update the locale, Will the app re render components. I don't think it will.

That's a good point. I wouldn't have thought so either.

@iwiznia
Copy link
Contributor

iwiznia commented Jul 27, 2021

When we update the locale, Will the app re render components. I don't think it will.

Ohhh... hmmm yeah, that kind of sucks.

@kidroca
Copy link
Contributor Author

kidroca commented Jul 27, 2021

When we update the locale, Will the app re render components. I don't think it will.

When does that happen, isn't the app reloading when a new locale is selected?

@iwiznia
Copy link
Contributor

iwiznia commented Jul 27, 2021

When does that happen, isn't the app reloading when a new locale is selected?

You can test this by changing the language in the preferences (maybe you need to force being in the bet if that's not done by default in dev). And no, it does not reload, all components that are using withLocalize will re-render themselves.

@kidroca
Copy link
Contributor Author

kidroca commented Jul 27, 2021

I've mentioned this at Slack, there's another way to implement the HOC and it will not suffer this problem: https://expensify.slack.com/archives/C01GTK53T8Q/p1627403864349200?thread_ts=1627393814.334100&cid=C01GTK53T8Q

The changes would be slightly more, but it might be an even faster if the HOC is implemented through React.createContext. As this will also save 300+ class instances of withLocalize

I'll try it out tomorrow and do another benchmark

@marcaaron
Copy link
Contributor

Looks good so far and definitely up for more improvements. I'm adding a link back to the original issue in the description so there is some more context.

@marcaaron
Copy link
Contributor

But I think maybe this needs a new issue?

@kidroca
Copy link
Contributor Author

kidroca commented Jul 27, 2021

But I think maybe this needs a new issue?

Yeah, I'll probably have to spent some more time here, and then test/bench the changes on the remaining platforms.

I can open an issue tomorrow

@marcaaron
Copy link
Contributor

👍 Sounds great!

@kidroca
Copy link
Contributor Author

kidroca commented Jul 28, 2021

@marcaaron I've created a new issue: #4268 and updated the PR description with the link

@kidroca
Copy link
Contributor Author

kidroca commented Jul 30, 2021

Updated implementation and posted new benchmarks here: #4268 (comment)

I think another possible optimization that might be applied at the moment is to drop the withOnyx call altogether like this:

class LocaleContextProvider
    componentDidMount() {
        this.connectionId = Onyx.connect({
            key: ONYXKEYS.NVP_PREFERRED_LOCALE,
            callback: (val) => {
                if (val) {
                    this.setState({preferredLocale: val});
                }
            },
        });
    }

    componentWillUnmount() {
        Onyx.disconnect(this.connectionId);
    }

This skips creating the withOnyx class component
I've tried it briefly it was slightly faster bringing "Last call ended time" to ~10.87s (otherwise it's ~11.05s)
I can try to capture more data about it next week, but it might be better to focus/find something more important

@kidroca kidroca marked this pull request as ready for review July 30, 2021 21:02
@kidroca kidroca requested a review from a team as a code owner July 30, 2021 21:02
@kidroca kidroca requested review from marcaaron and Julesssss and removed request for a team July 30, 2021 21:02
@MelvinBot MelvinBot requested a review from aldo-expensify July 30, 2021 21:02
@kidroca kidroca requested a review from iwiznia July 30, 2021 21:02
Copy link
Contributor

@marcaaron marcaaron left a comment

Choose a reason for hiding this comment

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

These changes look good to me and do make chat switching significantly faster. I can't really think of any reasons why we should not do this (other than people being unfamiliar with the Context API). Probably as a follow up we can add something to the documentation about how to approach using withOnyx when a component will be used a great number of times throughout the app or some list.

const WithLocalize = forwardRef((props, ref) => (
<LocaleContext.Consumer>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
{ translateUtils => <WrappedComponent {...translateUtils} {...props} ref={ref} />}
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB, Unnecessary space here.

@marcaaron
Copy link
Contributor

This skips creating the withOnyx class component
I've tried it briefly it was slightly faster bringing "Last call ended time" to ~10.87s (otherwise it's ~11.05s)
I can try to capture more data about it next week, but it might be better to focus/find something more important

Yeah, I think there are probably better optimizations to focus on. This is already so great 🎉

@marcaaron marcaaron merged commit 8a958f2 into Expensify:main Jul 30, 2021
@OSBotify
Copy link
Contributor

🚀 Deployed to staging in version: 1.0.81-7🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 failure ❌
🍎 iOS 🍎 failure ❌
🕸 web 🕸 success ✅

@isagoico
Copy link

@kidroca Hello! Any QA tests needed for this PR?

@kidroca
Copy link
Contributor Author

kidroca commented Jul 31, 2021

@isagoico No specific test steps other than basic regressions as translations are used everywhere.
Switching the app language should work

@nkuoch
Copy link
Contributor

nkuoch commented Aug 2, 2021

@kidroca this PR created this regression.
Seems like it was pointed out before the merge though. Not sure why we merged it regardless and what was decided about it though? cc @marcaaron

@kidroca
Copy link
Contributor Author

kidroca commented Aug 2, 2021

@kidroca this PR created this regression.
Seems like it was pointed out before the merge though. Not sure why we merged it regardless and what was decided about it

The referenced comment was made for the logic in the initial PR, since then the code changed quite a lot
But debugging this I see that even though the Context rerenders it's children does not because they don't receive anything new

We can fix this by passing preferredLocale down. This will trigger a re-render in child components when the locale changes

I see a new ticket have been opened: #4359
Are we going to handle this as a continuation PR that fixes the regression?
Or should the other ticket have to be triaged and go through the full process of proposing and accepting a solution?

IMO, since it was tracked it to this PR, it would be easier and faster to address here by re-open the existing issue

@kidroca kidroca deleted the kidroca/locale-perf-fix branch August 2, 2021 13:25
@iwiznia
Copy link
Contributor

iwiznia commented Aug 2, 2021

Are we going to handle this as a continuation PR that fixes the regression?

IMO yes, because it's a feature that worked and was broken by this PR.

@parasharrajat
Copy link
Member

parasharrajat commented Aug 2, 2021

@kidroca Please close that Issue when you submit a fix via the PR. That issue was created for tracking the problem.

@kidroca
Copy link
Contributor Author

kidroca commented Aug 2, 2021

Shouldn't I be assigned to the new ticket as well then?

@parasharrajat
Copy link
Member

Is that any advantage of assigning an issue? Asking in general.

@iwiznia
Copy link
Contributor

iwiznia commented Aug 2, 2021

It makes it easier to find things if they are assigned to the people that worked on them. It is also used in some of our internal tooling to for example assign reviewers for issues or PRs.

@marcaaron
Copy link
Contributor

Not sure why we merged it regardless and what was decided about it though?

Oh, hmm, we merged it because the implementation was entirely different. In short, we didn't suspect the new one would have the same issue.

@OSBotify
Copy link
Contributor

OSBotify commented Aug 6, 2021

🚀 Deployed to production in version: 1.0.82-7🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Performance] Onyx usage in withLocalize adds a significant overhead
8 participants