#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.