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

feat: preserve shared state on unmount with a future flag #5123

Merged
merged 21 commits into from
Oct 9, 2023

Conversation

Haroenv
Copy link
Contributor

@Haroenv Haroenv commented Sep 29, 2022

This PR introduces a functional change in how UI state is handled when widgets are removed from InstantSearch.

Currently, when a widget is removed, its dispose() method returns a cleaned state that is used to compute the new shared UI state. This means that if there are multiple widgets targeting the same attribute, when one of them is removed, the widget that is left has its UI state reset as a side-effect.

Through the introduction of future flags in InstantSearch, we are able to explicitly switch to a new dispose mode, which doesn't use the cleaned state returned by removed widgets, to allow multiple instances of widgets to keep the refinements active.

It's easy to opt into this new dispose method:

instantsearch({
  // ...
  future: {
    preserveSharedStateOnUnmount: true,
  },
});

Having this option enabled with a future flag allows us to easily release it without breaking existing implementations, allowing users to adopt it at their own rhythm.

This is made available for InstantSearch.js, React InstantSearch and Vue InstantSearch.

FX-2621

Initial PR description we have ui state and widgets reading this ui state. This means that when you dispose a widget, you don't need to call that function if you start with a clean helper state instead of persisting the state.

This needs to be done in a major version, as people might rely on state without ui state (i'm not sure if they do) and that would be removed if they dispose a widget.

This allows again for classic react-instantsearch-core style virtual widgets for the modal and dynamic widget use case

This could be introduced non-breaking as a different "mode" InstantSearch behaves in, that could be swapped the default value later

@codesandbox-ci
Copy link

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 87d1851:

Sandbox Source
InstantSearch.js Configuration

src/widgets/index/index.ts Outdated Show resolved Hide resolved
@@ -450,7 +450,10 @@ const index = (widgetParams: IndexWidgetParams): IndexWidget => {
};

derivedHelper = mainHelper.derive(() =>
mergeSearchParameters(...resolveSearchParameters(this))
mergeSearchParameters(
mainHelper.state,
Copy link
Contributor Author

@Haroenv Haroenv Sep 29, 2022

Choose a reason for hiding this comment

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

this part here is to ensure that "statically set parameters" on mainHelper persist (parameters on helper don't, as that actually is the helper of the mainIndex, confusing naming, I know).

Later, we probably should simply get rid of helper, and replace it with mainHelper only (which then gets name swapped)

@Haroenv Haroenv added the requires major a change which could not be implemented without a backwards incompatibility label Sep 29, 2022
@Haroenv Haroenv force-pushed the wip/dispose-is-gone branch from a2e4077 to 1bb6531 Compare November 25, 2022 09:44
@codesandbox-ci
Copy link

codesandbox-ci bot commented Sep 12, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 8ea7e44:

Sandbox Source
InstantSearch.js Configuration
react-instantsearch-app Configuration
example-react-instantsearch-default-theme Configuration
example-react-instantsearch-next-app-dir-example Configuration
example-vue-instantsearch-default-theme Configuration

Haroenv and others added 6 commits September 27, 2023 15:46
we have ui state and widgets reading this ui state. This means that when you dispose a widget, you don't need to call that function if you start with a clean helper state instead of persisting the state.

This needs to be done in a major version, as people _might_ rely on state without ui state (i'm not sure if they do) and that would be removed if they dispose a widget.

This allows again for classic react-instantsearch-core style virtual widgets for the modal and dynamic widget use case
@dhayab dhayab force-pushed the wip/dispose-is-gone branch from de926c3 to 9ff57f1 Compare September 27, 2023 13:56
@dhayab dhayab changed the title wip: no longer process dispose search parameters feat: preverse shared state on unmount with a future flag Sep 27, 2023
@dhayab dhayab changed the title feat: preverse shared state on unmount with a future flag feat: preserve shared state on unmount with a future flag Sep 27, 2023
@dhayab dhayab removed the requires major a change which could not be implemented without a backwards incompatibility label Sep 27, 2023
@dhayab dhayab requested review from dhayab and removed request for dhayab September 27, 2023 14:02
dhayab and others added 2 commits September 28, 2023 11:27
Co-authored-by: Haroen Viaene <hello@haroen.me>
Comment on lines 309 to 310
safelyRunOnBrowser(() => {
if (options.future?.preserveSharedStateOnUnmount === undefined) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

why not warn or warning? they already take a boolean that can be filled with options.future?.preserveSharedStateOnUnmount !== undefined

Copy link
Member

Choose a reason for hiding this comment

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

A warning might signify to users that not adopting the change will break their implementation, so I preferred a lighter informational message.

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'm mainly thinking of the DEV wrapping for warn. Not sure if info or warn makes much difference though, it's a valid point

Copy link
Member

Choose a reason for hiding this comment

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

Oh right, I didn't think about this and agree it should be scoped to dev mode. I'll add this.

@dhayab dhayab marked this pull request as ready for review October 2, 2023 13:59
@dhayab dhayab requested a review from sarahdayan October 2, 2023 14:00
Copy link
Contributor Author

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

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

Not sure what the right solution is for warn/info but otherwise this lgtm

.codesandbox/ci.json Outdated Show resolved Hide resolved
Comment on lines 309 to 310
safelyRunOnBrowser(() => {
if (options.future?.preserveSharedStateOnUnmount === undefined) {
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'm mainly thinking of the DEV wrapping for warn. Not sure if info or warn makes much difference though, it's a valid point

@dhayab dhayab mentioned this pull request Oct 3, 2023
Copy link
Contributor Author

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

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

✔️

Copy link
Member

Choose a reason for hiding this comment

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

Why not use this opportunity to create an tests/common/widgets/index/options.ts file and test this new behavior in it? No need to migrate the rest of our tests, we can do it separately, but at least we could start "the right way" and test as a user, without manipulating the helper.

Also, we should add a test for the default case (false, but not passed by the user).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was a CTS-style test before, but we couldn't get it to pass, not sure if that's stashed anywhere

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I've pushed the CTS here if you want to take a look, basically we saw lifecycle issues with React and Vue in the testing environment for which we could not find solutions for now.

Thanks for the suggestion on the missing test case, I've added it in 58ddb2a.

@dhayab dhayab requested a review from sarahdayan October 4, 2023 16:18
@dhayab dhayab merged commit 2258d89 into master Oct 9, 2023
3 checks passed
@dhayab dhayab deleted the wip/dispose-is-gone branch October 9, 2023 08:47
dhayab added a commit that referenced this pull request Oct 12, 2023

Co-authored-by: Dhaya <154633+dhayab@users.noreply.github.com>
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.

3 participants