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

Navigator: remove location history, simplify internal logic #64675

Merged
merged 11 commits into from
Aug 23, 2024

Conversation

ciampo
Copy link
Contributor

@ciampo ciampo commented Aug 21, 2024

What?

Part of #59418
Related to #60927

Rewrite Navigator's internal logic, removing the location history.

Why?

The location history is only an implementation detail after the changes in #63317 deprecated the "go back in history" behaviour, in favour of always navigating to the screen's parent.

Removing the code related to the location history allows the internal logic to be simpler and easier to maintain

How?

  • Instead of storing the whole location history, Navigator only internally stores the current location;
  • the goBack function inside the reducer was removed, together with some extra checks. The goTo function now always creates a new location object
  • Focus restoration logic uses a (screen path, focus selector) map instead of the location history, and should work like before;
    • In order to make the new focus restoration logic more robust, a new constraint was added, preventing a screen from being registered if a screen with the same path already exists;
  • The isInitial flag is now computed based on the initialPath prop, instead of using the location history — again, there shouldn't be any changes in behaviour.
  • The replace option is marked as deprecated, as it doesn't make sense without a location history (I don't think it was used in the editor anyway)

Testing Instructions

  • Unit tests should pass
  • Storybook examples should continue to work as expected
  • Smoke tests

@ciampo ciampo marked this pull request as ready for review August 21, 2024 10:01
@ciampo ciampo requested a review from ajitbohra as a code owner August 21, 2024 10:01
Copy link

github-actions bot commented Aug 21, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@ciampo ciampo self-assigned this Aug 21, 2024
@ciampo ciampo added [Type] Enhancement A suggestion for improvement. [Package] Components /packages/components labels Aug 21, 2024
@ciampo ciampo requested review from youknowriad, jsnajdr and a team August 21, 2024 10:04
@ciampo ciampo force-pushed the refactor/navigator-remove-location-history branch from 73870a0 to 1f12c95 Compare August 22, 2024 13:59
Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

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

Great cleanup, @ciampo!

Besides the focus management, looks and works well 👍

Seems like we'll need to do some re-architecting to let the reducer consider focusSelectors changes that goTo() does.

@ciampo ciampo force-pushed the refactor/navigator-remove-location-history branch from 1f12c95 to 77fb59f Compare August 23, 2024 14:08
@ciampo ciampo requested a review from tyxla August 23, 2024 14:09
@ciampo
Copy link
Contributor Author

ciampo commented Aug 23, 2024

@tyxla focus management should be fixed. I believe this PR is ready for another (final?) round of review

Copy link
Member

@tyxla tyxla left a comment

Choose a reason for hiding this comment

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

Works well in my testing, both in global styles and in storybook. ✅

Code looks good too. I've left a few questions/suggestions, but I feel like none of them are really blocking and could be addressed in follow-ups if we wish.

Thanks @ciampo!

isBack &&
locationHistory.length > 1 &&
locationHistory[ locationHistory.length - 2 ].path === path;
const focusSelectorsCopy = new Map( state.focusSelectors );
Copy link
Member

Choose a reason for hiding this comment

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

Any chance we're needlessly creating a copy? Should we create a copy only if (and when) we really need to change it? Like, in the conditions below?

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 optimised the code so that we create a copy only when necessary — it's not as elegant, but it does the job

7e159f8

Open to improvements in a follow-up!

screens: Screen[];
locationHistory: NavigatorLocation[];
currentLocation?: NavigatorLocation;
Copy link
Member

Choose a reason for hiding this comment

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

Is this type precise now? Seems like we're never setting isInitial to currentLocation, and we're only setting it manually when computing the context. Should we clean up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The type was precise, but you're right about the fact that we could be setting isInitial inside the reducer (instead of doing so in the context value). Done in 29e0fb2

@ciampo ciampo enabled auto-merge (squash) August 23, 2024 16:34
@ciampo ciampo merged commit 1e3efbb into trunk Aug 23, 2024
63 checks passed
@ciampo ciampo deleted the refactor/navigator-remove-location-history branch August 23, 2024 17:35
@github-actions github-actions bot added this to the Gutenberg 19.2 milestone Aug 23, 2024
Copy link

Flaky tests detected in 29e0fb2.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/10529136439
📝 Reported issues:

console.warn(
`Navigator: a screen with path ${ screen.path } already exists.
The screen with id ${ screen.id } will not be added.`
);
Copy link
Member

Choose a reason for hiding this comment

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

Let's use @wordpress/warning for this, already used widely in the components package.

focusSelectorsCopy = new Map( state.focusSelectors );
}
currentFocusSelector = focusSelectorsCopy.get( path );
focusSelectorsCopy.delete( path );
Copy link
Member

Choose a reason for hiding this comment

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

Here I would enhance the logic for the case when we navigate to the path in a isBack = false way, and it has a focusSelector stored. Then we don't want to focus (that's implemented currently) and also to delete the stored focusSelector because it's no longer relevant.

Also, a little optimization opportunity: create the copy only when you really found a selector to be deleted. Currently, if .get( path ) is null, you created the copy for nothing, it won't be mutated.

break;
}

if ( currentLocation?.path === state.initialPath ) {
currentLocation = { ...currentLocation, isInitial: true };
}
Copy link
Member

Choose a reason for hiding this comment

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

Do you really want to do this? isInitial should be true only when the page is initially loaded. Then we don't want to do animations or change focus. But when later navigating to the initial page, the initial page is a page like any other, we want to run animations and to restore focus.

Copy link
Contributor Author

@ciampo ciampo Aug 25, 2024

Choose a reason for hiding this comment

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

Do you really want to do this?

No, the logic is wrong. I had already noticed it while working on #64777. I'm going to extract and refine the fix, and apply it in a separate PR

locationHistory = goTo( state, action.path, action.options );
const goToNewState = goTo( state, action.path, action.options );
currentLocation = goToNewState.currentLocation;
focusSelectors = goToNewState.focusSelectors;
Copy link
Member

Choose a reason for hiding this comment

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

You can do a destructuring assignment in only you wrap it in parens so that it's not confused with a block:

( { currentLocation, focusSelection } = goTo() );

@ciampo
Copy link
Contributor Author

ciampo commented Aug 25, 2024

Thank you for the review, @jsnajdr — I opened #64786 to address your feedback

bph pushed a commit to bph/gutenberg that referenced this pull request Aug 31, 2024
…s#64675)

* Remove location history and only use current location

* Deprecate `options.replace`

* Make sure that two screens with the same path cannot be added

* Re-implement focus restoration relying on a map with paths as keys

* Re-implement the isInitial flag by relying on the initialPath

* Update README

* Comment map deletion out

* CHANGELOG

* Fix broken focus restoration by updating focusSelectors in the navigator reducer

* create a copy of focusSelectors map only when necessary

* Set isInitial inside the reducer, instead of on the context value

---

Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Components /packages/components [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants