Lazy initialized TabBar #634
-
Thanks for the library. e.g: RNN & RN lazy options |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 30 replies
-
Hey, I'm glad you're enjoying the Navigation router. You can add an const [tab, setTab] = useState(0);
const loaded = useRef({0: true});
<TabBar
tab={tab}
onChangeTab={(newTab) => {
setTab(newTab);
if (!loaded.current[newTab]) loaded.current[newTab] = true;
}}
> Then you can use <TabBarItem title="Notifications">
<Notifications loaded={loaded.current[1]} />
</TabBarItem> Then the Notifications component can only load its content when loaded is true. Notice that I'm rendering a shell and the loaded check is conditionally loading the content (it's important that you render a real native view into the const Notifications = ({ loaded }) => (
<SafeAreaView style={{flex: 1}}>
<CoordinatorLayout>
{loaded && (
<>
<NavigationBar If you have a <TabBarItem title="Notifications">
<NavigationHandler stateNavigator={notificationsNavigator}>
<NavigationStack>
<Scene stateKey="notifications"><Notifications loaded={loaded.current[1]} /></Scene>
<Scene stateKey="tweet"><Tweet /></Scene>
</NavigationStack>
</TabBarItem> I hope this helps but please let me know if any of it isn't clear. I'm happy to go into more detail if you want. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the detailed explanation. Currently your explanation best approach so I will mark as answered. On the other hand, I think we should do this on native side. This library looks most performant in this navigation area. So i think it's better to keep handling lazy TabBar options on native side rather than lean on react state. I wish I could check if it can be done in native and make a PR(not have native exp.) but don't have time these days because of our app needs to be finalize :/ Thanks again. |
Beta Was this translation helpful? Give feedback.
-
Hey, I don’t think lazy loading tabs works that well if it’s built into the Navigation router. In the Twitter example, if the notifications tab is lazy loaded then when first selecting it it will show blank until the notifications fetch completes. Because the tab doesn’t render it until it’s selected, the query can’t start until then. Over the weekend, I managed to freeze the inactive tabs. This could work a bit better because the Navigation router could delay the freeze to allow for a first render to happen even on the inactive tabs. Then when switching to the notifications tab the query will have already returned. But what if the notifications tab takes more than one state update to fully render? In that case, it won’t be finished when first switching. I think this is better left in userland because it’s the developer that knows how best to load the content of the inactive tabs. For example, the developer could What do you think? |
Beta Was this translation helpful? Give feedback.
-
Hey there @burakgormek I've got a new idea that I'd like to run past you. I'll just give a bit of background first. The Navigation router freezes scenes (using React Suspense) that are hidden in the stack. Frozen scenes receive state updates but don't render. When the user navigates back, the Navigation router unfreezes the previous scene so it can render with its latest state. We want to do the same thing with tabs. But tabs are different to scenes because all but one of the tabs start as inactive (scenes are always active when they first appear). We don't want to freeze inactive tabs straight away because they won't have done a single render. So when the user switches to them they'll flash blank before the first render happens. So the Navigation router has to let tabs render before freezing them. But there's no way for the Navigation router to know when a tab has loaded (finished rendering). It might take a few render cycles for the tab to be considered loaded. In the following (pseudocode) example, it takes 2 renders for notifications to load. const NotificationsTab = () => {
const [notifications, setNotifications] = useState();
useEffect(() => {
const data = await fetch();
setNotifications(data);
}, [])
} But in this example it takes 3 renders. The notifications aren't fetched until const Notifications = () => {
const [notifications, setNotifications] = useState();
const [run, setRun] = useState(false);
useEffect(() => {
setRun(true);
}, []);
useEffect(() => {
if (run) {
const data = await fetch();
setNotifications(data);
}
}, [run])
} My new idea is to let the developer tell the Navigation router when the tab has loaded! We'll create a const Notifications = () => {
const {loaded} = useContext(TabBarItemContext);
useEffect(() => {
if (notifications) {
loaded();
}
}, [notifications]);
} I haven't talked about lazy initialization yet. But really that's just a special case of this generic solution. For example, if the developer wants to do a 'traditional' lazy initialization then they call useEffect(() => {
loaded();
const data = await fetch();
setNotifications(data);
}, []) |
Beta Was this translation helpful? Give feedback.
-
Hey, sorry for late response. I've seen that you're working on it(tab branch). Nice idea to control render. Dev. can choose a complex&controllable way(useEffect) or a simplified way to control render. |
Beta Was this translation helpful? Give feedback.
-
This has been fixed by #650 Thanks @burakgormek for the great discussion. I really enjoyed chewing over some ideas with you. Hopefully we can work together again on something. I’ll thank you more formally in the release notes. In summary, the Navigation router freezes inactive tabs once they’ve been visited. To handle freezing an inactive tab that hasn’t been visited, there’s a const NotificationsTab = () => {
const {onLoad} = useContext(TabBarItemContext);
const [notifications, setNotifications] = useState();
useEffect(() => {
onLoad();
const data = await fetch();
setNotifications(data);
}, [])
} |
Beta Was this translation helpful? Give feedback.
This has been fixed by #650
Thanks @burakgormek for the great discussion. I really enjoyed chewing over some ideas with you. Hopefully we can work together again on something. I’ll thank you more formally in the release notes.
In summary, the Navigation router freezes inactive tabs once they’ve been visited. To handle freezing an inactive tab that hasn’t been visited, there’s a
TabBarItemContext
with anonLoad
function. The user callsonLoad
once it’s safe to freeze. In a Twitter example, the notifications tab is frozen once the data is fetched,