【问题标题】:I have in issue with filter function in my react ecommerce app我的反应电子商务应用程序中的过滤器功能有问题
【发布时间】:2021-05-19 03:06:03
【问题描述】:

React 过滤器功能正在工作

当我点击“牛仔布”、“衬衫”等过滤选项时,它应该会过滤产品并仅显示这些商品。我使用handleTag 函数过滤产品数组,然后更新setfilterProducts,但它不起作用。

在我的主文件下面Home.jsx

function Home() {
    const [products, setProducts] = useState([]);
    const [filterProducts, setFileterProducts] = useState([]);
    const [sortValue, setSortValue] = useState('');
    const [tag, setTag] = useState('');
    // const [error, setError] = useState('');

    const loadAllProducts = () => {

    /*var myArray = ['a', 1, 'a', 2, '1'];

    let unique = [...new Set(myArray)];

    console.log(unique); // unique is ['a', 1, 2, '1']*/
    let ar = data.map(item => item.tag);
    let uniqueEle = [...new Set(ar)];
    // console.log(uniqueEle);
    setProducts(data);
    setFileterProducts(data);
}

useEffect(() => {
    loadAllProducts();
    handleSort();
    handleTag();
}, [filterProducts, sortValue, tag])

const handleSort = (value) => {
    setSortValue(value);
    listProducts();
}

function listProducts() {
    
    if(sortValue !== '') {
        // console.log("SORT: "+sortValue)
        products.sort((a, b) => sortValue === 'lowest' ? (parseInt(a.price) > parseInt(b.price) ? 1:-1) : (parseInt(a.price) < parseInt(b.price) ? 1:-1))
    } else {
        // console.log("INSIDE THE ELSE PART");
        products.sort((a, b) => (a.id > b.id ? 1 : -1))
    }
    return {setFileterProducts: products}
}

const handleTag = (value) => {
    // console.log(value);
    setTag(value);
    listTagProduct();
}

function listTagProduct() {
    if(tag !== '') {
        if(tag === 'Denim') {
            console.log(tag);
            let filterAr = tagFilter(tag);
            console.log("FilterArr "+filterAr);
            return {setFileterProducts: filterAr}
        } else if(tag === "T-shirt") {
            let filterAr = tagFilter(tag);
            return {setFileterProducts: filterAr}
        } else if(tag === "shirt") {
            let filterAr = tagFilter(tag);
            return {setFileterProducts: filterAr}
        } else if(tag === "jacket") {
            let filterAr = tagFilter(tag);
            return {setFileterProducts: filterAr}
        }
    }
    return {setFileterProducts: products}
}

// utility function
function tagFilter(tag) {
    let ar = filterProducts.filter(item => item.tag === "Denim");
    // console.log(ar);
    return ar;
}

return (
    <div className =  "container-fluid">
        <h2>All Products: {filterProducts.length}</h2>
        <Filter 
            product = {filterProducts} 
            handleSort = {handleSort} 
            sort = {sortValue}
            handleTag = {handleTag}
            tag = {tag}
        />
        <hr />
        <div className="row custom-card">
                {filterProducts.map((product, idx) => {
                    console.log(product);
                    return(
                        
                   

     <div key = {product.id} className="col-md-3 mb-2">
                                <Card products = {product}/>
                            </div>
                        )
                    })}
            </div>
        </div>
    )
}

    export default Home

这用于显示过滤器选项Filter.jsx

function Filter(props) {
    const handleChange = (event) => {
        // console.log(event.target.value);
        return props.handleSort(event.target.value);
    }

const handleTagChange = (event) => {
    // console.log(event.target.value);
    return props.handleTag(event.target.value);
}
let tagNames = ["T-shirt", "shirt", "Denim", "jacket"];
return (
    <div className="container-fluid">
        <div className="row">
            <div className="col-12 col-md-9">
                <p className = " mr-2">Filters:<span className="mr-4"></span>
                    {tagNames.map((item, idx) => (
                        <span key = {idx} >
                            <button 
                                type="button" 
                                class="btn btn-outline-secondary mr-2 custom-filter"
                                value= {item}
                                onClick = {handleTagChange}
                            >{item}</button>
                        </span>
                    ))}
                </p>
                </div>
            <div className="col-12 col-md-3">
            <select className="form-control" value = {props.sort} onChange = {handleChange}>
                {/* {console.log("CHECKING: "+props.sort)} */}
                <option value="">Sort by</option>
                <option value="lowest">lowest to highest</option>
                <option value="highest">highest to lowest</option>
            </select>
            </div>
        </div>
    </div>
)

}

    export default Filter

codesandbox link

【问题讨论】:

  • 有人能用那个取悦我吗

标签: javascript reactjs react-hooks e-commerce


【解决方案1】:

您的Filter.jsx 看起来不错,应该可以正常工作。我只做了一些简单的更改,例如将onClick 事件处理程序内联移动,并为所选按钮添加了一些样式以区分其状态。

直接改变状态

另一方面,您的 Home.jsx 看起来过于复杂,所以我需要清理一下。最大的错误之一是直接改变状态。它可能会导致非常奇怪的错误。你可能甚至没有注意到你改变了状态,但是 products.sort 改变了原来的 products 数组。

您应该先克隆数组(可以使用.slice()spread operator),对克隆进行排序,然后使用这个新排序的数组更新状态。

奇怪的返回语句

另一个问题是返回像{setFileterProducts: products}{setFileterProducts: filterAr} 这样的对象。我不确定你想做什么,也许是setFileterProducts(filterAr)

useEffect 挂钩

下一个问题是useEffect 钩子的使用。每次过滤标签、按值排序或过滤的产品发生变化时,您都尝试loadAllProducts,这是绝对不必要的。

您可以改为使用两个useEffects;一种用于从 API 加载数据并设置productsfilteredProducts 状态,另一种用于在每次标签或排序值更改时更新filteredProducts。你不需要其他任何东西,因为每当 filteredProducts 数组发生变化时,React 都会重新渲染组件。

更简单的一些

我更改了一些变量名,并尝试从Home.jsx 中删除所有不必要的行;只有状态、两个useEffect 钩子和return 语句保留。过滤和排序由钩子处理,无需为此使用额外的功能。

我还简化了排序功能。如果你想sort numbers,你只需要减去它们(因为减法会将价格的类型更改为数字,你甚至不需要再使用parseInt了)。

Home.jsx

import React, { useEffect, useState } from "react";

import data from "../../../data.json";
import Card from "../card/Card.jsx";
import Filter from "../filter/Filter.jsx";
import "./Home.css";

function Home() {
  const [products, setProducts] = useState([]);
  const [filteredProducts, setFilteredProducts] = useState([]);
  const [sortBy, setSortBy] = useState("");
  const [selectedTag, setSelectedTag] = useState("");

  useEffect(() => {
    setProducts(data);
    setFilteredProducts(data);
  }, []);

  useEffect(() => {
    const filtered = selectedTag
      ? products.filter((item) => item.tag === selectedTag)
      : products;

    setFilteredProducts(
      sortBy
        ? [...filtered].sort((a, b) =>
            sortBy === "lowest" ? a.price - b.price : b.price - a.price
          )
        : [...filtered].sort((a, b) => (a.id > b.id ? 1 : -1))
    );
  }, [selectedTag, sortBy, products]);

  return (
    <div className="container-fluid">
      <h2>Products: {filteredProducts.length}</h2>
      <Filter
        handleSort={setSortBy}
        handleTagChange={setSelectedTag}
        selectedTag={selectedTag}
        sortBy={sortBy}
      />
      <hr />
      <div className="row custom-card">
        {filteredProducts.map((product) => (
          <div key={product.id} className="col-md-3 mb-2">
            <Card products={product} />
          </div>
        ))}
      </div>
    </div>
  );
}

export default Home;

Filter.jsx:

import React from "react";
import "./Filter.css";

function Filter({ handleSort, handleTagChange, selectedTag, sortBy }) {
  let tagNames = ["T-shirt", "shirt", "Denim", "jacket"];

  return (
    <div className="container-fluid">
      <div className="row">
        <div className="col-12 col-md-9">
          <p className=" mr-2">
            Filters: <span className="mr-4"></span>
            {tagNames.map((tag, idx) => (
              <button
                key={idx}
                type="button"
                className={`btn mr-2 custom-filter ${
                  selectedTag === tag
                    ? "btn-secondary"
                    : "btn-outline-secondary"
                }`}
                onClick={(e) => handleTagChange(e.target.value)}
                value={tag}
              >
                {tag}
              </button>
            ))}
          </p>
        </div>
        <div className="col-12 col-md-3">
          <select
            className="form-control"
            onChange={(e) => handleSort(e.target.value)}
            value={sortBy}
          >
            <option value="">Sort by</option>
            <option value="lowest">Lowest to highest</option>
            <option value="highest">Highest to lowest</option>
          </select>
        </div>
      </div>
    </div>
  );
}

export default Filter;

CodeSandbox link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    相关资源
    最近更新 更多