I'm trying to get some data from my server depending on whose currently logged in. I'm using Next-Auth and normally I can just call:
const { data: session } = useSession();
At the top of the functional component, but you cannot do this in getServerSideProps().
I need to make a get request like this:
export async function getServerSideProps() {
const res = await fetch(
`http://localhost:5000/api/users/${session.id}/following`
);
const isFollowing = res.json();
return {
props: { props: isFollowing },
};
}
that has the current users session ID dynamically put in.
How do I access my session ID inside getServerSideProps?
Since useSession is react-hook - it can be used only inside Component. For server-side usage there another method from Next-Auth package - getSession.
https://next-auth.js.org/v3/getting-started/client#getsession
Server-Side Example
import { getSession } from "next-auth/client"
export default async (req, res) => {
const session = await getSession({ req })
/* ... */
res.end()
}
Note: When calling getSession() server side, you need to pass {req} or context object.
you should to re-assign the headers from the getServerSideProps request to inner fetch, because that fetch has no headers, cookies or tokens
export async function getServerSideProps(ctx) {
const headers=ctx.req.headers //where cookies, jwt or anything
const res = await fetch(
`http://localhost:5000/api/users/${session.id}/following`,
{headers}
);
const isFollowing = res.json();
return {
props: { props: isFollowing },
};
}
Related
I am using react-query in conjunction with Next JS getServerSideProps to fetch data before a page loads using the hydration method specified in the docs like this:
// Packages
import { dehydrate, QueryClient } from '#tanstack/react-query';
// Hooks
import { useGetGoogleAuthUrl, useGetMicrosoftAuthUrl } from '../hooks/auth';
import { getGoogleAuthUrl, getMicrosoftAuthUrl } from '../hooks/auth/api';
export async function getServerSideProps({ req, res }) {
const queryClient = new QueryClient();
const microsoftAuthQueryClient = new QueryClient(); // Not working
await queryClient.prefetchQuery(['getGoogleAuthUrl'], getGoogleAuthUrl);
await microsoftAuthQueryClient.prefetchQuery(['getMicrosoftAuthUrl'], getMicrosoftAuthUrl); // Not working
return {
props: {
dehydratedState: dehydrate(queryClient),
dehydratedMicrosoftAuthState: dehydrate(microsoftAuthQueryClient), // Not working
},
};
}
export default function Signin() {
const date = new Date();
const { data: googleAuthData } = useGetGoogleAuthUrl();
const { data: microsoftAuthData } = useGetMicrosoftAuthUrl();
console.log(googleAuthData); // logs actual data on mount and data is immediately available
console.log(microsoftAuthData); // logs undefined before eventually logging data after being successfully fetched with the useGetMicrosoftAuthUrl() query
return (
//Page content
);
}
How do I make it work as it is supposed to work. Is it not possible to make multiple requests in getServersideProps using react-query hydration method?
Thank you so much in advance
You would just use the same queryClient and prefetch both queries into it, then hydrate just the one:
export async function getServerSideProps({ req, res }) {
const queryClient = new QueryClient();
await queryClient.prefetchQuery(['getGoogleAuthUrl'], getGoogleAuthUrl);
await queryClient.prefetchQuery(['getMicrosoftAuthUrl'], getMicrosoftAuthUrl);
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
}
This however fetches them one after the other, so you might want to await them in Promise.all:
await Promise.all([
queryClient.prefetchQuery(['getGoogleAuthUrl'], getGoogleAuthUrl),
queryClient.prefetchQuery(['getMicrosoftAuthUrl'], getMicrosoftAuthUrl)
])
I have the following function:
export async function getServerSideProps({ req }: any) {
const user = (
await axios.get("http://localhost:4000/api/auth/status", {
withCredentials: true,
headers: { Cookie: `connect.sid=${req.cookies["connect.sid"]}` },
})
).data;
return { props: { user } };
}
Which fetches the users cookie, and then make a HTTP request using it, now I would have liked to do this in my _app.js file - however getServerSideProps() doesn't seem to be useable in there? Essentially, I was wondering how I would execute this function once and not have to include it in every single page file, and then be able to access its output (user) from each page.
Any suggestions would be greatly appreciated.
i had same problem for use getStaticProps. my problem solved with this way.
you can create a lib folder in project root. and create getServerSide.js file into lib.
export function makeServerSideProps(ns = {}) {
return async function getServerSideProps(ctx) {
return {
props: await getUserProps(ctx, ns),
};
};
}
and define function for receive user data getUserProps.
export async function getUserProps(ctx, ns = ['common']) {
const user = (
await axios.get("http://localhost:4000/api/auth/status", {
withCredentials: true,
headers: { Cookie: `connect.sid=${req.cookies["connect.sid"]}` },
})
).data;
return user;
}
and use makeServerSideProps into any pages:
import { makeServerSideProps} from 'lib/getServerSide';
import User from 'components/Authentication/User';
const UserPage = () => {
return (
<User/>
);
};
export default UserPage ;
const getServerSideProps = makeServerSideProps();
export { getServerSideProps };
I use NextJs and make several pages with SSR(server-side rendering)
I have to send the userId to the server
At first, I realized I had to use a cookie
npm i js-cookie
but I use Redux-Saga and I call API in Redux Action
For sending Cookie into Redux Action from the SSR page I use this code
export const getServerSideProps = wrapper.getServerSideProps(
async ({ store, query, req }) => {
let cookie = req.headers.cookie;
store.dispatch(loadProductDetailData(`${id}`,cookie));
})
for export deviceId from the cookie, I make this function
export const getCookie = (cookie: string, key: string) => {
let value = ''
cookie.split(';').forEach((e) => {
if (e.includes(key)) {
value = e.split('=')[1]
}
})
return value
}
I call this function
getCookie(cookie,'deviceId')
I'm calling a page withRouter(Page) and expect the variable for the page (the page is called [category].js) to be present on initial page load. Query itself is there, the key is there, but the value is 'undefined.' There seem to be a few calls to getInitialProps on the server side with 2/3 being undefined.
The react component has a constructor, etc. it's not a functional component.
This is my current getInitialProps:
Category.getInitialProps = async ({ req, query }) => {
let authUser = req && req.session && req.session.authUser
let categoryData = {}
let categoryItemData = {}
let category = query.category
if(category){
let res = await fetch(url1,
{
method: 'POST',
credentials: 'include',
})
categoryData = await res.json();
let categoryItemsRes = await fetch(url2,
{
method: 'POST',
credentials: 'include',
})
categoryItemData = await categoryItemsRes.json();
}
return { query, authUser, categoryData, categoryItemData }
}
This might be redundant at this point, but I ran into this as well and found the docs explain this here
During prerendering, the router's query object will be empty since we do not have query information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object.
You might try this instead:
export async function getServerSideProps(ctx) {
const { id } = ctx.query;
return {
props: {
id,
},
};
}
This way it gets the query params when rendering server side, so they're instantly available.
For others who use express custom server, to fix the undefined params, we have to set the dynamic route at server.js as follow:
# server.js
...
app.prepare().then(() => {
const server = express();
....
server.get('/product/:category', (req, res) => {
const { category } = req.params;
return app.render(req, res, `/product/${category}`, req.query)
})
...
}
And then, as Valentijn answers, we can get the category params.
# pages/product/[category].js
....
export async function getServerSideProps(ctx) {
const {category} = ctx.params;
return {
props: {
category
},
};
};
...
The key is dynamic path /product/${category}. Don't use /product/:category
This is how my simple function to synchronize the data looks like:
Function
import { getData } from './api/index'
export default async function synchronize (navigator) {
const data = await getData()
// ... then store data to local db...
}
I'm fetching some data from the server using an RESTful API:
getData
import { Alert, AsyncStorage } from 'react-native'
async function getData () {
try {
const lastSynched = await AsyncStorage.getItem('data.lastSynched')
const date = lastSynched ? Number(Date.parse(lastSynched)) / 1000 : 0
const token = await AsyncStorage.getItem('auth.token')
const uriBase = 'http://localhost:3000'
let response = await fetch(`${uriBase}/get-data/${date}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'x-access-token': token
}
})
let responseJson = await response.json()
return responseJson
} catch (error) {
Alert.alert('Error', 'Could not synchronize data')
}
}
export default getData
But now I'm using apollo graphQL and I do not understand how to get the data using a query as I'm using here a function (synchronize()) - not a component.
I think good start will be from this link. Here you have good examples how to use Apollo client to execute query and fetch data.
Maybe I don't understand properly what is issue but here is high level of Apollo usage.
First you will need to create Apollo client and supply at least URI to GraphQL endpoint.
import ApolloClient from "apollo-boost";
const client = new ApolloClient({
uri: "https://w5xlvm3vzz.lp.gql.zone/graphql"
});
Once you created client you should than execute your query with previously created client like in following:
import gql from "graphql-tag";
client
.query({
query: gql`
{
rates(currency: "USD") {
currency
}
}
`
})
.then(result => console.log(result));
Make sure that you installed apollo-boost react-apollo graphql-tag graphql packages. Also make sure that you wrap your query into GraphQL tag like this because it will compile your query.