Sending dynamic object information to a component through nuxt-link

I've developed a project in Nuxt 3 that features a homepage displaying various products. Users can click on the product title to access the details page, achieved through the use of <NuxtLink>

<NuxtLink :to="{ name: 'slug', params: { slug: product.slug }}">
    <p>{{ product.title }}</p>
</NuxtLink>

Upon clicking the link, the [slug].vue component fetches the product data from the API based on its slug:

const { data } = await useFetch(runtimeConfig.public.api.product.view + `/${slug}`);

This behavior proves advantageous when users directly visit the product details page from external sources like Facebook. However, if the user navigates from the homepage using <NuxtLink>, I would prefer passing the product object directly to the [slug].vue component to avoid redundant API calls and enhance user experience.

To achieve this, I have written code within the [slug].vue component that checks for empty props and determines whether fetching from the API is necessary:

<script setup lang="ts">
  const { slug } = useRoute().params;
  const runtimeConfig = useRuntimeConfig()
  const route = useRoute()

  // Define component props
  const props = defineProps({
    product: null
  });

  // Computed property to determine necessity of data fetch
  const fetchData = computed(() => {
    return !props.product; // Fetch data only if props are empty
  });

  // Data ref to store fetched data
  const product = ref(null);

  // Fetch data from API if needed
  if (fetchData.value) {
    const { data } = await useFetch(runtimeConfig.public.api.product.view + `/${slug}`);
    product.value = data.value;
  }
</script>

However, I am facing challenges in passing the product object from <NuxtLink> to the props of my [slug].vue component. Any suggestions on how to accomplish this without overcomplicating the URL with excessive data or resorting to additional storage solutions?

If you have alternative ideas on efficiently passing data to the [slug].vue component from the homepage, feel free to share them!

Regards

Answer №1

In the past, it was feasible to accomplish this using params. However, due to a recent update in the vue router (referenced here), achieving this without incorporating it as a URL query or slug is now deemed an anti-pattern.

As indicated in the aforementioned link, there are alternative methods to achieve the same result. Personally, I would suggest utilizing the localStorage or vue store approach. Nevertheless, if those options are not suitable for you, employing history state as recommended in the same source can be an option. A straightforward implementation involves adding state to the :to props of NuxtLink:

// homepage /index
<template>
  <div>
    <NuxtLink :to="{ name: 'slug', state: { product: toRaw(product) }}">
      <p>{{ product.title }}</p>
    </NuxtLink>
  </div>
</template>

<script setup>
const product = ref({
  title: 'product title',
  slug: 'product123'
})
</script>

Subsequently:

// product detail page /slug
<template>
  <section>
    <h1>{{ product?.title }}</h1>
  </section>
</template>

<script setup>
const product = ref(null)

onMounted(() => {
  product.value = history.state.product // obtain product from previous route

  if (!product.value) {
    // retrieve product from API if it doesn't exist
  }
})
</script>

A non-reactive object should be passed to state, thus leveraging

toRaw</code, similar to the code snippet above, will convert the reactive state to a standard object. This enables access to the data on the product detail page through</p>
<pre><code>history.state.product

It's worth noting that this method retains the state even when the page is reloaded. To clear the state upon reloading, additional lines of code can be added at the conclusion of the onMounted function on the product detail page:

// product detail page /slug
onMounted(() => {
  product.value = history.state.product // obtain product from previous route

  if (!product.value) {
    // retrieve product from API if it doesn't exist
  }

  const { product: _product, ...currentState } = history.state // retain keys excluding product key
  window.history.replaceState({ ...currentState }, '') // eliminate state
})

I'd like to reiterate that opting for an alternative approach as recommended by the vue router change is advisable over this solution.

Answer №2

<NuxtLink> acts as a simple router link without the ability to transfer data to the next page directly.
However, you can store this data in a store or localStorage after clicking on <NuxtLink>, and retrieve it for processing on the subsequent view.

Answer №3

To improve the efficiency of your project, it is recommended to utilize a store implementation. Begin by creating a file named 'store.js' within the 'store' folder located in the root directory of your project.

export const store = reactive({
   items: [],
})

Subsequently, when retrieving products on the main index page, ensure that you save them in the store for easy access later.

import { store } from "@/store/store.js";

const { result } = await $fetch('endpoint')
store.items = result

When navigating to an individual product page, remember to first verify if the desired product exists in your store.

