Avoid new axios request each time vue component is rendered - javascript

I'm very much new to Vue so please excuse my lack of knowledge here.
In one of my (child) components (Product_Collection.vue) I make an axios request to get some products from my Shopify store via their GraphQL API:
data: () => {
return {
products: null
}
},
methods: {
getProducts: function(){
// 1. axios code here...
// 2. ...then assign result to "this.products" data property
}
}
The products are displayed as thumbnails (let's say there's 10 t-shirts). I then click a product to view it in more detail with more product info and images etc (very much an Amazon-like experience).
The product is shown on it's own in a Product_Single.vue component. So far so good.
But here's the problem...
When I click back to the products page (Product_Collection.vue) (the page with the 10 t-shirts on) the axios request to the Shopify API gets called again and the component is re-rendered from scratch.
My question is how do I tell Vue to stop fetching the data from the Shopify API each time the component is rendered? Thank you

Sounds like you want cache-control, which Axios supports with an extension.
https://github.com/kuitos/axios-extensions
import axios from 'axios';
import { cacheAdapterEnhancer } from 'axios-extensions';
const http = axios.create({
baseURL: '/',
headers: { 'Cache-Control': 'no-cache' },
// cache will be enabled by default
adapter: cacheAdapterEnhancer(axios.defaults.adapter)
});
http.get('/users'); // make real http request
http.get('/users'); // use the response from the cache of previous request, without real http request made
http.get('/users', { cache: false }); // disable cache manually and the the real http request invoked
Or you could go a more complex route and cache the results yourself into an object, and check if that object exists, but then you'll have to deal with when you want to expire the data in that object.
If you use a cache-control, and cache-control headers and expiry, you can drive all that from the API layer and not have to deal with manually managed stale data in the application.

If you are not using Vue Router, and hiding the list page, you can try a simple option.
Instead of v-if, use v-show. The component will be hidden and displayed again. It won't be re-created.
Also, where do you call the API? From created or mounted hook?

If You are using GraphQL then there is the Apollo state management way which integrates nicely with graphQL. Check this out: https://dev.to/n_tepluhina/apollo-state-management-in-vue-application-8k0
So instead of rewriting the app with axios and adding vuex in the mixture, maybe Apollo client would be more convenient

Related

fetch data by useEffect in a server side rendering page

I have a project with react js and next js. I am developing a dynamic page, with getStaticPaths and getStaticProps. So I am fetching most of the data in getStaticProps to make the page be rendered on server side.
But there are some data which I can't fetch on server side, because it needs token which is stored in local storage.
The question is, if I use useEffect hook to fetch those data on client side, does this all process make any advantage for SEO?
Or I have to change structures, and store token in cookies to fetch all data on server side?
Update:
I want to check if user is logged in, and based on the result, show the page in different styles. But no user-related data is going to be rendered.
Right now, my code looks like this:
export default function BookDetail(props) {
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
React.useEffect(() => {
// It captures token from cookies
const token = getCookie("token");
// Then I need to confirm that token is valid from backend
if (token) {
setIsLoggedIn(true);
}
}, []);
return (
<div>
{ !isLoggedIn ? (
{props.res.data.title}
<br/>
{props.res.data.description}
) : (
{props.res.data.title}
<br/>
<button type="button" onclick={()=>{window.location.href='http://example.com';}}
)}
</div>
);
}
If you need a token to fetch said data, that data is probably related to the user? Hence, doesn't and shouldnt be considered with SEO.
If your data is not specifically for the user. Consider making it accessable without token.
Edit based on the comments here:
Fetching data inside useEffect will absolutely affect SEO. You want to display part of a book (text) for users that are not logged in. You check if users are logged in by a request from the useEffect, this is fine and standard.
If you want to Google to be able to read your book-text with crawlers you can not fetch it in useEffect, I suggest the following:
in your getStaticProps: Fetch the data (book text) and pass it to your page. Display this information by default.
Then in your useEffect you check if the user is logged in. If they are --> remove the text and render a button instead.
This way, Google will read it as you intend, while logged in users will only see a button.
You can check no problem on the server side whether a user is logged in only when you use getServerSideProps - getStaticProps are executed at a built time so there is no communication with whatever user inputs into the UI simply because thats a different time frame: building the app on the server, only when the app is built user can interact with it.
But getServerSideProps are not executed at a built time, yet there are still executed on the server side and since useEffect is a frontend API it won't work there. So there are two ways:
If you use NextAuth - you can use getServerSideProps and on the context object you have 'req' property and the property passed to the getSession function (you need to import that function) will tell you whether user has a session or not. Here is an example code snipet:
import { getSession } from "next-auth/react";
// some code here like your frontend component
export const getServerSideProps = async (context) => {
const { req, res } = context;
const session = await getSession({ req: req });
if (!session) {
return {
redirect: { destination: "/", permanent: false },
};
}
const email = session.user.email;
return {
props: { email: email, session },
};
};
Here is more on the subject from the official next docs:
https://nextjs.org/docs/authentication
If you don't use NextAuth I am sure you can attach your token to the context object like in the example above and read it in getServerSideProps except not use getSession as that is NextAuth API. haven't done it though.

Next Authentication with node js api

