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 tab group sync #8483

Closed
wants to merge 1 commit into from
Closed

Fix tab group sync #8483

wants to merge 1 commit into from

Conversation

0916dhkim
Copy link
Contributor

@0916dhkim 0916dhkim commented Dec 25, 2022

Pre-flight checklist

  • I have read the Contributing Guidelines on pull requests.
  • If this is a code change: I have written unit tests and/or added dogfooding pages to fully verify the new behavior.
  • If this is a new API or substantial change: the PR has an accompanying issue (closes #0000) and the maintainers have approved on my working plan.

Motivation

Fixing #8473

Test Plan

  1. Test Syncing tab choices section of Docusaurus Tabs page. Syncing feature should work as expected.
  2. Test Query string section of the same page. "Android, iOS" tab group should be synced and URL query params should change on select.

Test links

Deploy preview: https://deploy-preview-8483--docusaurus-2.netlify.app/

Related issues/PRs

fix #8473

#8225

@netlify
Copy link

netlify bot commented Dec 25, 2022

[V2]

Built without sensitive environment variables

Name Link
🔨 Latest commit c44e113
🔍 Latest deploy log https://app.netlify.com/sites/docusaurus-2/deploys/63a8b4743c958b0008f8a906
😎 Deploy Preview https://deploy-preview-8483--docusaurus-2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@github-actions
Copy link

⚡️ Lighthouse report for the deploy preview of this PR

URL Performance Accessibility Best Practices SEO PWA Report
/ 🟢 94 🟢 97 🟢 100 🟢 100 🟢 90 Report
/docs/installation 🟠 79 🟢 100 🟢 100 🟢 100 🟢 90 Report

Copy link
Contributor Author

@0916dhkim 0916dhkim left a comment

Choose a reason for hiding this comment

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

Changes Summary

Current implementation does not update selectedValue when there is a query parameter or local storage change (only restores on mount). That's why tab group sync is not working.

Because selected tab is stored in React state, local storage, and query params, I thought it would be helpful to manage all three in tabGroupChoice.tsx module.

New structure

const {selectedValue, setTabGroupChoice} = useTabGroupChoice(...);
  • setTabGroupChoice updates selectedValue, local storage (if groupId is given), and query params (if queryString is given).
  • When a value in local storage or query params changes, selectedValue is updated to match that value. This is the mechanism of syncing multiple tabs in a group.

const defaultValue =
defaultValueProp !== undefined
? defaultValueProp
: children.find((child) => child.props.default)?.props.value ??
children[0]!.props.value;

const [selectedValue, setSelectedValue] = useState(defaultValue);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Manage selectedValue state inside useTabGroupChoice hook.

Comment on lines 109 to -195
blockElementScrollPositionUntilNextRender(newTab);
setSelectedValue(newTabValue);
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 thought of moving blockElementScrollPositionUntilNextRender into tabGroupChoice.tsx, but decided to leave it as-is. Let me know if you think it's better to move it.

Comment on lines -22 to +26
/** A boolean that tells if choices have already been restored from storage */
readonly ready: boolean;
/** A map from `groupId` to the `value` of the saved choice. */
readonly tabGroupChoices: {readonly [groupId: string]: string};
/** A map from `groupId` to the `value` of the saved choice in storage. */
readonly tabGroupChoicesInStorage: {readonly [groupId: string]: string};
/** A map from `searchKey` to the `value` of the choice in query parameter. */
readonly tabGroupChoicesInQueryParams: {readonly [searchKey: string]: string};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • Remove ready property.
  • Manage both local storage values & query param values in this context.

(groupId: string, newChoice: string) => {
setChoices((oldChoices) => ({...oldChoices, [groupId]: newChoice}));
setChoiceSyncWithLocalStorage(groupId, newChoice);
const setTabGroupChoice = useCallback(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

setTabGroupChoice pushes tab choice to local storage or query param depending on groupId & queryString.

Comment on lines +173 to +184
// Sync storage, query params, and selected state.
useEffect(() => {
const queryParamValue =
searchKey && context.tabGroupChoicesInQueryParams[searchKey];
const storageValue = groupId && context.tabGroupChoicesInStorage[groupId];
const valueToSync = queryParamValue ?? storageValue;
const isValid =
!!valueToSync && values.some(({value}) => value === valueToSync);
if (isValid && valueToSync !== selectedValue) {
setSelectedValue(valueToSync);
}
}, [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Essence of this PR: Detect changes in local storage or query params, then update selectedValue accordingly.

@slorber
Copy link
Collaborator

slorber commented Dec 27, 2022

Thanks

Will review this more deeply later, but in the meantime this PR breaks the querystring feature.

Opening this in a new session (clean/empty localstorage) should focus the iOS tab, but it doesn't anymore:
https://deploy-preview-8483--docusaurus-2.netlify.app/docs/markdown-features/tabs/?current-os=ios#query-string

@slorber
Copy link
Collaborator

slorber commented Dec 28, 2022

Thanks for trying, but I'm going to open a different PR with a totally different way to handle things (useSyncExternalStore)

The current legacy way is not ideal and I'd like to get rid of this provider and react state synchronisation. As we can see, this leads to subtle bugs and is overly complex

@0916dhkim
Copy link
Contributor Author

@slorber No problem! I was concerned about adding more to the context too, and now excited to see a better implementation 😄

@slorber
Copy link
Collaborator

slorber commented Dec 28, 2022

Thanks

Closing this PR in favor of #8486

Can you help review and let me know if you see any issue?

@slorber slorber closed this Dec 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tab sync using groupId not functioning
3 participants