Nextjs getting single product from woocommerce - woocommerce

new in graphQL and nextjs, why do i keep getting this error
Error: Cannot find module 'react'
Require stack:
- /home/monster/app/nextpress/node_modules/#apollo/client/react/context/context.cjs
- /home/monster/app/nextpress/node_modules/#apollo/client/react/react.cjs
i already checked the package it exit in my node, if use on other page it work but once i put in this code, it have this error.
// product/[slug].tsx
import React from 'react'
import { ApolloClient, InMemoryCache, gql } from '#apollo/client'
export default function Product({ product }) {
console.log('product:', product)
return (
<main>
<div>
<h1>Product Page</h1>
</div>
</main>
)
}
export async function getStaticProps(context) {
const client = new ApolloClient({
uri: 'http://localhost:3080/graphql/',
cache: new InMemoryCache(),
})
const {
params: { slug },
} = context
const { data } = await client.query({
query: gql`
query Product($slug: ID!) {
product(id: $slug, idType: SLUG) {
id
name
}
}
`,
variables: { slug },
})
return {
props: {
product: data?.product || {},
},
revalidate: 1,
}
}
export async function getStaticPaths() {
const client = new ApolloClient({
uri: 'http://localhost:3080/graphql/',
cache: new InMemoryCache(),
})
const { data } = await client.query({
query: gql`
query Products {
products(first: 10) {
nodes {
id
slug
}
}
}
`,
})
const pathsData = []
data?.products?.nodes.map((product) => {
if (!isEmpty(product?.slug)) {
pathsData.push({ params: { slug: product?.slug } })
}
})
return {
paths: pathsData,
fallback: false,
}
}
what wrong with it ? if anyone can help me pinpoint my mistake, will be greatful and am i doing right to get single product data like this or there is a better way ? thanks :D

Related

Next.js reference error "client" is not defined

I am having an error when trying to fetch product data from sanity with getStaticPaths
here is my code:
import React, { useState } from "react";
function ProductPage({ product, products }) {
const { image, name, details, price } = product;
return (
<div className="pdPage">
<div className="container">{name}</div>
</div>
);
}
export default ProductPage;
export const getStaticPaths = async () => {
const query = `*[_type == "product"] {
slug {
current
}
}
`;
const products = await client.fetch(query);
const paths = products.map((product) => ({
params: {
slug: product.slug.current,
},
}));
return {
paths,
fallback: "blocking",
};
};
export const getStaticProps = async ({ params: { slug } }) => {
const query = `*[_type == "product" && slug.current == '${slug}'][0]`;
const productsQuery = '*[_type == "product"]';
const product = await client.fetch(query);
const products = await client.fetch(productsQuery);
console.log(product);
return {
props: { products, product },
};
};
And then I get reference error client is not defined from getstatic client.fetch
I even delete my code and replace from tutor github repository, but get the same error
After figure it out sometimes I found that I forgot to import client from

Next.js ApolloError Only absolute URLs are supported

I followed this video tutorial
https://youtu.be/JUEw1yHJ8Ao?t=715
at this time i have an error Only absolute URLs are supported
Server Error
Error: Only absolute URLs are supported
This error happened while generating the page. Any console logs will be displayed in the terminal window.
my code:
import { ApolloClient, InMemoryCache, createHttpLink, gql } from '#apollo/client'
import { setContext } from '#apollo/client/link/context'
export async function getServerSideProps() {
const httpLink = createHttpLink({
uri: 'https://api.github.com/graphql',
})
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
}
}
})
const apolloClient = new ApolloClient({
uri: authLink.concat(httpLink),
cache: new InMemoryCache()
});
const { data } = await apolloClient.query({
query: gql`
{
user(login: "mygithublogin") {
avatarUrl(size: 36)
gists(privacy: PUBLIC, last: 10) {
totalCount
nodes {
createdAt
url
stargazerCount
}
}
login
}
}
`
})
console.log(data);
return {
props: {
}
};
}
help please 🙋‍♂️

How do you do server side rendering with nextjs [id].js in headless wordpress? fetch single page using graphql from Wordpress. like service/[id].js