I'm new to the Next js and developing the Next js website. I am stuck in multiple authentications with different routes and roles. How can I handle it in the next js?
Frontend: Next js
Backend: Node js with JWT (JSON web token).
Please guide me on what I should use to authenticate.
Thanks in advance.
I am assuming you have done a couple things with my answer below:
you are setting a http only authenticated cookie / signing it, expiring it etc
On api requests, you are validating this cookie
You can create a middleware.ts / .js file on the root of your project, something like the following (note I was using typescript, you can just remove the types if using javascript):
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const protectedPages = ["/something", "/foo", "/profile"];
export function middleware(request: NextRequest) {
if (protectedPages.find((page) => page === request.nextUrl.pathname)) {
const token = request.cookies.get("YOUR_TOKEN_NAME");
if (!token) {
// send the user back to the sign in / home page or wherever
const url = request.nextUrl.clone();
url.pathname = "/home";
return NextResponse.redirect(url);
}
}
}
You do not need to import this anywhere, just do this, get the cookie and you are done. No Cookie with the name you gave it, show them the door.
Take a read of the docs from if you want to know more, they explain things better than me :) https://nextjs.org/docs/advanced-features/middleware
Can also combine this with the above suggestion with getServerSideProps to pass the data as a prop to the component.

How to access httpOnly cookies from Nuxt 3 server

I am implementing a login feature to a website project. The backend is Express and the frontend is Nuxt 3. Upon successfully authenticating a user login, the Express backend returns necessary data to the webserver, which then creates an httpOnly cookie and sets any necessary data in a Pinia store. On page refresh, I would like the Nuxt 3 server to look at the cookie and setup the Pinia store (since it is lost on page refresh).
Can someone provide some guidance? I have looked at the useNuxtApp() composable, and I can see the cookie in nuxtApp.ssrContext.req.headers.cookie, but that only provides a K/V pairing of all set cookies, which I would need to parse. I know of the useCookie composable, but that only works during Lifecycle hooks, which seems to only resolve undefined.
Thanks.
Not sure if this is the right way,
but it's a solution I used to get through a similar case - dotnet api + nuxt3 client.
First, we need to proxy API (express in your case),
this will make it, so our cookie is on the same domain and browser will start sending it to /api/ endpoints.
Install #nuxtjs-alt/proxy - npm i #nuxtjs-alt/proxy.
Add configuration to nuxt.config.ts (my api running on localhost:3000):
nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'#nuxtjs-alt/proxy'
],
proxy: {
enableProxy: true,
fetch: true,
proxies: {
'/proxy': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/proxy/, '')
}
}
}
});
Then we can the request that will set a cookie anywhere on client using proxy instead of a direct call.
Anywhere on client, do a request using newly setup proxy instead of calling API directly.
Adjust parameters based on your setup.
await $fetch('/proxy/user/sign-in', {
method: 'POST',
body: {
email: 'example#mail.com',
password: 'password'
}
});
Ultimately, should end up with a cookie set on our client domain.
And lastly, when we handle request client side - we read the cookie and set up on forwarding request.
Replace COOKIE_NAME and API URL accordingly.
server/api/user/me.get.ts:
export default defineEventHandler(async (event) => {
return await $fetch('http://localhost:3000/user/me', {
headers: {
Cookie: `COOKIE_NAME=${
getCookie(event, 'COOKIE_NAME')
}`
}
});
});
API call will use the same cookie we got when we did a first request using cookie and the server should be able to read it.

Pass data to next route with vue

In my vue frontend I have the following method:
methods:{
async moveToOrder() {
const res = await this.$axios.get('/product/cart-to-order', {
headers: {
Authorization: 'Bearer ' + this.userData.userToken
}
});
if (res.status === 200) {
this.$router.push({name: 'Orders'});
}
}
}
The above method hits the following method that moves the data from cart collection to orders collection in the node backend and returns the moved data from orders collection:
exports.cartToOrder = async (req, res, next) => {
///method code goes here
res.status(200).json({products: products});
}
I want to display the data that I get as response in my orders (view or route). Can I pass data returned from backend to next route in Vue ?
Or do I need to make seperate methods on frontend and backend to fetch the data from orders collection ??
You can use query or url parameters between routes with the vue router. However, the data is now exposed in the url and you will now inherit all limitations from url requirements such as length and type (url encoded string).
A couple solutions are more applicable for your issue :
As you mentioned you could trigger a subsequent request if the first call is successful.
Emit the data to the destination view/route (note that the data can only flow up or down the component tree)
(Preferred) Use a state management tool like vuex to centralize your data. You will only need to update (mutate) your data (state) once and it will be available anywhere within your application. The time investment for this solution is not negligeable, however on a longer term it can simplify your application significantly.

How do I fetch data from server using MySQL/PHP using Vuejs frontend framework

I am quite new to web programming. Currently, I am looking to import backend data from PHP/MySQL into the vuejs application. One of them that I don't understand is how the Axios really works and how can I import data through the PHP(MySQL backend database). The backend database is created through XML.
First and foremost, I installed the vue-Axios through this link https://www.npmjs.com/package/vue-axios. Next, I continued to read on the documentation and there are various types of codes( which I am unsure of where to apply). What I am looking for is how can I import a specific component/item (which contains data) with pictures. I appreciate the help in advance.
I will just post my answer here as a response to the comment of the OP and to provide better formatting.
import axios from 'axios'
export default {
name: 'home',
async mounted () {
let response = await axios('http://128.106.100.230/bistro/get_step1_1.php')
// do something with the response here...
},
}
response is an object. You can obtain your result using
response.data
or using es6's object destructuring:
let { data } = await axios('http://128.106.100.230/bistro/get_step1_1.php')

Categories

Resources