-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(demo): custom bottom bar component (#962)
Fix double rendering of the custom bottom bar component by refactoring the following pieces: - context: switch to using the reducer pattern, and expose 3 methods: `getElementProps`, `setElementProps`, `setElement`. - core component: render any child element of the custom "non-render" element, not just the assumed single-child - custom element: set the `registered` attribute on the element upon setting the props in the context, to avoid re-render loops when the screen holding the custom element re-renders. This does not prevent server side updates of the tab bar. - update the demo app to factorize the markup for the tab bar as well as to show case the server updates of the tab bar. Special thanks to @ehenighan for the thorough investigation and help solving #956. https://github.com/user-attachments/assets/756d8585-d563-4a23-b845-3b42a843c4e7 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a notification badge design for the bottom tab bar. - Added a new tab bar component to manage notifications within the second tab. - **Enhancements** - Improved the BottomTabBar's context management with a reducer pattern for better state handling. - Streamlined the BottomTabBar component's logic and rendering process. - Enhanced tab navigation with a modular approach for dynamic rendering. - **Bug Fixes** - Resolved rendering loops in the BottomTabBar component. - **Documentation** - Updated context exports to prioritize the new custom hook for easier access. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: flochtililoch <[email protected]>
- Loading branch information
1 parent
68067f6
commit a3c783a
Showing
12 changed files
with
233 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
demo/backend/navigation/navigator/bottom-tabs/tab-bar-notify-tab-2.xml.njk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
permalink: "/navigation/navigator/bottom-tabs/tab-bar-notify-tab-2.xml" | ||
|
||
--- | ||
{% set selected_tab = 2 %} | ||
{% set notify_tab = 2 %} | ||
{% include "./tab-bar.xml.njk" %} |
51 changes: 51 additions & 0 deletions
51
demo/backend/navigation/navigator/bottom-tabs/tab-bar.xml.njk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<navigation:bottom-tab-bar | ||
xmlns="https://hyperview.org/hyperview" | ||
xmlns:navigation="https://hyperview.org/navigation" | ||
navigation:navigator="custom-bottom-tabs-navigator" | ||
id="bottom-tab-bar" | ||
> | ||
<select-single style="tabbar-bottom" name="custom-tab-bar" key="custom-tab-bar"> | ||
<option | ||
{% if selected_tab == 1 %} | ||
selected="true" | ||
{% endif %} | ||
style="tabbar-bottom-tab" | ||
value="custom-tab-1" | ||
> | ||
<behavior trigger="select" action="navigate" target="custom-bottom-tabs-tab-1" /> | ||
<view style="tabbar-bottom-tab-content"> | ||
<view style="tabbar-bottom-tab-icon-selected"> | ||
{% include 'icons/behaviors-selected.svg' %} | ||
</view> | ||
<view style="tabbar-bottom-tab-icon"> | ||
{% include 'icons/behaviors.svg' %} | ||
</view> | ||
<text style="tabbar-bottom-tab-label">Tab 1</text> | ||
{% if notify_tab == 1 %} | ||
<view style="tabbar-bottom-tab-notify" /> | ||
{% endif %} | ||
</view> | ||
</option> | ||
<option | ||
{% if selected_tab == 2 %} | ||
selected="true" | ||
{% endif %} | ||
style="tabbar-bottom-tab" | ||
value="custom-tab-2" | ||
> | ||
<behavior trigger="select" action="navigate" target="custom-bottom-tabs-tab-2" /> | ||
<view style="tabbar-bottom-tab-content"> | ||
<view style="tabbar-bottom-tab-icon-selected"> | ||
{% include 'icons/advanced-selected.svg' %} | ||
</view> | ||
<view style="tabbar-bottom-tab-icon"> | ||
{% include 'icons/advanced.svg' %} | ||
</view> | ||
<text style="tabbar-bottom-tab-label">Tab 2</text> | ||
{% if notify_tab == 2 %} | ||
<view style="tabbar-bottom-tab-notify" /> | ||
{% endif %} | ||
</view> | ||
</option> | ||
</select-single> | ||
</navigation:bottom-tab-bar> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,113 @@ | ||
import React, { createContext, useState } from 'react'; | ||
import React, { | ||
createContext, | ||
useCallback, | ||
useContext, | ||
useReducer, | ||
} from 'react'; | ||
import type { HvComponentProps } from 'hyperview'; | ||
|
||
type ElementProps = Record<string, HvComponentProps>; | ||
type State = Record<string, HvComponentProps>; | ||
|
||
type Action = { | ||
type: string; | ||
payload: { | ||
navigator: string; | ||
} & Partial<{ | ||
props: HvComponentProps; | ||
element: Element; | ||
}>; | ||
}; | ||
|
||
/** | ||
* React context that provides the Hyperview demo app with a state | ||
* holding the navigation elements rendered by each screens that | ||
* React navigation navigators use to drive navigation. | ||
*/ | ||
export const BottomTabBarContext = createContext<{ | ||
elementsProps: ElementProps | undefined; | ||
setElementProps: ((id: string, props: HvComponentProps) => void) | undefined; | ||
const Context = createContext<{ | ||
getElementProps: | ||
| ((navigator: string) => HvComponentProps | undefined) | ||
| undefined; | ||
setElement: ((navigator: string, element: Element) => void) | undefined; | ||
setElementProps: | ||
| ((navigator: string, props: HvComponentProps) => void) | ||
| undefined; | ||
}>({ | ||
elementsProps: undefined, | ||
getElementProps: undefined, | ||
setElement: undefined, | ||
setElementProps: undefined, | ||
}); | ||
|
||
export function BottomTabBarContextProvider(props: { | ||
children: React.ReactNode; | ||
}) { | ||
const [elementsProps, setElementsProps] = useState<ElementProps>({}); | ||
return ( | ||
<BottomTabBarContext.Provider | ||
value={{ | ||
elementsProps, | ||
setElementProps: (id: string, p: HvComponentProps) => { | ||
setElementsProps({ ...elementsProps, [id]: p }); | ||
const initialState: State = {}; | ||
|
||
type Reducer<S, A> = (prevState: S, action: A) => S; | ||
|
||
const reducer: Reducer<State, Action> = ( | ||
state: State = initialState, | ||
action: Action, | ||
) => { | ||
const { element, navigator, props } = action.payload; | ||
switch (action.type) { | ||
case 'SET_ELEMENT_PROPS': | ||
if (!props) { | ||
return state; | ||
} | ||
return { | ||
...state, | ||
[navigator]: props, | ||
}; | ||
case 'SET_ELEMENT': | ||
if (!element) { | ||
return state; | ||
} | ||
return { | ||
...state, | ||
[navigator]: { | ||
...(state[navigator] || {}), | ||
element, | ||
}, | ||
}; | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
export function BottomTabBarContextProvider(p: { children: React.ReactNode }) { | ||
const [state, dispatch] = useReducer(reducer, initialState); | ||
const getElementProps = useCallback( | ||
(navigator: string) => { | ||
return state[navigator]; | ||
}, | ||
[state], | ||
); | ||
const setElement = useCallback( | ||
(navigator: string, element: Element) => { | ||
dispatch({ | ||
payload: { | ||
element, | ||
navigator, | ||
}, | ||
type: 'SET_ELEMENT', | ||
}); | ||
}, | ||
[dispatch], | ||
); | ||
const setElementProps = useCallback( | ||
(navigator: string, props: HvComponentProps) => { | ||
dispatch({ | ||
payload: { | ||
navigator, | ||
props, | ||
}, | ||
}} | ||
> | ||
{props.children} | ||
</BottomTabBarContext.Provider> | ||
type: 'SET_ELEMENT_PROPS', | ||
}); | ||
}, | ||
[dispatch], | ||
); | ||
return ( | ||
<Context.Provider value={{ getElementProps, setElement, setElementProps }}> | ||
{p.children} | ||
</Context.Provider> | ||
); | ||
} | ||
|
||
export const useBottomTabBarContext = () => useContext(Context); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
export { | ||
BottomTabBarContext, | ||
useBottomTabBarContext, | ||
BottomTabBarContextProvider, | ||
} from './BottomTabBar'; |
Oops, something went wrong.