let product
if(store.items.length){
   product = store.items.find(//identify your specific product within the array//)
}else{
   const { data } = await useFetch(runtimeConfig.public.api.product.view + `/${slug}`);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A guide on customizing the appearance of individual items in a vue v-for loop based on specific conditions

I am currently developing a multiple choice quiz game and I want the selected answer by the user to change color, either red or green, depending on its correctness. To achieve this, I have created a variable called selected that correctly updates when the ...

Leveraging Lodash to retrieve values based on specific keys, even when certain keys are missing

How can I efficiently utilize Lodash while iterating through an array to extract and assign relevant values? I have an unfiltered array which contains ID and name[x].text elements. Some objects in the array may not have French text available, in which cas ...

Exploring the elements within an array of objects using JavaScript

I am currently working on a challenge to calculate the total number of likes. However, I am encountering an issue where I am receiving an error message stating that the posts do not exist. The user object contains a property called posts, which is an arr ...

What is the best way to display information using Datatables in VueJs?

The data retrieved from the API is appearing next to the datatable instead of within it. In my Vuex actions, I am fetching an array of records from an API and returning the state (array) through getters to components where datatables are being used. impo ...

Transform an Hstore to a Map instance

I'm struggling to convert a string that looks like this: "'keyTest'=>'valueTest', 'keyTest2'=>'valueTest2',..." into a Map object easily. I can achieve it using forEach, but I'm wondering i ...

Using the parameter of type 'never' is necessary as per the TypeScript error message, which states that the argument of type 'string' cannot be assigned to it. This error persists even when

https://i.sstatic.net/tkX07.png const index = selectedActivities.value.indexOf(activity_id); I encountered a TypeScript error saying 'Argument of type 'string' is not assignable to parameter of type 'never'. How can I fix this iss ...

Manipulate images in real-time and insert custom text using JavaScript/jQuery

Within my possession is an image depicted above. My objective revolves around dynamically altering the values present at the occurrences of L, A, and B; to achieve this, I must eliminate or conceal L, A, and B while substituting them with numerical equiv ...

Elements are failing to update properly due to unforeseen issues

Having recently delved into JavaScript, I decided to try my hand at updating elements in an array with this piece of code: var N = 2; var Range = 64; var array = [[0,100], [(Range),100]]; Here are the key Variables: $('#button2').click(functio ...

Highlighting table column when input is selected

I am working with a table where each <td> contains an <input>. My goal is to apply the class .highlighted to all the column <td>s when an <input> is being focused on. Additionally, I want to remove this class from all other columns ...

Why Form Validation in JavaScript is Failing to Display Alerts or Update Input Background Colors

Having created this script to validate my forms, I encountered an issue where leaving a textfield blank does not trigger the expected behavior. There is no red background or alert message displayed as intended. function validateForm() { /* Loop through al ...

What distinctions are there between saving a constant value in a variable and in state?

There are a couple of different approaches to accomplishing the same thing within a React functional component. When you have a config value that is only needed inside the component (just a constant value, never passed in or modified), you can either use a ...

How can I efficiently create an editForm in Angular?

Within my database, there are numerous users, each with their own collection of recipes. Each recipe contains various properties and a list of ingredients. Take a look at the screenshot below: Recipe with all properties When a user goes to edit a recipe ...

How can I add a channel to a category using await(discord.js)?

Having trouble organizing a new channel within a category. The .setParent(categoryID) method seems to only work with existing channels, causing an issue when I attempt to execute my code. Take a look at the code snippet below: client.on("message" ...

Guide to changing the border color in a Material-UI TextField component styled with an outline design

To complete the task, utilize the Material UI outlined input field (TextField component from "@material-ui/core": "^4.12.2",) and apply a custom blue color style to it. Here is the outcome of my work: https://i.sstatic.net/lw1vC.png C ...

"Encountering difficulties while setting up an Angular project

I am currently working on setting up an Angular project from scratch. Here are the steps I have taken so far: First, I installed Node.js Then, I proceeded to install Angular CLI using the command: npm install -g @angular/cli@latest The versions of the ...

JavaScript: Filtering list by elements that contain a certain value

I have the following collection of objects: [ { employeeId:1 employeeName:"ABC" }, { employeeId:2 employeeName:"ABD" }, { employeeId:3 employeeName:"FEW" }, { employeeId:4 employeeName:"JKABL" },] I am looki ...

The term "export" was not located within the Vue framework

After transitioning to vue3 using vue-next, I encountered some warnings when running yarn serve. import Vue from 'vue'; triggers the warning "export" 'Vue' was not found in 'vue'. However, import { createApp, h } f ...

recoil struggles to manage the error thrown by an asynchronous selector

Recoil offers the ability for users to throw errors in async selectors. For more information, please refer to the documentation. Both "<ErrorBoundary>" and "useRecoilValueLoadable()" can handle errors from async selectors, but I encountered issues w ...

Ensure that cookies intended for cross-site contexts are marked as Secure to enable their setting across different sites

When using nookies in Next.js on browsers with Chromium, an error is occurring as mentioned in the title and the cookie is not being saved properly. The website is securely hosted with SSL/HTTPS. Have already attempted: - sameSite = None - secure = tru ...

Do not attempt to log after tests have finished. Could it be that you overlooked waiting for an asynchronous task in your test?

Currently, I am utilizing jest in conjunction with the Vue framework to create unit tests. My test example is successfully passing, however, I am encountering an issue with logging the request. How can I resolve this error? Is there a mistake in my usage o ...