Как установить состояние

#javascript #reactjs #web #redux

#javascript #reactjs #веб #redux

Вопрос:

Добрый вечер,

я совсем новичок в react, и я создаю свой первый крупный проект. Я хочу сделать следующее: я хочу изменить значение состояния элементов, когда пользователь выбирает определенный размер продукта. Когда пользователь выбирает размер, на экране должны появляться продукты только такого размера. Последнее, что я должен сделать, это установить состояние, когда пользователь изменяет размер, но я не могу этого сделать:

мой код:

 import React, { Component, useEffect, useState } from 'react'
import { listProduct } from '../../actions/productActions'
import { useDispatch, useSelector } from 'react-redux'

const Filter = () => {
  const productList = useSelector((state) => state.productList)
  const { products } = productList
  const dispatch = useDispatch()
  const [items, setItem] = useState([])

  useEffect(() => {
    dispatch(listProduct())
    setItem(products)
  }, [])

  console.log(items)

  const handleChange = (e) => {
    if (e.target.value === 'S') {
      return console.log(products.filter((item) => item.size === 'S'))
    } else if (e.target.value === 'XS') {
      return console.log(products.filter((item) => item.size === 'XS'))
    } else if (e.target.value === 'M') {
      return console.log(products.filter((item) => item.size === 'M'))
    } else if (e.target.value === 'L') {
      return console.log(products.filter((item) => item.size === 'L'))
    } else if (e.target.value === 'XL') {
      return console.log(products.filter((item) => item.size === 'XL'))
    } else {
      return console.log(products)
    }
  }

  return (
    <div className="filter">
      <label>
        Order:
        <select>
          <option value="lowest">Lowest to Highest</option>
          <option value="highest">Highest to Lowest</option>
        </select>
      </label>
      <label>
        Size:
        <select className="size" onChange={handleChange}>
          <option value="">ALL</option>
          <option value="XS">XS</option>
          <option value="S">S</option>
          <option value="M">M</option>
          <option value="L">L</option>
          <option value="XL">XL</option>
        </select>
      </label>
    </div>
  )
}

export default Filter
  

Ответ №1:

Вы возвращаетесь:

 return (
              console.log(products.filter(item =>item.size === "S"  ) ) 
                 
            )
  

console.log() конечно, это не влияет на фактическое состояние компонента.
Попробуйте использовать setItem(products) для обновления вашего состояния

Комментарии:

1. хорошо сделал это, но я думаю, что я делаю что-то не так с рендерингом.

2. console.log что-нибудь печатает?

3. да, это консоль. регистрирует продукты на основе выбранного размера

4. где вы хотите отфильтрованные продукты? Если вам нужно отфильтровать их в другом компоненте, таком как таблица продуктов, вам придется использовать для них другое состояние. Как вы это написали, ваши отфильтрованные продукты будут доступны только внутри компонента фильтра

Ответ №2:

И именно здесь я создал свой компонент продукта:

 import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { Library } from '@fortawesome/fontawesome-svg-core'
import { faShoppingBasket } from '@fortawesome/free-solid-svg-icons'
import { useDispatch, useSelector } from 'react-redux'
import Filter from './filter'
import { listProduct } from '../../actions/productActions'

function Product(props) {
  //default value is an array, because we've got data in an array
  const [qty, setQty] = useState(1)
  const productList = useSelector((state) => state.productList)

  const { products, loading, error } = productList
  const dispatch = useDispatch()
  const [items, setItems] = useState()

  useEffect(() => {
    dispatch(listProduct())
  }, [])

  // handlefilter

  // handle cart adding
  const handleAddToCart = () => {
    props.history.push('/cart/'   props.match.params.id   '?qty'   qty)
  }

  return (
    // Check the loading before rendering products
    loading ? (
      <div>
        <h1 className="load">loading...</h1>
      </div>
    ) : error ? (
      <div>{error}</div>
    ) : (
      <ul className="products">
        {products.map((product) => (
          <li key={product.id} className="product">
            <Link to={'/product/'   product.id}>
              <div
                className="img"
                style={{
                  background: `url(${product.img})`,
                  backgroundSize: 'cover',
                }}
              ></div>
            </Link>
            {/* LOOK OUT FOR TYPOS IN ROUTIING  dont put':' after /, this only applies
                       when routing because the ": " implies for a parameter
                       In this case you can directly access product.id  */}
            <Link to={'/product/'   product.id}>
              <h1>{product.name}</h1>
            </Link>
            <p>
              {' '}
              <small></small>
              {product.price}
            </p>
            <div>size: {product.size}</div>

            {product.qty > 0 ? (
              <div>
                <button onClick={handleAddToCart}>Add to cart</button>{' '}
                <div>{product.qty} left</div>
              </div>
            ) : (
              <div>out of stock</div>
            )}
          </li>
        ))}
      </ul>
    )
  )
}
export default Product
  

итак, я хочу отобразить конкретный продукт на основе выбранного размера

Ответ №3:

 import React, { useState, useEffect } from "react";
import "./styles.css";

export default function App() {
  const products = [
    { size: "S" },
    { size: "S" },
    { size: "XS" },
    { size: "XS" },
    { size: "M" },
    { size: "M" },
    { size: "L" },
    { size: "L" },
    { size: "XL" },
    { size: "XL" }
  ];
  const [items, setItem] = useState([]);

  useEffect(() => {
    setItem(products);
  }, []);

  const handleChange = ({ target: { value } }) => {
    let filteredProducts = [];
    filteredProducts =
      value === "ALL"
        ? [...products]
        : products.filter((item) => item.size === value);

    console.log(value);

    setItem(filteredProducts);
  };

  return (
    <div className="filter">
      <label>
        Order:
        <select>
          <option value="lowest">Lowest to Highest</option>
          <option value="highest">Highest to Lowest</option>
        </select>
      </label>
      <label>
        Size:
        <select className="size" onChange={handleChange}>
          <option value="ALL">ALL</option>
          <option value="XS">XS</option>
          <option value="S">S</option>
          <option value="M">M</option>
          <option value="L">L</option>
          <option value="XL">XL</option>
        </select>
      </label>

      <ul>
        {items.map((p) => (
          <li>{p.size}</li>
        ))}
      </ul>
    </div>
  );
}
  

Вам просто нужно передать отфильтрованный массив в setItems и отобразить элементы в html.