I have a nextjs project that is using apollo graphql to fetch data from the backend. I am trying to render my page using server side rendering. But I am currently using graphql apollo hooks to fetch my data from the backend, and the react hooks prevents me from calling my backend inside of the getServerSideProps.
Create and fetch single page using graphql from Wordpress with clean URLs like services/[id].js
N.B: Warning Show ( Error: Response not successful: Received status code 500)
import {
gql,
ApolloClient,
InMemoryCache
} from "#apollo/client";
export const client = new ApolloClient({
uri: 'https://.........../graphql',
cache: new InMemoryCache()
});
const serviceDetail = (serviceOutput) => {
return (
<div>
{serviceOutput.serviceTitle}
{serviceOutput.serviceContent}
</div>
)
}
export const getServerSideProps = async (context) => {
const result = await client.query({
query: gql`
query serData($id: id!) {
HomePage: pageBy(uri: "https://......./home/") {
aboutSection {
serviceSec(id: $id) {
id
serviceTitle
serviceContent
serviceImage {
sourceUrl
}
}
}
}
}
`,
variables: {
id: context.params.id
}
})
return {
props: {
serviceOutput: result.data.HomePage.aboutSection.serviceSec;
},
};
}
export default serviceDetail;
i am not an expert, but as far i have used. you cannot use Apollo together with next js fetching method(ssg,ssr,isr).
Apollo runs queries on client side, and can be used with useQuery and useLazyQuery. while next js fetching is completely different.
I will demonstrate 2 ways here.
-- Using Apollo --
const FETCH_ALL = gql`
query MyQuery($first: Int!, $after: String) {
posts(first: $first, after: $after) {
edges {
node {
title
}
}
}
}
`;
export default function LoadMoreList() {
const { data } = useQuery(FETCH_ALL, {
variables: { first: 5, after: null },
notifyOnNetworkStatusChange: true,
});
return (
<>
<div>
{postdata.map((node, index) => {
{
return (
<div key={index}>
<h1>{node?.node?.title}</h1>
</div>
);
}
})}
</div>
</>
)}
=== using fetch and getStaticProps ==
--File1 (this is a fetch function, to which you pass your queries and variables)
async function fetchAPI(query, { variables } = {}) {
const headers = { "Content-Type": "application/json" };
const res = await fetch(process.env.WP_API, {
method: "POST",
headers,
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
console.log(json.errors);
throw new Error("Failed to fetch API");
}
return json.data;
}
export default fetchAPI;
-- File2 (this is a file that contains your query)
import fetchAPI from "./fetching";
export async function homeheadposts() {
const data = await fetchAPI(
`
query homeheadposts {
posts(first: 7) {
edges {
node {
id
slug
title
featuredImage {
node {
sourceUrl
}
}
excerpt(format: RAW)
}
}
}
}
`
);
return data?.posts;
}
-- File3 (place this function , where you wanna call and use the data, )
export async function getStaticProps() {
const latestPosts = await homeheadposts();
return {
props: { latestPosts },
};
}
export default function CallingData({ latestPosts }) {
console.log(latestPosts);
return <h1>hello</h1>;
}

Composition API - Axios request in setup()

I am experimenting with Vue3's Composition API in a Laravel/VueJS/InertiaJS stack.
A practice that I have used a lot in Vue2 with this stack is to have 1 route that returns the Vue page component (eg. Invoices.vue) and then in the created() callback, I would trigger an axios call to an additional endpoint to fetch the actual data.
I am now trying to replicate a similar approach in Vue3 with composition API like so
export default {
components: {Loader, PageBase},
props: {
fetch_url: {
required: true,
type: String,
}
},
setup(props) {
const loading = ref(false)
const state = reactive({
invoices: getInvoices(),
selectedInvoices: [],
});
async function getInvoices() {
loading.value = true;
return await axios.get(props.fetch_url).then(response => {
return response.data.data;
}).finally(() => {
loading.value = false;
})
}
function handleSelectionChange(selection) {
state.selectedInvoices = selection;
}
return {
loading,
state,
handleSelectionChange,
}
}
}
This however keeps on giving me the propise, rather than the actual data that is returned.
Changing it like so does work:
export default {
components: {Loader, PageBase},
props: {
fetch_url: {
required: true,
type: String,
}
},
setup(props) {
const loading = ref(false)
const state = reactive({
invoices: [],
selectedInvoices: [],
});
axios.get(props.fetch_url).then(response => {
state.invoices = response.data.data;
}).finally(() => {
loading.value = false;
})
function handleSelectionChange(selection) {
state.selectedInvoices = selection;
}
return {
loading,
state,
handleSelectionChange,
}
}
}
I want to use function though, so I can re-use it for filtering etc.
Very curious to read how others are doing this.
I have been googling about it a bit, but cant seem to find relevant docu.
All feedback is highly welcomed.
I tried this now with async setup() and await getInvoices() and <Suspense> but it never displayed any content.
So this is how I'd do it, except I wouldn't and I'd use vuex and vuex-orm to store the invoices and fetch the state from the store.
<template>
<div>loading:{{ loading }}</div>
<div>state:{{ state }}</div>
</template>
<script>
import {defineComponent, ref, reactive} from "vue";
import axios from "axios";
export default defineComponent({
name: 'HelloWorld',
props: {
fetch_url: {
required: true,
type: String,
}
},
setup(props) {
const loading = ref(false)
const state = reactive({
invoices: []
})
async function getInvoices() {
loading.value = true;
await axios.get(props.fetch_url).then(response => {
state.invoices = response.data;
}).finally(() => {
loading.value = false;
})
}
return {
getInvoices,
loading,
state,
}
},
async created() {
await this.getInvoices()
}
})
</script>
<style scoped>
</style>
This is of course similar to what you're doing in option 2.

My website deployed on Vercel keeps giving me the "429: TOO_MANY_REQUESTS" errors. What could be going wrong, how can I debug this?

Occassionally (maybe about half the time) when I load a page on the website I'm working on, I'm getting an error that looks like this.
429: TOO_MANY_REQUESTS
Code: INTERNAL_FUNCTION_RATE_LIMIT
ID: lhr1::258d8-1638206479250-0a01c8648601
My website hasn't been launched yet, almost nobody visits it but me, so it can't be having too much traffic yet.
The page I'm loading has a getServerSideProps() function that does only one thing - uses prisma to fetch posts from my database, which are sent to my component to be rendered.
I can't imagine what could be causing too many requests.
My vercel usage stats look like this.
What am I doing wrong? What could be causing this? How can I debug this?
For reference, below is all my relevant code. Any chance you could take a look at it and let me know if you have any ideas on what could be happening?
index.tsx has getServerSideProps() function which calls a getPosts() function to fetch the posts.
import Layout from 'components/Layout/Layout'
import PostFeed from 'components/Posts/PostFeed'
import Subnav from 'components/Layout/Subnav'
import Pagination from 'components/Posts/Pagination'
import ProfileHeader from 'components/Users/ProfileHeader'
import TagHeader from 'components/Layout/TagHeader'
import HomeHeader from 'components/CTAs/HomeHeader'
import SubscribeBox from 'components/CTAs/SubscribeBox'
import AdBoxes from 'components/CTAs/AdBoxes'
export default function browse({ posts, postCount, username }) {
return (
<Layout subnav={<Subnav />}>
<PostFeed posts={posts} />
<Pagination postCount={postCount} />
<AdBoxes/>
<SubscribeBox />
<br />
</Layout>
)
}
import { getPosts } from 'prisma/api/posts/get-posts'
import config from 'config.json'
export async function getServerSideProps({ req, query }) {
const { username, sort, tag, search } = query
const { posts, postCount } = await getPosts({
published: true,
searchString: search,
username: username,
tagSlug: tag,
sort: sort,
skip: config.postsPerPage * (parseInt(query.page?.toString()) - 1 || 0),
take: config.postsPerPage,
})
return { props: { posts, postCount, username } }
}
get-posts.ts runs a prisma query and fetches the posts.
import prisma from 'prisma/prismaClient'
export async function getPosts({ username, published, tagSlug, searchString, sort, skip, take }) {
console.log(`Get posts. Sorting: ${sort}`)
// Filter posts by user (to show them on their profile)
let author
if (username) author = await prisma.user.findUnique({ where: { username } })
// Filter by tag
const tagFilter = tagSlug ? {
tags: { some: { slug: tagSlug } }
} : {}
// Search through posts
const search = searchString ? {
OR: [
{ title: { contains: searchString, mode: "insensitive", } },
{ body: { contains: searchString, mode: "insensitive", } },
{ tags: { some: { name: { contains: searchString, mode: "insensitive", } } } },
{ author: { username: { contains: searchString, mode: "insensitive", } } },
],
} : {}
let orderBy = [{ rank: 'desc' }]
if (sort === 'new') orderBy = [{ createdAt: 'desc' }]
if (sort === 'top') orderBy = [{ score: 'desc' }]
const allFilters = {
authorId: author?.id,
published: published,
...search,
...tagFilter,
}
const [posts, postCount] = await prisma.$transaction([
prisma.post.findMany({
where: allFilters,
orderBy: orderBy, //rank: 'desc' //score: 'desc'
take, skip,
include: {
tags: true,
author: {
select: {
username: true
}
},
upvoters: {
select: {
username: true
}
},
// Just for the comment counter
comments: {
select: {
id: true
}
}
}
}),
prisma.post.count({ where: allFilters })
])
return { posts, postCount }
}
the prismaClient which get-posts is using to connect to prisma
import { PrismaClient } from "#prisma/client";
// PrismaClient is attached to the `global` object in development to prevent
// exhausting your database connection limit.
//
// Learn more:
// https://pris.ly/d/help/next-js-best-practices
let prisma: PrismaClient
if (process.env.NODE_ENV === 'production') {
prisma = new PrismaClient()
} else {
if (!global.prisma) {
global.prisma = new PrismaClient()
}
prisma = global.prisma
}
export default prisma
Try going towards getInitialProps which will execute your function on the browser vs getServerSideProps which always goes to your function creating loops as customers refresh your page or traverse through the site.
As to why so many requests, i think as clients traverse your site, you are generating hits to your function in a loop.

Resources