Отфильтровать отфильтрованный массив и визуализировать

Как я могу отфильтровать отфильтрованный массив? Допустим, я фильтрую товары по цене. Предположим, что значение ползунка входного диапазона (цена) меньше тысячи долларов, тогда он вернет массив, который меньше указанного значения, равного тысяче долларов. Теперь, если я хочу снова отфильтровать, используя кнопки фильтра бренда или категории, например, я выбрал бренд «ikea» из фильтров брендов. Как я могу отфильтровать возвращаемый массив по отфильтрованной цене? Прямо сейчас, когда я фильтрую продукты по цене, он может возвращать массив, но когда я снова фильтрую по категории/бренду, он возвращает массив, который не исходит из отфильтрованного массива цен.

Вот мои коды:

export const state = {
  products: [], //this is where I stored all the products coming from the API
  filters: {
    categories: [], //this is where I stored all the categories
    brands: [], //this is where I stored all the brand
    price: 0, //this is where I stored the max price from the array
  },
};

@значение параметра — целочисленное значение, полученное от ползунка диапазона ввода.

export const loadFilterPrice = function (value) {
  return state.products.filter(product => product.price <= value);
};

@тип параметра - строковое значение "бренд" или "категория" @значение параметра - строковое значение брендов/категорий,

export const loadFilterProductByType = function (type, value) {
  if (value === 'all') return state.products;

  return state.products.filter(product => product[type] === value);
};

Есть и другая проблема. Если вы хотите отфильтровать как по category, так и по brand — скажем, нужно показать только категорию table от бренда ikea — это также будет невозможно с текущей логикой.

jsN00b 09.04.2022 07:43

Что я должен делать?

J.Wujeck 09.04.2022 07:48

Вам нужно создать метод, который перебирает все свойства в state.filters, а затем фильтрует и возвращает отфильтрованное состояние, используя loadFilterProductByType каждый раз, когда он зацикливается. Наконец, запустите loadFilterPrice() после начального цикла в созданном вами методе.

Rickard Elimää 09.04.2022 10:37
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
Четыре эффективных способа центрирования блочных элементов в CSS
Четыре эффективных способа центрирования блочных элементов в CSS
У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то...
1
3
61
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы отфильтровали продукты, но не назначили новую переменную/состояние для отфильтрованных продуктов

Вы можете добавить переменную filteredProducts здесь

export const state = {
  products: [], //this is where I stored all the products coming from the API
  filteredProducts: [] //this should be a clone of `products`
  filters: {
    categories: [], //this is where I stored all the categories
    brands: [], //this is where I stored all the brand
    price: 0, //this is where I stored the max price from the array
  },
};

Всякий раз, когда вы изначально назначаете значение для products из вызова API, вы также можете назначить значение filteredProducts

//`respondedProducts` is from API calls
state.products = [...respondedProducts]
state.filteredProducts = [...respondedProducts]

Вот как мы это используем

export const loadFilterPrice = function (value) {
  if(!value) return state.products; //return the original product list

  return state.filteredProducts.filter(product => product.price <= value);
};
state.filteredProducts = loadFilterPrice(1000) //need to update filtered products variable

Точно так же мы можем применить его к loadFilterProductByType

export const loadFilterProductByType = function (type, value) {
  if (value === 'all') return state.products; //return the original product list

  return state.filteredProducts.filter(product => product[type] === value);
};
state.filteredProducts = loadFilterProductByType('brand', 'ikea') //need to update filtered products variable

Я получаю сообщение об ошибке «продукты не определены».

J.Wujeck 09.04.2022 18:11

какую строчку ты понял, @J.Wujeck?

Nick Vu 09.04.2022 18:12

Эта строка: filteredProducts: [...products]

J.Wujeck 09.04.2022 18:13

@ J.Wujeck, о, это просто пример того, как я его клонирую, когда вы назначаете значение для products, вы также можете присвоить это значение filteredProducts. Это может быть из вашего вызова API.

Nick Vu 09.04.2022 18:15

@ J.Wujeck, кстати, я обновил эту часть, чтобы сделать ее менее запутанной, дайте мне знать, если у вас есть дополнительные вопросы: D

Nick Vu 09.04.2022 18:23

Теперь он работает, но есть проблема, когда значение диапазона ввода равно 0, а затем я увеличиваю значение диапазона ввода (перемещая ползунок вправо), он не отображает продукты. Почему это происходит?

J.Wujeck 09.04.2022 18:34
if(!value) return state.products; вам нужно убедиться, что в исходном списке отфильтрованы продукты, когда значение равно 0 @J.Wujeck
Nick Vu 09.04.2022 18:38

Спасибо за это. Но мне нужно показать сообщение об ошибке, когда значение равно 0, тогда, когда я увеличу диапазон ввода, он отобразит продукты.

J.Wujeck 09.04.2022 18:50

