nextjs <a> inside <Link> results in 2 history stacks - next.js

When I click on Hello, it redirects ok but to browse back to where i was by clicking back button, it requires 2 back button clicks. (probably because <Link> and <a> are triggered at the same time)
export default function Navigation() {
const router = useRouter()
const menus = [
{ key: 'key1', title: 'title1', clasName: 'class1' },
{ key: 'key2', title: 'title2', clasName: 'class2' },
]
return (
<div role="tablist">
{menus.map(({ key, title, className }) => (
<Link
href={{
pathname: router.pathname,
query: {
menu: key
}
}}>
<a
className={className}
role="tab">
<span>{title}</span>
</a>
</Link>
))}
</div>
)
}
I have to use <a> to apply className.
Only using <a> causes page to rerender even when href is same as current page.
What should I do to prevent 2 history stacks being inserted?
Thanks!

Apparently it was my custom popstate event listener that was pushing an extra stack into History. Thanks all for your comments

Related

How to pass a big data object to another page with dynamic route in next js (without query params)?

I have a page where I fetch data and map through it.
In my map function I display a card component with some data like this:
pokemonsList?.map((pokemon, index) => {
return (
<Link href={`/pokemon/${pokemon.id}`} key={index}>
<a>
<Card pokemon={pokemon} />
</a>
</Link>
);
}
As you can see, the route is dynamic.
What I would like to do is to pass the whole pokemon object to the page.
I would like to achieve this without using the next router query method, because the object contains a lot of data.
Is there an other way ?
You could cache it, either by using some global state management package (Redux, React Query) or inbuilt Context API.
Or
<Link
href={{
pathname: '/pokemon',
query: {
id: pokemon.id,
pokemon: JSON.stringify(pokemon)
}
}}
as={`/pokemon/${pokemon.id}`}
key={index}>
<a>
<Card pokemon={pokemon} />
</a>
</Link>
And then on the page
const { query } = useRouter();
const pokemon = JSON.parse(query.pokemon);

VUE3.JS - Modal in a loop

I have a GET request in my home.vue component.
This query allows me to get an array of objects.
To display all the objects, I do a v-for loop and everything works fine.
<div class="commentaires" v-for="(com, index) of coms" :key="index">
My concern is that I want to display an image by clicking on it (coms[index].imageUrl), in a modal (popup).
The modal is displayed fine but not with the correct image, i.e. the modal displays the last image obtained in the loop, which is not correct.
Here is the full code of my home.vue component
<template>
<div class="container">
<div class="commentaires" v-for="(com, index) of coms" :key="index">
<modale :imageUrl="com.imageUrl_$this.index" :revele="revele" :toggleModale="toggleModale"></modale>
<img class="photo" :src=""" alt="image du commentaire" #click="toggleModale">
</div>
</div>
</template>
<script>
//import axios from "axios";
import axios from "axios";
import Modale from "./Modale";
export default {
name: 'HoMe',
data() {
return {
coms: [],
revele: false
}
},
components: {
modale: Modale
},
methods: {
toggleModale: function () {
this.revele = !this.revele;
},
</script>
Here is my modale.vue component
<template>
<div class="bloc-modale" v-if="revele">
<div class="overlay" #click="toggleModale"></div>
<div class="modale card">
<div v-on:click="toggleModale" class="btn-modale btn btn-danger">X</div>
<img :src=""" alt="image du commentaire" id="modal">
</div>
</div>
</template>
<script>
export default {
name: "Modale",
props: ["revele", "toggleModale", "imageUrl"],
};
</script>
I've been working on it for 1 week but I can't, so thank you very much for your help...
in your v-for loop you're binding the same revele and toggleModale to every modal. When there is only one revele then any time it's true, all modals will be displayed. It's therefore likely you're actually opening all modals and simply seeing the last one in the stack. You should modify coms so that each item has it's own revele, e.g.:
coms = [
{
imageUrl: 'asdf',
revele: false
},
{
imageUrl: 'zxcv',
revele: false
},
{
imageUrl: 'ghjk',
revele: false
}
];
then inside your v-for:
<modale
:image-url="com.imageUrl"
:revele="com.revele"
#toggle-modale="com.revele = false"
></modale>
<img class="photo" :src=""" alt="image du commentaire" #click="com.revele = true">
passing the same function as a prop to each modal to control the value of revele is also a bad idea. Anytime a prop value needs to be modified in a child component, the child should emit an event telling the parent to modify the value. Notice in my code snippet above I replaced the prop with an event handler that turns the revele value specific to that modal to false. Inside each modal you should fire that event:
modale.vue
<div class="btn-modale btn btn-danger" #click="$emit('toggle-modale')">
X
</div>
This way you don't need any function at all to control the display of the modals.

How to retrieve the elements from Shadow DOM and pass property?

With the help of Lit library we have implemented the component that should render the list with items, where each item is rendered with a separate component:
<div>
<slot name="label"> Here goes the title </slot>
<slot name="list"></slot>
</div>
We pass data to the component like following:
<webc-list ?divided=${true}>
<span slot="label">Title</span>
<ul slot="list">
${items.map(
item =>
html`<webc-list-item
>${item}</webc-list-item
>`,
)}
</ul>
</webc-list>
My question is how can I pass the divided property to the <webc-list-item>.
I tried to access the elements
firstUpdated() {
const dividedProperty = this.divided;
this.renderRoot.querySelector('slot[name=list]')?.assignedElements({ flatten: true })
?.forEach(el => {
if (el && el.tagName && el.tagName.toLowerCase().includes('webc-list-item')) {
el.setAttribute('divided', `${dividedProperty}`);
}
});
But it doesn't work like this, any help would be appreciated!

How to use Next.js <Link> prefetch for a <button>? (And avoiding a double selection while navigating with Tab key)

Accessibility best practices suggest using <button> for button elements.
Prefetching for Next.js can be done via <Link>.
However, when you combine the two and use the Tab key to navigate, it will essentially select that button twice. E.g.
<Link href="#">
<a>
This selects once
</a>
</Link>
<Link href="#">
<a>
<button>
This selects twice
</button>
</a>
</Link>
You could do something like this:
<button
onClick={() => { window.location.href "#" }
>
This only selects once
</button>
But that doesn't prefetch.
You can use router.prefetch to fetch the route before going to the page. Check this for more details
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}
this is for nuxt
you don't need to do that way, you can just add props and value into nuxtlink
<NuxtLink
id="home-link"
:to="localePath('/')"
exact
active-class="nav-active"
tag="button"
class="btn btn-primary"
>
Home/Any Name
</NuxtLink>
for next top answer is right
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}

Gutenberg setAttributes does not update my edit area

How can i make my HTML Elements in Gutenberg binded to an Array/Object?
Hi,
i am programming an Gutenberg Block now and just wanted to bind an Object to my Block but it does not update.
Currently i have an list of 's and wanted to be added automatically if i push the "Click me!" Button.
What it does is... If i push on that button, it pushes the new Element into the Array but the Elements are not added. If i click away (if the block loses focus), the elements are added.
What did i do wrong?
edit: props => {
const { setAttributes, attributes } = props;
let slides = props.attributes.slides;
const addSlide = function(event){
slides.push({ title : 'new' });
setAttributes({ slides: slides });
}
return [
<InspectorControls key="inspector">
<PanelBody
title={'Slides'}
initialOpen={true}
>
{slides.map((slide, i) =>
<li key={i}>
{slide.title}
</li>
)}
<Button isPrimary onClick={addSlide}>
Click me!
</Button>
</PanelBody>
</InspectorControls>,
<div className={ props.className } key='richtext'>
{slides.map((slide, i) =>
<li key={i}>
{slide.title}
</li>
)}
<Button isPrimary onClick={addSlide}>
Click me!
</Button>
</div>
];
}
I'm expecting the list elements to add dynamically while foxused.

Resources