Get 2024 Templates Mega Bundle!$1000 worth of 19 Bootstrap HTML, Vue & React Templates + 3 Vector Sets for just $99
Get for 99$

Reinitializing Topbar menu elements in React


Hi,

I am not sure about the exact reason, but when dinamically routing to the page or rendering the component when user data is fetched for HeaderUserMenu, the menu is not opening on click. I have to make a full page reload in order for it to work. How can one ensure the menu is working even if the component is rendered dynamically or conditionally?

Best regards,


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (20)


Hi Carmelo,

Thank you for checking it out.

You are right, it seems that the reinitialization was not the problem. After some further testing it looks like the issue is being generated by using the RTK Query hooks. I still need to do some tests to find out the right way to implement that, but the good news is that the theme is working as expected when the conditional value is in local state.

Thank you for helping me get to the bottom of this.

Best wishes,
Tamás



Hi there,

I managed to recreate the issue for you so you may be able to test it on the react demo2. Please try out this code in i18nProvider.tsx and see that after login, the HeaderUserMenu is not opening on click.


const I18nProvider: FC<WithChildren> = ({children}) => {
const locale = useLang()
const messages = allMessages[locale]

const [loading, setLoading] = useState(true)

useEffect(() => {
setLoading(true)
setTimeout(() => {
setLoading(false)
}, 2000)
}, [])

return loading ? (
<FallbackView />
) : (
<IntlProvider locale={locale} messages={messages}>
{children}
</IntlProvider>
)
}

export {I18nProvider}



Some update needs to happen somewhere that is not happening by default, and the previously suggested MenuComponent.reinitialization() and ToggleComponent.reinitialization() also didn't work.

What do you suggest?

Thank your for the support.

Best wishes,



Hi,

I've just checked your case, and all menus works, without any changes and extra re-initialization (I changed I18nProvider as you mentioned above).
MasterInit is a child element of I18nProvider and it handles all menus/toggles re-initialization inside the app.

My code of I18nProvider:

import {FC, useEffect, useState} from "react"
import {useLang} from "./Metronici18n"
import {IntlProvider} from "react-intl"
import "@formatjs/intl-relativetimeformat/polyfill"
import "@formatjs/intl-relativetimeformat/locale-data/en"
import "@formatjs/intl-relativetimeformat/locale-data/de"
import "@formatjs/intl-relativetimeformat/locale-data/es"
import "@formatjs/intl-relativetimeformat/locale-data/fr"
import "@formatjs/intl-relativetimeformat/locale-data/ja"
import "@formatjs/intl-relativetimeformat/locale-data/zh"

import deMessages from "./messages/de.json"
import enMessages from "./messages/en.json"
import esMessages from "./messages/es.json"
import frMessages from "./messages/fr.json"
import jaMessages from "./messages/ja.json"
import zhMessages from "./messages/zh.json"
import {WithChildren} from "../helpers"

const allMessages = {
de: deMessages,
en: enMessages,
es: esMessages,
fr: frMessages,
ja: jaMessages,
zh: zhMessages,
}

const I18nProvider: FC<WithChildren> = ({children}) => {
const locale = useLang()
const messages = allMessages[locale]
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
setTimeout(() => {
setLoading(false)
}, 10000)
}, [])

return loading ? (
<div>Loading ... </div>
) : (
<IntlProvider locale={locale} messages={messages}>
{children}
</IntlProvider>
)
}

export {I18nProvider}


We don't have FallbackView in our sources (maybe smth wrong with this FallbackView component).

Regards,
Keenthemes support



Hi Carmelo,

I don't see how this ticket got the 'resolved' status, the issue is not solved, as stated in my last comment. Do you have any suggestions for a workaround at least if the fix is not in sight?

Thank you for your help.



Hi Tamás,

Not sure how we can help with this. cause, we aren't able to reproduce your custom code. We can keep it as 'unresolved' but in that case, I will not be able to receive notifications about new answers in the thread.

Anyway, try to check User management module src/app/modules/apps/user-management/users-list.
Here is a lot of dynamic rendering (including fetching the data from the server and rendering them + conditional rendering) with working menus:
1) Actions component (Actions menu in the table): src/app/modules/apps/user-management/users-list/table/columns/UserActionsCell.tsx
2) Filter: src/app/modules/apps/user-management/users-list/components/header/UsersListFilter.tsx

