skip to Main Content

I’m using nextjs and graphql for a shopify POC.

I have a component that shows a list of products with links on them that point to the product page

<Link
   as={`${handle}/product/${url}`}
   href={`/product?id=${item.id};`}>
   <a>{item.title}</a>
</Link>

handle is the collection name so the url in the browser will look like
http://localhost:3000/new-releases/product/Plattan-2-Bluetooth but behind the scenes its really just using a page called products and i’m passing the product id.

Now in product.js (pasted below) i’m getting the query string value of the id and doing another query to get the product. All works fine but then if i hit refresh or copy and paste the url into a new window i get 404.

I know this is something to do with routing but i’m not sure what i need to do to fix this. Thanks

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Query } from 'react-apollo';
import gql from 'graphql-tag';


class product extends Component {
  static async getInitialProps({query}) {
    console.log("query", query)
    return query ? { id: query.id.replace(';', '') } : {}
  }

  render() {

    const PRODUCT_FRAGMENT = gql`
        fragment ProductPage on Product {
          title
          description
          descriptionHtml
          id
          images(first: 10, maxWidth: 600) {
            edges {
              node {
                id
                altText
                originalSrc
              }
            }
          }
        }
      `;

    const PRODUCT_FETCH_QUERY = gql`
      query PRODUCT_FETCH_QUERY {
        node(id: "${this.props.id}") {
          __typename
          ...ProductPage
        } 
      }
      ${PRODUCT_FRAGMENT}
    `;

    return (
      <div>
         <Query query={PRODUCT_FETCH_QUERY}>
              {({ data, error, loading }) => {
                console.log("data", data)
                if (loading) return <p>Loading...</p>
                if (error) return <p>Error: {error.message}</p>
                return null}
              }
            </Query>
      </div>
    );
  }
}

product.propTypes = {

};

export default product;

2

Answers


  1. This is because when you use the next/link component the href prop has the “real” URL to the page with the query parameter for the item ID set. This means that on the client (the browser), Next.js can load the right page (your product.js page) with the parameter for your data query.

    But when you load from the server, either by reloading the page or opening it in a new window, Next.js doesn’t know what page to load and in this case I think it will try to find the file ./pages/new-releases/product/Plattan-2-Bluetooth.js, which of course doesn’t exist.

    If you want to have these kinds of URLs you have to make sure the request gets routed to the right page file (./pages/product.js) on the server as well. You can do this by by creating a custom server. There are a bunch of examples in the Next.js repo including one using Express. This is also covered in the “Learn” section of there website in a tutorial called Server Side Support for Clean URLs

    If you decide to use Express, you will end up with something like:

    server.get('/:collection/product/:productUrl', (req, res) => {
      return app.render(req, res, '/product', { productUrl: req.params.productUrl})
    })
    

    This will render the product page, and you’ll have productUrl available on the query object in getInitialProps(). Of course now you will need to fetch your data with that instead of the product id.

    Login or Signup to reply.
  2. You can try these in a file called next.config.js in the root of your project

    module.exports = {
      trailingSlash: true
    }
    

    Check this link

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search