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: state management flow to avoid data loss #283

Merged
merged 1 commit into from
Aug 30, 2023

Conversation

pasyukevich
Copy link
Contributor

@pasyukevich pasyukevich commented Jul 24, 2023

Details

Related Issues

Expensify/App#22122
Expensify/App#21881

Automated Tests

Linked PRs

@github-actions
Copy link
Contributor

github-actions bot commented Jul 24, 2023

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@pasyukevich
Copy link
Contributor Author

I have read the CLA Document and I hereby sign the CLA

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

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

@pasyukevich can you add some manual test cases to the PR description, please? So reviewers know how to verify the fix.

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

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

Hmm, this doesn't seem to resolve the Android splash bug for me. To test I manually changed the code in the App node modules file. Am I missing something?:

Screenshot_20230726_094039

@pasyukevich
Copy link
Contributor Author

@Julesssss could you provide details on how you managed to reproduce the issue?

I will take a look

@Julesssss
Copy link
Contributor

Yeah, so internally we use Ngrok for dev testing. A lot of us have noticed that NewDot is bricked on Android emulators with the chrome app: Expensify/App#22122

But perhaps that is a separate issue after all... oh well.

We still need some tests that we can use to verify this fix though.

@pasyukevich
Copy link
Contributor Author

pasyukevich commented Jul 26, 2023

@Julesssss I'm in the process of preparing the instruction to verify the fix. However, it has become more challenging to do so with my previous flow, after updating to the latest version of the app. Now, I'm observing that in most instances, 'setState' is not invoked before 'setWithOnyxState' when using the same input.

When it comes to testing it locally, I've simply modified 'withOnyx.js' and 'web.development.js' inside the node_modules by incorporating this fix for both the mobile and web platforms.

@pasyukevich
Copy link
Contributor Author

pasyukevich commented Jul 27, 2023

Hi @Julesssss

I'm not able to reproduce the issue on the latest app version, so I prepared steps on how to reproduce it on the old app but with the latest Onyx library

Step-by-step on how to reproduce the broken flow for Onyx

  1. Log into the app locally using the main branch.
  2. Shut down the current environment.
  3. Fetch this branch from the forked repo - https://github.com/pasyukevich/Expensify-app/tree/test-report-expanded-latest-onyx (This is the older app version with the port updated to 8082, Onyx version updated, and the Test component prepared).
  4. Install the necessary modules and run the app.
  5. Open any report, type a few lines of text, and expand the composer.
  6. Retrieve the report ID from the URL.
  7. Navigate to Test.js in the 'src/libs/Navigation/AppNavigator'.
  8. Replace 'PLACE_HERE_ID_OF_REPORT' with the actual report ID.
  9. Open CentralPanelNavigator.js
  10. Replace ReportScreenWrapper with the Test component (use 'import Test from '../Test').
  11. Refresh the page after autorefresh.
  12. Observe that Expensify logs as true in the console, while Test logs as false (in both instances, this.props.isSidebarLoaded is logged).
  13. Apply the Onyx changes from this PR in web.development.js located in the node_modules. (to apply the same changes for mobile - withOnyx.js)
  14. Refresh the page again and note that 'Test' is now true.

@aimane-chnaif
Copy link

@pasyukevich can you please clarify exactly what issue existed before this change and fixed after this change?

@pasyukevich
Copy link
Contributor Author

@aimane-chnaif Sure

This change should fix the flow when the Onyx variable is not updated to the latest

  1. SetState is called for the Onyx instance and adding an updated flag to the state
  2. setWithOnyxState is called and tempState is set, the previous value erased
  3. As a result we have the initial value in the current state

@trjExpensify
Copy link

This PR has stalled for a couple of weeks. Can we keep it moving @aimane-chnaif?

@aimane-chnaif
Copy link

yes, sure. sorry for delay

@aimane-chnaif
Copy link

@pasyukevich please fix conflict

@pasyukevich
Copy link
Contributor Author

@aimane-chnaif PR is updated

@pasyukevich
Copy link
Contributor Author

I see that the update was applied to the Onyx library that was aimed to fix the same problem, but during my test, it did not work well in the described flow

With this branch after cleaning node modules and reinstalling them I was able to reproduce the composer issue. - Expensify/App#21881

I found that the approach with function in the setState fixes this issue, but the manual assign is not (as it is now done in the wIthOnyx)

@aimane-chnaif
Copy link

I will test after Expensify/App#24041 (which bumps this repo version) is merged in E/App.

@pasyukevich
Copy link
Contributor Author

@aimane-chnaif this flow is not reproducible on the current app version due to the page commits

best choice is to use this branch of app with updated Onyx library version

I can prepare an updated branch and flow with newer Onyx and recheck

@aimane-chnaif
Copy link

I can prepare an updated branch and flow with newer Onyx and recheck

Sure, thanks!

@pasyukevich
Copy link
Contributor Author

I created a new test branch with updated Onyx test-report-expanded-latest-onyx

Instruction updated - #283 (comment)

This behavior is still reproducible

@mountiny
Copy link
Contributor

@hannojg @Szymon20000 Could you help review this PR and issue its attempting to solve, your experience with Onyx might be handy, thanks!

lib/withOnyx.js Outdated
this.setState(stateUpdate); // Trigger a render
// Retain previous state to avoid data loss during pre-load updates.
// This handles race conditions where setWithOnyxState might be called after setState
this.setState(prevState => ({...this.tempState, ...prevState, loading: false}));
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the race condition exactly? Is there any example? Can we break this problem down a bit further in the comment? Who is calling setState() and why should we ever prefer the previous state of the withOnyx() component over the initial value being set here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment updated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exact flow described here

Copy link
Contributor

Choose a reason for hiding this comment

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

That's pretty interesting.

So ultimately, sounds like we have made the bad assumption here that setState() can never be called before setWithOnyxState().

If we got here and the state already has the key then we could
in theory remove it from tempState? That approach might be a little more obvious vs. spreading the prevState after the tempState. Though they would achieve the same result. Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I agree with you that it would be more straightforward to remove properties from the tempState that already exist in prevState

I'd assume that you mean something like omit

I will recheck the flow again with the update and apply changes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@marcaaron PR updated with omit approach

lib/withOnyx.js Show resolved Hide resolved
Signed-off-by: Yauheni Pasiukevich <pasyukevich@live.com>
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.

LGTM thanks for the change

@marcaaron
Copy link
Contributor

All yours @Julesssss !

Copy link
Contributor

@Julesssss Julesssss left a comment

Choose a reason for hiding this comment

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

Okay, we'll have to be careful to test this in the App PR that bumps the Onyx lib.

@Julesssss Julesssss merged commit f3141b9 into Expensify:main Aug 30, 2023
3 checks passed
@aimane-chnaif
Copy link

Okay, we'll have to be careful to test this in the App PR that bumps the Onyx lib.

I will be taking responsible for this

@Julesssss
Copy link
Contributor

Sweet. I created a bump PR here but I'm struggling to build Desktop now...

@Julesssss
Copy link
Contributor

Actually, the Desktop error seems unrelated

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.

6 participants