Теперь он работает нормально для вас? @Дж.Вуджек

Nick Vu 09.04.2022 18:51

Да, но есть проблема.

J.Wujeck 09.04.2022 18:52

Хм, у меня здесь нет исполняемого кода, я не уверен, с какой проблемой вы столкнулись @J.Wujeck

Nick Vu 09.04.2022 18:53

Это решение специально пытается ответить ниже:

What should I do?

Есть несколько способов сделать это. Оптимальными способами могут быть использование useMemo, useCallback и т. д.

Ниже приведен только один способ, которым это можно сделать, основанный только на useState и useEffect.

const {useState, useEffect} = React;

const Thingy = ({initState, ...props}) => {
  const [products, setProducts] = useState(
    [
      ...initState.products.map(
        x => ({...x, filtered: false})
      )
    ]
  );
  const [filters, setFilters] = useState({
    categories: "", brands: "", price: 0 // Number.MAX_VALUE
  });
  const [showFilters, setShowFilters] = useState(false);
  const [filterPrice, setFilterPrice] = useState(0);
  const renderFilterFor = col => (
    <div>
      <label> {col} </label>
      <select
        name={col}
        onChange={e => {
          const v = e.target.value;
          setFilters(prev => ({
            ...prev,
            [col]: v !== 'None' ? v : ""
          }));
        }}
      >
        {
          [
            'None', ...new Set(products.map(ob => ob[col]))
          ].map(cat => (
            <option value={cat}>{cat}</option>
          ))
        }
      </select>
    </div>
  );
  const applyFilter = pr => (
    Object.entries(filters)
    .filter(([k, v]) => ((k === 'price' && v > 0) || v.length > 0))
    .every(([k, v]) => ((k === 'price' && pr[k] <= v) || pr[k] === v))
  );
  useEffect(
    () => setProducts(
      prev => prev.map(
        p => ({
          ...p,
          filtered: applyFilter(p)
        })
      )
    ),
    [filters]
  );
  return (
    <div>
      <button
        onClick={() => setShowFilters(prev => !prev)}
      >
        {showFilters ? 'Hide' : 'Show'} Filters
      </button>
      {
        showFilters && (
          <div class="filtersLine">
            <div>{renderFilterFor("categories")}</div>
            <div>{renderFilterFor("brands")}</div>
            <label for="priceInp">Enter price: </label>
            <input
              type="number" value={filterPrice} min={0}
              onChange={e => {
                const v = e.target.value;
                setFilterPrice(v);
                setFilters(prev => ({
                  ...prev,
                  price: +v
                }));
              }}
            />
          </div>
        )
      }
      {
        products.filter(({filtered}) => filtered).map(
          ({productId, productName, categories, brands, price}) => (
            <div class="singleProduct" key={productId}>
              {productName}
              <b>Category: </b>{categories}
              <b>Brand: </b>{brands}
              <b>Price: </b>{price}
            </div>
          )
        )
      }
    </div>
  );
};

const initState = {
  products: [...Array(15).keys()].map(i => ({
    productId: i+1,
    productName: `Product - ${i+1}`,
    categories: `Category - ${i % 3 +1}`,
    brands: `Brand - ${i % 4 +1}`,
    price: Math.floor(Math.random() * ((i+1) * 5))
  }))
};

ReactDOM.render(
  <div>
    DEMO
    <Thingy initState={initState}/>
  </div>,
  document.getElementById("rd")
);
.singleProduct {
  border: 2px solid grey;
  margin: 5px;
  width: 85%;
}
.singleProduct > *{
  margin: 15px;
  padding: 5px;
}

.filtersLine {
  display: flex;
  margin: 15px;
  align-items: center;
  justify-content: space-between;
  width: 85%;
}
.filtersLine > label { margin: 10px; }
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>

Спасибо за это, но я не использую js framework. Я просто использую vanilla js.

J.Wujeck 09.04.2022 17:06

Другие вопросы по теме

Похожие вопросы

Когда я пытаюсь удалить указанный массив с помощью indexOf и splice, другое значение удаляется
Неверный вызов ловушки. Хуки могут быть вызваны только внутри тела функционального компонента (реактивный)
Локальная статическая переменная JavaScript, как в C/C++
Как обратные вызовы получают доступ к методам
OnClick не работает, когда я пытаюсь изменить значение переменной
Как я могу поместить новый объект Book в пустой массив, используя синтаксис класса?
Как очистить ввод при изменении другого ввода
Как сделать волну фоновой анимации с помощью JavaScript?
Как я могу использовать подсказку, если и еще в функции Javascript, чтобы выбрать арифметический символ и выполнить некоторые вычисления с пользовательскими входами
Я хочу приостановить/воспроизвести анимацию CSS с помощью одной кнопки с помощью Javascript. Цвета солнца и неба должны управляться кнопкой