Regards,
Keenthemes support



That's unfortunate. Anyway, thanks for the tips. I have no issue anywhere else with conditional rendering and fetching data from the server. Only this issue I am having with the i18nProvider and the Menus. What to do, I'll try to refactor the logic and see if I can circumvent this.

Thank you for looking at it.

Best wishes,



Yes, isLoading is there in the deps array of I18nProvider useEffect.



Hi,

That didn't help, but I've found that the issue was not caused in that component. Earlier I have implemented some logic for the I18nProvider component, where I fetch the user language from the backend.

I have this in the I18nProvider.tsx:


return isLoading ? (
<LoadingView />
) : (
<IntlProvider locale={locale} messages={messages}>
{children}
</IntlProvider>


It seems if I remove the conditional logic, it works, but then how to show a loading screen until the user language is being fetched? What is the right way to do this?

Thank you



Hi,

In that case try to add isLoading into the useEffect into the deps array.

Regards,
Keenthemes support



Also, you can write a wrapper component for your {children} and call re-init when this component will be mounted into the DOM.

Regards,
Keenthemes support



Did you mean like this:


const Wrapper: FC<WithChildren> = ({children}) => {
useEffect(() => {
MenuComponent.reinitialization()
}, [])
return <>{children}</>
}


and wrapping the children in i18nProvider.tsx

Unfortunately it didn't solve the issue. Something is really misbehaving under the hood.



Hi,

Wrap MenuComponent.reinitialization() into setTimout, we have to be sure that your component is already mounted. *You can check example in src/_metronic/layout/MasterInit.tsx file.
Also you haven't added ToggleComponent reinitialization also.

Regards,
Keenthemes support




const Wrapper: FC<WithChildren> = ({children}) => {
useEffect(() => {
setTimeout(() => {
ToggleComponent.bootstrap()
MenuComponent.bootstrap()
}, 1500)
}, [])
return <>{children}</>
}


I tried adjusting the timeout value also, no luck.



Hi Carmelo,

I made a very simple modification in the TopBar.tsx in Metronic Demo2 so you can test the logic. I am using RTK Query to get the user and pass it as a prop to HeaderUserMenu component. I have tested user, isLoading, isSuccess properties for updating the component without any success.

I have also tried to move the fetching logic into the HeaderUserMenu, but the results is the same.

https://gist.github.com/tom3rr/dd4a2cdaf19554e2dc899b43c06e55e7

What am I missing?

Thanks for your help,
Tamás



Hi,

Try also add ToggleComponent.bootstrap(),
Maybe it will help to active toggling. Quite not sure, but other things looks fine.

Regards,
Keenthems support



Hi Carmelo,

I tried your suggestion, it still doesn't work. I don't understand why is this strange behaviour. I would simply like to load the user data from the backend and render the name in the HeaderUserMenu. After login, when the page is redirected it doesn't work, on refreshing the page it works again. MenuComponent.reinitialization does not seem to have any effect, no matter what the dependency array on useEffect is.

How could this be done properly?

Thank you for your help.



Hi,

Please share with us how you implemented it (you can use GitHub gist for it), maybe we can try to check it.

Regards,
Keenthemes support



Hi Carmelo,

I've added the code to the HeaderUserMenu component like this:


useEffect(() => {
setTimeout(() => {
MenuComponent.reinitialization()
}, 500)
}, [])


This component is conditionally rendered in TopBar.tsx when the user data is fetched from the server.

It is simply not working after I login, the menu is not opening. Some menus, like the dark mode switcher, chat, search and activity logs are working, but the rest is not. What could be the issue?

Thanks a lot.



Hi,

In useEffect in the dependencies array, you can add location from const location = useLocation();.
Then it will re-init the menu when you route to the page.

Regards,
Keenthemes support



Hi,

Once your HeaderUserMenu is ready and mounted to the DOM, you can run:
setTimeout(() => {
MenuComponent.reinitialization()
}, 500)

import {MenuComponent} from '{pass_to_assets}assets/ts/components'.
It will re-init your menu then.

Regards,
Keenthemes support


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(