From 02cf7826b3407ba0c1ac023fc6175401ddee0092 Mon Sep 17 00:00:00 2001 From: gcornut Date: Thu, 21 Jan 2021 11:31:18 +0100 Subject: [PATCH 1/2] fix(tab): fix tab state update --- packages/lumx-react/src/components/tabs/TabProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lumx-react/src/components/tabs/TabProvider.tsx b/packages/lumx-react/src/components/tabs/TabProvider.tsx index 1aaf9b418..5315f4a4e 100644 --- a/packages/lumx-react/src/components/tabs/TabProvider.tsx +++ b/packages/lumx-react/src/components/tabs/TabProvider.tsx @@ -52,7 +52,7 @@ export const TabProvider: React.FC = (props) => { onChange(state.activeTabIndex); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [onChange, propState.activeTabIndex], + [onChange, state.activeTabIndex], ); return {children}; From 0e4e1fa5440c21fe5969280e5068d3dfb6f82349 Mon Sep 17 00:00:00 2001 From: gcornut Date: Thu, 21 Jan 2021 17:45:24 +0100 Subject: [PATCH 2/2] fix(tabs): fix state on unmount/remount --- CHANGELOG.md | 1 + .../ProgressTrackerProvider.tsx | 8 +++---- .../lumx-react/src/components/tabs/state.ts | 21 ++++++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f3ae77b0..f773f86c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed `Thumbnail` focus state style. - Fixed `Thumbnail` fallback placement. - Fixed `Thumbnail` fill height style. +- Fixed `TabProvider` and `ProgressTrackerProvider` state on unmout/remount. ## [1.0.2][] - 2021-01-18 diff --git a/packages/lumx-react/src/components/progress-tracker/ProgressTrackerProvider.tsx b/packages/lumx-react/src/components/progress-tracker/ProgressTrackerProvider.tsx index 6434f6bf3..d532c8cf8 100644 --- a/packages/lumx-react/src/components/progress-tracker/ProgressTrackerProvider.tsx +++ b/packages/lumx-react/src/components/progress-tracker/ProgressTrackerProvider.tsx @@ -32,7 +32,7 @@ const DEFAULT_PROPS: Partial = { * @return React element. */ export const ProgressTrackerProvider: React.FC = (props) => { - const { children, onChange, activeStepIndex, ...propState } = props; + const { children, onChange, ...propState } = props; const [state, dispatch] = useReducer(reducer, INIT_STATE); // On prop state change => dispatch update. @@ -42,18 +42,18 @@ export const ProgressTrackerProvider: React.FC = ( type: 'update', payload: { ...propState, - activeTabIndex: activeStepIndex, + activeTabIndex: propState.activeStepIndex, }, }); }, // eslint-disable-next-line react-hooks/exhaustive-deps - [dispatch, ...Object.values(propState), activeStepIndex], + [dispatch, ...Object.values(propState)], ); // On active tab index state change => send update to the onChange. useEffect( () => { - if (state === INIT_STATE || !onChange || activeStepIndex === state.activeTabIndex) { + if (state === INIT_STATE || !onChange || propState.activeStepIndex === state.activeTabIndex) { return; } onChange(state.activeTabIndex); diff --git a/packages/lumx-react/src/components/tabs/state.ts b/packages/lumx-react/src/components/tabs/state.ts index 13c75f949..624a5257a 100644 --- a/packages/lumx-react/src/components/tabs/state.ts +++ b/packages/lumx-react/src/components/tabs/state.ts @@ -18,7 +18,8 @@ export const INIT_STATE: State = { export type Action = | { type: 'update'; payload: Partial } | { type: 'setActiveTabIndex'; payload: number } - | { type: 'register'; payload: { type: TabType; id: string } }; + | { type: 'register'; payload: { type: TabType; id: string } } + | { type: 'unregister'; payload: { type: TabType; id: string } }; export const reducer = (state: State, action: Action): State => { switch (action.type) { @@ -36,6 +37,20 @@ export const reducer = (state: State, action: Action): State => { // Append tab/tabPanel id in state. return { ...state, ids: { ...state.ids, [type]: [...state.ids[type], id] } }; } + case 'unregister': { + const { type, id } = action.payload; + const index = state.ids[type].indexOf(id); + if (index === -1) return state; + // Remove tab & tab panel at index. + const tabIds = [...state.ids.tab]; + tabIds.splice(index, 1); + const tabPanelIds = [...state.ids.tabPanel]; + tabPanelIds.splice(index, 1); + return { + ...state, + ids: { tab: tabIds, tabPanel: tabPanelIds }, + }; + } default: return state; } @@ -68,6 +83,10 @@ export const useTabProviderContext = (type: TabType, originalId?: string): undef () => { // On mount: register tab or tab panel id. dispatch({ type: 'register', payload: { type, id } }); + return () => { + // On unmount: unregister tab or tab panel id. + dispatch({ type: 'unregister', payload: { type, id } }); + }; }, // eslint-disable-next-line react-hooks/exhaustive-deps [],