Closed kirillplatonov closed 7 months ago
I can see this issue too.
I have the same issue. There is currently no way to subscribe to Redirect action. This is last thing that prevents me from migrating to the CDN version
Hello, thanks for your report.
Can you try specifying your app's root path as the first item in the nav menu, and adding rel="home"
to that link? This is what our docs specify.
For example:
<ui-nav-menu>
<a href="/" rel="home">Home</a>
<a href="/first-page">First page</a>
<a href="/second-page">Second page</a>
</ui-nav-menu>
Hello, thanks for your report.
Can you try specifying your app's root path as the first item in the nav menu, and adding
rel="home"
to that link? This is what our docs specify.For example:
<ui-nav-menu> <a href="/" rel="home">Home</a> <a href="/first-page">First page</a> <a href="/second-page">Second page</a> </ui-nav-menu>
That doesn't seem to work. I think the page has to be cached like it was done in the previous app bridge
Use react Link to=""
instead of <a href=""
We are experiencing the same problem, please Shopify considers our users who don't use Remix, I looked at the original app bridge react part of the code and there is a CustomRouter defined in there to synchronize the paths between shopify and the app, how can we implement this please
Use react
Link to=""
instead of<a href=""
Thanks. This actually works!!
Use react
Link to=""
instead of<a href=""
Thank you very much. It really works.
This doesn't solve the problem for non-react apps. We still need a proper way to make it work with normal links without hacks. Same way as Navigation
component works: https://shopify.dev/docs/api/app-bridge-library/reference/navigation#example-navigating-to-routes-within-your-app
You can do this in plain JavaScript. The key is to prevent browser's default behaviour with event.preventDefault()
. Something like this should work:
<ui-nav-menu>
<a href="/" rel="home" onclick="navigate">Home</a>
<a href="/first-page" onclick="navigate">First page</a>
<a href="/second-page" onclick="navigate">Second page</a>
</ui-nav-menu>
<script>
function navigate(event) {
event.preventDefault();
history.pushState({}, null, event.target.href);
}
</script>
Yeah, it's true. We doing something similar for Turbo
as well. But it's still broken out of the box and needs to be fixed.
You can do this in plain JavaScript. The key is to prevent browser's default behaviour with
event.preventDefault()
. Something like this should work:<ui-nav-menu> <a href="/" rel="home" onclick="navigate">Home</a> <a href="/first-page" onclick="navigate">First page</a> <a href="/second-page" onclick="navigate">Second page</a> </ui-nav-menu> <script> function navigate(event) { event.preventDefault(); history.pushState({}, null, event.target.href); } </script>
Is this actually working for you? I've just tested it out and there isn't any difference. The AppBridge navigation is still sending unauthenticated requests into the app - causing page reloading.
It's definitely a hack and behaviour could easily break if not part of AppBridge by default - so I would not advise caution to anyone reading into this.
@kirillplatonov has the right sentiment here - AppBridge should send these requests with the Bearer token provided, so the app can simply load the view without reloading/redirecting.
Yes, it works for me and no, it's not a hack. This is what React Router Link
is doing under the hood.
This code only updates browser URL without navigating to specific page:
history.pushState({}, null, event.target.href);
It's suitable as a fix for #242 when you need to keep focus on the right menu element. But not as a fix for navigation itself.
I incorrectly assumed that the example app is an SPA. In this case dynamic links won't help as they would require some kind of router that would update the page accordingly.
Maybe it would be possible to workaround this issue with View Transitions API but it's just a guess. I hope app bridge gets a fix for static links in the Navigation component.
For those using React, @shopify/app-bridge 3.4.3, react-router-dom 5.3.0.
I also encountered the app reloading when clicking on a navigation item until I used this code on the AppBridgeProvider:
app.subscribe(Redirect.Action.APP, function() {});
Hi everyone, I have a few notes about this:
<ui-nav-menu>
<a href="/first-page">First page</a>
<a href="/second-page">Second page</a>
</ui-nav-menu>
preventDefault()
like below which is what the Link
component does in remix template<ui-nav-menu>
<a href="/first-page">First page</a>
<a href="/second-page">Second page</a>
</ui-nav-menu>
// In Javascript
document.querySelector('ui-nav-menu').addEventListener('click', (e) => {
if (e.target.nodeName === 'A') {
// handle your own redirect here
e.preventDefault();
}
});
Hi @henrytao-me
I've tried adding the click event listener, and have confirmed the ui-nav-menu
is found in the DOM, but the click event is not firing. I suspect the version on this CDN is not the latest?
https://cdn.shopify.com/shopifycloud/app-bridge.js
?Hi @henrytao-me
I'm having trouble with the event listener as well. It only seems to trigger when clicking back and forth.
https://github.com/Shopify/shopify-app-bridge/assets/1133950/b82011f7-e794-47c9-9a2d-668aef965e5c
Update
Managed to get it working by adding history.pushState({}, null, event.target.href);
after handling the redirect.
Use react
Link to=""
instead of<a href=""
Where is this component front? from polaris doesn't have a to field anymore.
Hi all, I just want to follow up on this issue. Let's me know if anyone is still having issue with this.
It was helpful for me
Use react
Link to=""
instead of<a href=""
Thank you very much. It really works.
Hi all, I just want to follow up on this issue. Let's me know if anyone is still having issue with this.
TL;DR about how App Bridge CDN handles redirect
- For multiple page apps, clicking on side nav items will reload the iframe with correct hmac
- For single page apps, apps need to addEventListener to the anchor tag and handle redirect manually. The url is not signed with hmac because the apps want to handle it manually. This comment is correct App Bridge 4 clicking on Navigation Menu causes app reload #240 (comment)
Hi @henrytao-me,
For single-page apps, manually implementing redirection may work, but afterward, if you click the browser's back button, it might not redirect properly. This issue could occur because the URL is not signed with HMAC. Please let me know if there is a solution for this problem.
Vue 3 example:
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ref, watch } from 'vue'
const router = useRouter()
function navigate(event: MouseEvent) {
const pathname = (event.target as HTMLAnchorElement).pathname
history.pushState({}, '', pathname)
router.replace(pathname)
}
// Re-render ui-nav-menu on route change
const key = ref(0)
watch(router.currentRoute, () => key.value++)
</script>
<template>
<ui-nav-menu :key="key">
<a href="/" rel="home" @click.prevent="navigate">Home</a>
<a href="/page-1" @click.prevent="navigate">Page 1</a>
<a href="/page-2" @click.prevent="navigate">Page 2</a>
</ui-nav-menu>
</template>
Vue 3 example:
<script setup lang="ts"> import { useRouter } from 'vue-router' import { ref, watch } from 'vue' import { useI18n } from 'vue-i18n' const router = useRouter() const { t } = useI18n() function navigate(event: MouseEvent) { const pathname = (event.target as HTMLAnchorElement).pathname history.pushState({}, '', pathname) router.replace(pathname) } // Re-render ui-nav-menu on route change const key = ref(0) watch(router.currentRoute, () => key.value++) </script> <template> <ui-nav-menu :key="key"> <a href="/" rel="home" @click.prevent="navigate">{{ t('home') }}</a> <a href="/page-1" @click.prevent="navigate">{{ t('page-1') }}</a> <a href="/page-2" @click.prevent="navigate">{{ t('page-2') }}</a> </ui-nav-menu> </template>
Hi @tobiasdalhof, The solution provided doesn't work for me. Additionally, I have a React app, and my code is as follows:
import { useNavigate } from "react-router-dom"; // v6
const navigate = useNavigate();
const pageRedirect = useCallback((e) => {
e.preventDefault();
window.history.pushState({}, '', e.target.href);
navigate(e.target.pathname);
}, [navigate]);
<NavMenu>
{Object.values(shopifyNavigation).map((i, index) => {
return (
<a
href={i.destination}
key={index}
onClick={pageRedirect}
>
{i.label}
</a>
);
})}
</NavMenu>
Here, I'm loading all nav-items dynamically
@jbeladiya , example from my project:
import {NavMenu} from "@shopify/app-bridge-react";
import {Link} from "react-router-dom";
<NavMenu>
<Link to="/">General settings</Link>
<Link to="/faq">FAQ</Link>
<Link to="/support">Support</Link>
<Link to="/plans-and-pricing">Plans and pricing</Link>
</NavMenu>
General settings
@sebastianpisula, approach is same. When I click on a navigation item, I am redirected to a specific route with that particular item highlighted. However, I am facing an issue because in my app, I have a back button to redirect to the previous screen or a specific route. When I click on the back button, it navigates to the specific route, but the corresponding navigation item is not highlighted at that time.
https://github.com/Shopify/shopify-app-bridge/assets/120442287/c6d6782d-7e95-425a-8166-d9f88e3c824c
Hi @jbeladiya If you didn't already solve your issue here is a code snippet for you to try:
import { NavMenu } from "@shopify/app-bridge-react";
import { useMemo } from "react";
import { useLocation, Link } from "react-router-dom";
const location = useLocation();
const navMenu = useMemo(() =>
<NavMenu key={location.key}>
{Object.values(shopifyNavigation).map((i, index) => {
return (
<Link to={i.destination}>
{i.label}
</Link>
);
})}
</NavMenu>, [location, shopifyNavigation]);
{ navMenu }
I didn't test with dynamic values so am not sure if it works like this, but here is a simple snippet that I already use in production:
import { NavMenu } from "@shopify/app-bridge-react";
import { useMemo } from "react";
import { useLocation, Link } from "react-router-dom";
const location = useLocation();
const navMenu = useMemo(() =>
<NavMenu key={location.key}>
<Link to="/" rel="home">
Home
</Link>
<Link to="/page1">
Page1
</Link>
<Link to="/page2">
Page2
</Link>
</NavMenu>, [location]);
{ navMenu }
Hope this helps future readers.
Hi @jbeladiya If you didn't already solve your issue here is a code snippet for you to try:
import { NavMenu } from "@shopify/app-bridge-react"; import { useMemo } from "react"; import { useLocation, Link } from "react-router-dom"; const location = useLocation(); const navMenu = useMemo(() => <NavMenu key={location.key}> {Object.values(shopifyNavigation).map((i, index) => { return ( <Link to={i.destination}> {i.label} </Link> ); })} </NavMenu>, [location, shopifyNavigation]); { navMenu }
I didn't test with dynamic values so am not sure if it works like this, but here is a simple snippet that I already use in production:
import { NavMenu } from "@shopify/app-bridge-react"; import { useMemo } from "react"; import { useLocation, Link } from "react-router-dom"; const location = useLocation(); const navMenu = useMemo(() => <NavMenu key={location.key}> <Link to="/" rel="home"> Home </Link> <Link to="/page1"> Page1 </Link> <Link to="/page2"> Page2 </Link> </NavMenu>, [location]); { navMenu }
Hope this helps future readers.
Hi @underwoodsimon it's work for me. Thanks. But other side browser back not working properly when I click on browser back two or three time then after it's redirect to previous route. If you have also solution for it let me know.
@jbeladiya I also faced that issue during development, most likely because react renders twice in strict mode. So probably there are multiple entries of the same location in the browser history and you need to click twice or more on the back button. You need to test on production to see if there is a difference.
Use react
Link to=""
instead of<a href=""
👍
This code only updates browser URL without navigating to specific page:
history.pushState({}, null, event.target.href);
It's suitable as a fix for #242 when you need to keep focus on the right menu element. But not as a fix for navigation itself.
I'm trying to switch pages via navigate and change the active menu in the left menus, but I can't seem to get it to work, I'm using open('/path', '_self') but it causes the app to be reloaded, there's Any solution?
Describe the bug
When clicking on any link in Navigation Menu the app is fully reloaded to open new page. It starts loading from scratch with splash screen, token fetching, etc. This slows down loading dramatically and just looks weird for users.
To Reproduce
Steps to reproduce the behaviour:
https://github.com/Shopify/shopify-app-bridge/assets/839922/c521a87d-2492-4f3c-8901-55c025e11755
Expected behaviour
App Bridge should treat Navigation Menu clicks as in-app navigation. Same as navigating relative link within app: https://shopify.dev/docs/api/app-bridge-library/reference/navigation#example-navigating-to-routes-within-your-app
If this is not possible then at least we should have a way to add event handler and override Navigation Menu behaviour. This is how we've done it with App Bridge 3: https://github.com/kirillplatonov/shopify-hotwire-sample/blob/main/app/javascript/shopify_app/navigation.js#L25
Contextual information
Packages and versions
App Bridge 4
from CDNPlatform
Additional context
Tech stack: