Как фильтровать продукты по реакции js - PullRequest
0 голосов
/ 09 апреля 2020

Я изучаю реакцию и пытаюсь отфильтровать по производителю продукты, которые я ранее запрашивал через API. С этим кодом отображаются продукты, а затем вы можете фильтровать по производителю. Однако, когда вы пытаетесь отфильтровать их снова, то есть выбрать продукты другого производителя, ничего не происходит. Мой код:

import React, {useEffect} from 'react'
import Loader from './../Loader/Loader'
import ProductItem from './ProductItem'

function Catalog() {
    const [products, setProducts] = React.useState([])
    const [brands, setBrands] = React.useState([])
    const [brand, setBrand] = React.useState('')

useEffect(() => {
    const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
const url = 'https://avtodoka-msk.ru/aimylogic-mission.json'
fetch(proxyUrl + url)
    .then(response => response.json())
    .then(products => {
        setProducts(products)
        const brands = []
        products.map(product => {
            return(
                brands.push(...product.brend)
            )
        })
        setBrands([...new Set(brands)])
    })
}, [])

 function toggleBrand(e) {
    setBrand(e.target.value)

    setProducts(
        products.filter(product => {
            if ([...product.brend].includes(e.target.value)) {
                return true
            }
        })
    )

}






return (
    <div className="container pt-5">

        {brands.length ? (
            <div className="row">
                <div className="col-3">
                    <select value={brand} onChange={toggleBrand}>
                        <option value={''}>Выбрать бренд</option>

                        {brands.map((brend,index) => {
                            return(
                                <option value={brend} key={index}>{brend}</option>
                            )
                        })}
                    </select>
                </div>
            </div>
        ): null}        
        {products.length ? (

            <div className="row">

                {products.map(product => {
                    return (

                        <ProductItem 
                            key={product.id}
                            product={product}
                        />
                    )
                })}


            </div>
        ) :  <Loader />}
    </div>
)
}

export default Catalog

1 Ответ

0 голосов
/ 09 апреля 2020

Если я правильно понял, ваше состояние должно иметь:

  • products массив - содержащий ваши продукты.
  • brands массив - содержащий ваших производителей.

Если это правильно, то я вижу пару проблем с вашим кодом:

  1. You ' слишком сложные методы массива, приводящие к желаемому поведению.
  2. Теперь реальная проблема заключается в том, что при первом фильтровании вы теряете доступ ко всем продуктам, и, следовательно, вам необходимо повторно выбирать их каждый фильтр клик.

Получив это, вот ваш обновленный код:

import React, {useEffect} from 'react'
import Loader from './../Loader/Loader'
import ProductItem from './ProductItem'

function Catalog() {
    const [products, setProducts] = React.useState([])
    const [brands, setBrands] = React.useState([])
    const [brand, setBrand] = React.useState('')

    useEffect(() => {
        const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
        const url = 'https://avtodoka-msk.ru/aimylogic-mission.json'     
        fetch(proxyUrl + URL)
            .then(response => response.json())
            .then(products => {
                if (brands.length <= 0) 
                    setBrandsFromProducs(products)

                const filteredProducts = products.filter(product => !brand || product.brend.includes(brand))
                setProducts(filteredProducts)
            })
    }, [brand])

    function setBrandsFromProducs(products) {
        const brands = products.reduce(
            (acc, product) => ([...acc, ...product.brend])
        , [])
        setBrands([...new Set(brands)])
    }

    function toggleBrand(e) {
        const selectedBrand = e.target.value
        setBrand(selectedBrand)
    }

}

Ключевые аспекты:

  1. product.brend - это массив , Чтобы извлечь все бренды из этого JSON, вам нужно сгладить массив массивов, поэтому вы уменьшаете его до плоского массива - следовательно, используется .reduce(). Это нужно делать только в том случае, если массив brands пуст. Однако, если вас не беспокоит производительность, вы можете удалить оператор if, чтобы всегда сбрасывать массив brands.
  2. Ваше событие выбирает марку, оно не должно содержать никаких других побочных эффектов. (фильтрация товаров). Те должны жить в надлежащем объеме -> useEffect. Чтобы вызвать это событие, вам необходимо «прослушать» изменения в фильтре brand, поэтому его необходимо указать как зависимость useEffect.
  3. В вашем filter отсутствует return false вне оператора if. Однако это можно упростить, поскольку .include () возвращает логическое значение и не изменяет исходный массив. Фильтр, который я создал, сначала проверит, есть ли у вас активный фильтр, и фильтрует его только в том случае, если он у вас есть.
  4. Необходимо убедиться, что e.target.value - это точная строка из массива product.brend.

Небольшие предложения:

  1. Если вы управляете API, ваши фильтры всегда должны быть на стороне сервера, чтобы избежать больших полезных нагрузок, чем вам нужно.
  2. Если вы не используете состояние brand, вы можете безопасно удалить его. Без вашего JSX я не могу быть уверен.
...