How to use nextjs middleware function properly with getServerSideProps function? - next.js

I am trying to use nextjs middleware function. Here I create middleware file and add this code
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
const { nextUrl: url, geo } = req
const country = geo?.country || 'US'
url.searchParams.set('country', country)
return NextResponse.rewrite(url)
}
export const config = {
matcher: '/'
}
In Index page-
export default function Home(props: any) {
console.log(props)
return (
<h1 className={styles.title}>
Welcome to {props.country}
</h1>
)
}
export const getServerSideProps = ({ query }: any) => ({
props: query,
})
Here I am showing country name into h1 tag from props.country. It works perfectly.
But Here we know in geo object, middleware gives us-
city,
region,
latitude,
longitude,
country
In middleware function I want to sent full geo object and receive from page components to showing all those geo information. How can I do that.
I am trying to sent by this
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
const { nextUrl: url, geo } = req
//Here I am try to sent full geo object, not only country as string
//Please tell me any way to sent object from here to page component.
url.searchParams.set('country', geo)
return NextResponse.rewrite(url)
}
export const config = {
matcher: '/'
}
From the page component, I want to receive all field such as city, region, latitude, longitude and country. Please help me and I hope I can clear my question.

Passing an object as the value to url.searchParams.set won't work because this value will be serialized in the process.
Instead, you can use JSON.stringify to turn the object into a string. Like so:
url.searchParams.set("geo", JSON.stringify(geo));
Then in your component, you use JSON.parse to turn it into an object again:
const geo = JSON.parse(props.geo);

Related

How to use `useRoute`/`useRouter` in a Pinia Store using Setup Store syntax in Vue3?

I've been trying to get my Pinia store up and running in Vue 3 and it all has been pretty effortless until I wanted to access some parameters in the url.
I have a store (simplified) like so:
import { defineStore } from 'pinia';
import { useRoute } from 'vue-router';
import { useLocalStorage } from '#vueuse/core';
export const useUserStore = defineStore('user', () => {
const route = useRoute();
const uuid = ref(
useLocalStorage('uuid', route.params.id)
)
return { uuid };
})
Unfortunately, the route remains undefined as if useRoute() is not triggered properly. I've seen that you can add plugins to add the router instance to the pinia store on initialisation, but there's no way I can find to access that this instance in a Setup Store.
Any help would be greatly appreciated
route is not defined when the pinia is initiated.
You need to wait a bit.
One way to do this is to call the function when the component is loaded.
export const useUserStore = defineStore('user', () => {
const route = useRoute();
const id = ref('');
const setId = () => {
id.value = route.params.id as string; // don't need as string if you don't use TypeScript
};
return { id, setId };
});
<script setup lang="ts">
import { useUserStore } from '../stores/user';
const user = useUserStore();
user.setId(); // call the function from pinia, route.params works just fine
</script>
Link Demo

How to get req data from nextjs middleware function to page component? [duplicate]

This question already has an answer here:
How to use nextjs middleware function properly with getServerSideProps function?
(1 answer)
Closed 2 months ago.
I successfully write a middleware function in nextjs
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server'
export function middleware(req: NextRequest) {
const { ip, geo } = req
}
export const config = {
matcher: '/'
}
Here in this middleware function, I am getting geo object and ip string. In the geo object it has country, city, latitude, longitude, and region field. Now I have to get this data into my home page component.
import type { NextPage, GetServerSideProps } from "next"
const Home: NextPage = () => {
return (
<div>
dfd
</div>
);
};
export default Home;
export const getServerSideProps: GetServerSideProps = async (context) => {
console.log(context);
return { props: {} }
}
How can I get those middleware data like ip, geo in my page component.
#Md Ali
if you deploy your application in vercel you will get ip and geo.

Next.js Middleware matcher, only use when path contains string (%)

I have a problem where some website redirects to my website with all entities encoded. I can't change it on their end so I wanted to fix it with a middleware.
Anyone has an idea how i can use the Next.js middleware to only invoke when the path contains a encoded string?
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
console.log('invoked middleware', request.nextUrl.pathname)
const decoded = decodeURIComponent(request.nextUrl.pathname)
if (decoded !== request.nextUrl.pathname) {
return NextResponse.redirect(new URL(decoded, request.url).href)
}
}
export const config = {
matcher: '//%/', // this doesn't work
}

How to access query params in Next.js SSG, ISR [duplicate]

