简体   繁体   中英

How to filter products by productType on Shopify?

The desired behaviour is for users to be able to filter products by their productType using buttons in a menu.

At the moment I'm querying the Shopify storefront API and fetching back products in lib/Shopify.js

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 25) {
        edges {
          node {
            id
            title
            productType
            handle
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query)
  const allProducts = response.data.collectionByHandle.products.edges ? response.data.collectionByHandle.products.edges : []
  return allProducts
}

export function filter(type) {
  let filtredProducts = getProductsInCollection().filter(product => product.node.productType === type);
  return filtredProducts;
}

lib/Shopify.js also contains a function to fetch all the productTypes in the store.

export async function getProductTypes() {
  const query = 
  `{
    shop {
      products(first:250, query:"-product_type:''") {
        edges {
            node {
              productType
          }
        }
      }
    }
  }`

  const response = await ShopifyData(query)
  const rawProductTypes = response.data.shop.products ? response.data.shop.products.edges : []
  const productTypes = Array.from(new Set(rawProductTypes));
  return productTypes
}

Then shop.js loops through all of the productTypes and displays them in a menu. It also loops through all of the products.

import { getProductsInCollection, getProductTypes, filter } from "../lib/shopify"
import React, { useState, useEffect } from "react";
import Link from 'next/link'

export default function Shop({ products, pages, projects, productTypes }) {
  const [filtredProducts, setFiltredProducts] = useState(null);

  useEffect(() => {
    setFiltredProducts(getProductsInCollection());
  }, []);

  var categories = new Map();
  productTypes.forEach( function( item ) {
    categories.set(JSON.stringify(item), item);
  });

  function handleCategories(e) {
    let type = e.target.value;
    type !== "all"
      ? setFiltredProducts(filter(type))
      : setFiltredProducts(getProductsInCollection());
  }

  const deduped = Array.from(new Set(productTypes));

  return (
    <div>
      <div>
         {categories &&
        [...categories.values()].map((category, index) => (
          <>
            <button className="mr-8 mb-6 underline" key={index} value={category.node.productType} onClick={handleCategories}>
             {category.node.productType}
            </button>
          </>
        ))}
      {filtredProducts &&
          filtredProducts.map(p => (
            <ul>
              <li>{p.node.title}</li>
            </ul>
          ))}
      </div>
    </div>
  )
}

export async function getStaticProps() {
    const products = await getProductsInCollection()
    const productTypes = await getProductTypes()
  
    return {
      props: { 
        products,
        productTypes,
      },
    }
  }

When the user tries to click on the filter they get the following error.

TypeError: getProductsInCollection(...).filter is not a function

What's the correct way to get the filter to work so the menu filters the products below?

You are trying to call .filter() on a Promise, not an array. Try modifying your code like this:

export async function filter(type) {
  let products = await getProductsInCollection();
  let filteredProducts = products.filter(product => product.node.productType === type);
  return filteredProducts;
}

Keep in mind, when calling filter() you need to use await again since it is now also an async function.

getProductsInCollection returns promise, use async/await before the filter.

In shop.js also you have to use async/await before setting to state.

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 25) {
        edges {
          node {
            id
            title
            productType
            handle
          }
        }
      }
    }
  }`;

  const response = await ShopifyData(query);
  const allProducts = response.data.collectionByHandle.products.edges
    ? response.data.collectionByHandle.products.edges
    : [];
  return allProducts;
}

export async function filter(type) {
  let filtredProducts = await getProductsInCollection();
  return filtredProducts.filter((product) => product.node.productType === type);
}

// shop.js
async function handleCategories(e) {
  let type = e.target.value;
  let products = [];
  if (type !== "all") {
    products = await filter(type);
  } else {
    products = getProductsInCollection();
  }
  setFiltredProducts(products);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM