在React中一起进行筛选和排序。

huangapple go评论68阅读模式
英文:

Filter and sort together in react

问题

以下是您要翻译的代码部分:

我无法同时筛选和排序我将从axios获取`products`并将其初始复制到`filteredProducts`然后我将点击`sort``discount`筛选选项排序在这里正常工作但与`discount`筛选一起不起作用如何在`useEffect`中实现这一点

```javascript
const [filteredProducts, setFilteredProducts] = useState([]);

const handleSort = (sortByValue) => {
    return filteredProducts.sort((a, b) => {
        switch(sortByValue) {
            case 'new' : return parseISO(b.created_at) - parseISO(a.created_at);
            case 'discount' : return b.discount - a.discount;
            case 'price_desc' : return b.price - a.price;
            case 'price_asc' : return a.price - b.price;
            default : return a.name.localeCompare(b.name);
        }
    })
}

const discount = queryParams.get('discount')
const sortBy = queryParams.get('sort')

const handleDiscountFilters = (filterResults) => {
    if(discount) {
        return filteredProducts.filter((product) => product.discount > discount)
    } else {
        return products
    }
}

// 这里我想首先调用不同的筛选函数,然后调用排序函数。
useEffect(() => {
    let filterResults = [...filteredProducts];
    filterResults = handleDiscountFilters(filterResults)
    filterResults = handleSort(sortBy)
    setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])
英文:

I am unable to filter and sort at the same time. I will be getting products from axios get call and create a copy of it into filteredProducts initially. Then i will be clicking on sort and discount filter options. Sorting is working fine here but not together with discount filter. How can i achieve this together inside useEffect ?

    const [filteredProducts, setFilteredProducts] = useState([]);

    const handleSort = (sortByValue) => {
        return filteredProducts.sort((a, b) => {
            switch(sortByValue) {
                case 'new' : return parseISO(b.created_at) - parseISO(a.created_at);
                case 'discount' : return b.discount - a.discount;
                case 'price_desc' : return b.price - a.price;
                case 'price_asc' : return a.price - b.price;
                default : return a.name.localeCompare(b.name);
            }
        })
    }
    
    const discount = queryParams.get('discount')
    const sortBy = queryParams.get('sort')

    const handleDiscountFilters = (filterResults) => {
        if(discount) {
            return filteredProducts.filter((product) => product.discount > discount)
        } else {
            return products
        }
    }
    
    // Here i want to call the different filter functions first and then call sort function. 
    useEffect(() => {
        let filterResults = [...filteredProducts];
        filterResults = handleDiscountFilters(filterResults)
        filterResults = handleSort(sortBy)
        setFilteredProducts(filterResults);
    }, [filteredProducts, handleDiscountFilters, handleSort, sortBy])

答案1

得分: 1

你需要将数组传递给handleSort函数,否则你将对初始数组进行排序,而不是过滤后的数组。

const handleSort = (products, sortByValue) => {
  return products.sort((a, b) => {
    switch (sortByValue) {
      case "new":
        return parseISO(b.created_at) - parseISO(a.created_at);
      case "discount":
        return b.discount - a.discount;
      case "price_desc":
        return b.price - a.price;
      case "price_asc":
        return a.price - b.price;
      default:
        return a.name.localeCompare(b.name);
    }
  });
};
useEffect(() => {
  let filterResults = [...filteredProducts];
  filterResults = handleDiscountFilters(filterResults);
  filterResults = handleSort(filterResults, sortBy);
  setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy]);
英文:

You have to pass the array to the handleSort function. Otherwise you sort the initial array, not the filtered one

const handleSort = (products, sortByValue) => {
  return products.sort((a, b) => {
    switch (sortByValue) {
      case "new":
        return parseISO(b.created_at) - parseISO(a.created_at);
      case "discount":
        return b.discount - a.discount;
      case "price_desc":
        return b.price - a.price;
      case "price_asc":
        return a.price - b.price;
      default:
        return a.name.localeCompare(b.name);
    }
  });
};
useEffect(() => {
  let filterResults = [...filteredProducts];
  filterResults = handleDiscountFilters(filterResults);
  filterResults = handleSort(filterProducts, sortBy);
  setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy]);

答案2

得分: 1

以下是翻译好的内容:

  1. There are a few problems with your code. The first is that you are modifying and setting filterResults in the same useEffect hook, which means you will have an infinite loop. Every time you call setFiltereddProducts the reference value of filteredProducts changes, which will cause your useEffect to fire again.

  2. Next, similar to how you pass the filterResults into handleDiscountFilters, you also need to do that for handleSort. Right now handleSort is reading from the top-level filteredProducts, which isn't being impacted by your filters:

  let filterResults = [...filteredProducts];
  filterResults = handleDiscountFilters(filterResults)
  filterResults = handleSort(filterResults, sortBy)
  1. But, except for the network call, you really don't need a useEffect at all for this:
const [products, setProducts] = useState([]);

useEffect(async () => {
    const response = await axios.get("someUrl");
    setProducts(response.data);
}, []);

const discount = queryParams.get('discount');
const sortBy = queryParams.get('sort');

const shouldFilterProduct = (product) => {
    if (discount) {
        return product.discount > discount;
    } else {
        return false;
    }
};

const sortProduct = (a, b) => {
    switch(sortByValue) {
        case 'new' : return parseISO(b.created_at) - parseISO(a.created_at);
        case 'discount' : return b.discount - a.discount;
        case 'price_desc' : return b.price - a.price;
        case 'price_asc' : return a.price - b.price;
        default : return a.name.localeCompare(b.name);
    }
}

const filteredAndSortedProducts = products
    .filter(filterProduct)
    .sort(sortProduct);

return (
    <div>
        {filteredAndSortedProducts.map(product => {
            return <div>{product.name}</div>;
        })}
    </div>
);
英文:

There are a few problems with your code. The first is that you are modifying and setting filterResults in the same useEffect hook, which means you will have an infinite loop. Every time you call setFiltereddProducts the reference value of filteredProducts changes, which will cause your useEffect to fire again.

Next, similar to how you pass the filterResults into handleDiscountFilters, you also need to do that for handleSort. Right now handleSort is reading from the top-level filteredProducts, which isn't being impacted by your filters:

  let filterResults = [...filteredProducts];
  filterResults = handleDiscountFilters(filterResults)
  filterResults = handleSort(filterResults, sortBy)

But, except for the network call, you really don't need a useEffect at all for this:

const [products, setProducts] = useState([]);

useEffect(async () =&gt; {
    const response = await axios.get(&quot;someUrl&quot;);
    setProducts(response.data);
}, []);

const discount = queryParams.get(&#39;discount&#39;);
const sortBy = queryParams.get(&#39;sort&#39;);

const shouldFilterProduct = (product) =&gt; {
    if (discount) {
        return product.discount &gt; discount;
    } else {
        return false;
    }
};

const sortProduct = (a, b) =&gt; {
    switch(sortByValue) {
        case &#39;new&#39; : return parseISO(b.created_at) - parseISO(a.created_at);
        case &#39;discount&#39; : return b.discount - a.discount;
        case &#39;price_desc&#39; : return b.price - a.price;
        case &#39;price_asc&#39; : return a.price - b.price;
        default : return a.name.localeCompare(b.name);
    }
}

const filteredAndSortedProducts = products
    .filter(filterProduct)
    .sort(sortProduct);

return (
    &lt;div&gt;
        {filteredAndSortedProducts.map(product =&gt; {
            return &lt;div&gt;{product.name}&lt;/div&gt;;
        })}
    &lt;/div&gt;
);

答案3

得分: 1

The problem is that handleSort uses the value declared in the first line of the code, so the value of filterResults assigned from the return value of handleDiscountFilters is lost, you are always using the unfiltered data.

So, to correct that I would add a parameter to the handleSort function, and use that parameter, instead of the const declared in the first line:

    const [filteredProducts, setFilteredProducts] = useState([]);

    const handleSort = (values, sortByValue) => {
        return values.sort((a, b) => {
            switch(sortByValue) {
                case 'new': return parseISO(b.created_at) - parseISO(a.created_at);
                case 'discount': return b.discount - a.discount;
                case 'price_desc': return b.price - a.price;
                case 'price_asc': return a.price - b.price;
                default: return a.name.localeCompare(b.name);
            }
        })
    }
    
    const discount = queryParams.get('discount')
    const sortBy = queryParams.get('sort')

    const handleDiscountFilters = (filterResults) => {
        if(discount) {
            return filteredProducts.filter((product) => product.discount > discount)
        } else {
            return products
        }
    }
    
    // Here i want to call the different filter functions first and then call sort function. 
    useEffect(() => {
        let filterResults = [...filteredProducts];
        filterResults = handleDiscountFilters(filterResults)
        filterResults = handleSort(filterResults, sortBy)
        setFilteredProducts(filterResults);
    }, [filteredProducts, handleDiscountFilters, handleSort, sortBy])

That's about why the filtering is being ignored, but there are other problems, I think: isn't this being rendered continuously in a loop? Because the handle___ functions are new ones every render, so the useEffect will be invoked also in every render, and useEffect is always invoking setFilteredProducts, so it will trigger another render, so it never stops rendering. Also, if you set the value after the first render, the filtered data would remain filtered (the values filtered out will be lost). I would have a state-associated variable for the source unfiltered data and another derived from it for the filtered data.

英文:

The problem is that handleSort uses the value declared in the first line of the code, so the value of filterResults assigned from the return value of handleDiscountFilters is lost, you are always using the unfiltered data.

So, to correct that I would add a parameter to the handleSort function, and use that parameter, instead of the const declared in the first line:

    const [filteredProducts, setFilteredProducts] = useState([]);
const handleSort = (values, sortByValue) =&gt; {
return values.sort((a, b) =&gt; {
switch(sortByValue) {
case &#39;new&#39; : return parseISO(b.created_at) - parseISO(a.created_at);
case &#39;discount&#39; : return b.discount - a.discount;
case &#39;price_desc&#39; : return b.price - a.price;
case &#39;price_asc&#39; : return a.price - b.price;
default : return a.name.localeCompare(b.name);
}
})
}
const discount = queryParams.get(&#39;discount&#39;)
const sortBy = queryParams.get(&#39;sort&#39;)
const handleDiscountFilters = (filterResults) =&gt; {
if(discount) {
return filteredProducts.filter((product) =&gt; product.discount &gt; discount)
} else {
return products
}
}
// Here i want to call the different filter functions first and then call sort function. 
useEffect(() =&gt; {
let filterResults = [...filteredProducts];
filterResults = handleDiscountFilters(filterResults)
filterResults = handleSort(filterResults, sortBy)
setFilteredProducts(filterResults);
}, [filteredProducts, handleDiscountFilters, handleSort, sortBy])

That's about why the filtering is being ignored, but there are other problems, I think: isn't this being rendered continously in a loop? Because the handle___ functions are new ones every render, so the useEffect will be invoked also in every render and useEffect is always invoking setFilteredProducts, so it will trigger another render, so it never stops rendering. Also, if you set the value after the first render the filtered data would remain filtered (the values filtered out will be lost). I would have a state-associated variable for the source unfiltered data and another derived from it for the filtered data.

huangapple
  • 本文由 发表于 2023年5月22日 16:37:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76304380.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定