I want to get query string from URL on Next.js static site generation.
I found a solution on SSR but I need one for SSG.
Thanks
import { useRouter } from "next/router";
import { useEffect } from "react";
const router = useRouter();
useEffect(() => {
if(!router.isReady) return;
const query = router.query;
}, [router.isReady, router.query]);
It works.
I actually found a way of doing this
const router = useRouter()
useEffect(() => {
const params = router.query
console.log(params)
}, [router.query])
As other answers mentioned, since SSG doesn't happen at request time, you wouldn't have access to the query string or cookies in the context, but there's a solution I wrote a short article about it here https://dev.to/teleaziz/using-query-params-and-cookies-in-nextjs-static-pages-kbb
TLDR;
Use a middleware that encodes the query string as part of the path,
// middleware.js file
import { NextResponse } from 'next/server'
import { encodeOptions } from '../utils';
export default function middleware(request) {
if (request.nextUrl.pathname === '/my-page') {
const searchParams = request.nextUrl.searchParams
const path = encodeOptions({
// you can pass values from cookies, headers, geo location, and query string
returnVisitor: Boolean(request.cookies.get('visitor')),
country: request.geo?.country,
page: searchParams.get('page'),
})
return NextResponse.rewrite(new URL(`/my-page/${path}`, request.nextUrl))
}
return NextResponse.next()
}
Then make your static page a folder that accepts a [path]
// /pages/my-page/[path].jsx file
import { decodeOptions } from '../../utils'
export async function getStaticProps({
params,
}) {
const options = decodeOptions(params.path)
return {
props: {
options,
}
}
}
export function getStaticPaths() {
return {
paths: [],
fallback: true
}
}
export default function MyPath({ options }) {
return <MyPage
isReturnVisitor={options.returnVisitor}
country={options.country} />
}
And your encoding/decoding functions can be a simple JSON.strinfigy
// utils.js
// https://github.com/epoberezkin/fast-json-stable-stringify
import stringify from 'fast-json-stable-stringify'
export function encodeOptions(options) {
const json = stringify(options)
return encodeURI(json);
}
export function decodeOptions(path) {
return JSON.parse(decodeURI(path));
}
You don't have access to query params in getStaticProps since that's only run at build-time on the server.
However, you can use router.query in your page component to retrieve query params passed in the URL on the client-side.
// pages/shop.js
import { useRouter } from 'next/router'
const ShopPage = () => {
const router = useRouter()
console.log(router.query) // returns query params object
return (
<div>Shop Page</div>
)
}
export default ShopPage
If a page does not have data fetching methods, router.query will be an empty object on the page's first load, when the page gets pre-generated on the server.
From the next/router documentation:
query: Object - The query string parsed to an object. It will be
an empty object during prerendering if the page doesn't have data
fetching
requirements.
Defaults to {}
As #zg10 mentioned in his answer, you can solve this by using the router.isReady property in a useEffect's dependencies array.
From the next/router object documentation:
isReady: boolean - Whether the router fields are updated
client-side and ready for use. Should only be used inside of
useEffect methods and not for conditionally rendering on the server.
you don't have access to the query string (?a=b) for SSG (which is static content - always the same - executed only on build time).
But if you have to use query string variables then you can:
still statically pre-render content on build time (SSG) or on the fly (ISR) and handle this route by rewrite (next.config.js or middleware)
use SSR
use CSR (can also use SWR)

Using the context API in Next.js

I'm building a simple Next.js website that consumes the spacex graphql API, using apollo as a client. I'm trying to make an api call, save the returned data to state and then set that state as context.
Before I save the data to state however, I wanted to check that my context provider was actually providing context to the app, so I simply passed the string 'test' as context.
However, up[on trying to extract this context in antoher component, I got the following error:
Error: The default export is not a React Component in page: "/"
My project is set up as follows, and I'm thinking I may have put the context file in the wrong place:
pages
-api
-items
-_app.js
-index.js
public
styles
next.config.js
spacexContext.js
Here's the rest of my app:
spaceContext.js
import { useState,useEffect,createContext } from 'react'
import { ApolloClient, InMemoryCache, gql } from "#apollo/client"
export const LaunchContext = createContext()
export const getStaticProps = async () => {
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache()
})
const { data } = await client.query({
query: gql`
query GetLaunches {
launchesPast(limit: 10) {
id
mission_name
launch_date_local
launch_site {
site_name_long
}
links {
article_link
video_link
mission_patch
}
rocket {
rocket_name
}
}
}
`
});
return {
props: {
launches: data.launchesPast
}
}
}
const LaunchContextProvider = (props) => {
return(
<LaunchContext.Provider value = 'test'>
{props.children}
</LaunchContext.Provider>
)
}
export default LaunchContextProvider
_app.js
import LaunchContextProvider from '../spacexContext'
import '../styles/globals.css'
function MyApp({ Component, pageProps }) {
return (
<LaunchContextProvider>
<Component {...pageProps} />
</LaunchContextProvider>
)
}
export default MyApp
Any suggestions on why this error is appearing and how to fix it?

Resources