使用钩子根据React中选中的复选框过滤对象数组以渲染项目



这里缺少什么??我一直在尝试在React中有条件地过滤一组对象。我把一切都安排好了,并按照我认为应该的方式工作,但我认为我只是在缺乏经验的情况下把一些事情搞混了。

最终,我希望在开始时渲染所有对象,但随后根据选中的复选框进行过滤。由于某种原因,渲染内容的条件语句根本不起作用,虽然我可以存储复选框状态并在每次单击时更改,但我无法对其进行筛选。

这是我为组件(StoneDisplay.js(编写的代码。它呈现了用于筛选要显示的石头列表的复选框列表,以及显示石头列表的容器。它包含我的复选框的State实例,以及要显示的石头的条件呈现代码。为了说明显而易见的一点,如果没有条件代码,所有项目都会表现得很好。

import React, { /* useEffect, */ useState } from 'react'
import StoneFilter from '../StoneFilter/StoneFilter'
import Stone from '../Stone/Stone'
import './StoneDisplay.css'
const StoneDisplay = ({ stones }) => {
const [checkedType, setCheckedType] = useState({})
const [checkedColor, setCheckedColor] = useState({})
//const [stonesToShow, setStonesToShow] = useState(stones)   // for useEffect
console.log('stones in StoneDisplay: ', stones)
//console.log('stonesToShow in Display: ', stonesToShow)  // for useEffect
console.log('checkedType in StoneDisplay: ', checkedType)
console.log('checkedColor in StoneDisplay: ', checkedColor)

///// This is code I am trying to filter stones conditionally without instance of state. /////
const stonesToShow = (checkedType === {} && checkedColor === {}) // (checkedType.length === 0 && checkedColor.length === 0) tried this too, but had difficulty with length and current setup..
? stones 
: stones.filter(item => item.type === checkedType && item.color === checkedColor) // need to figure what is wrond with this filter
//stones.filter((item) => true) // Use this filter to 'override' filter to show rendering functions work.
console.log('checkedType.length: ', checkedType.length) // attempt to try and use .length for initial statement for conditional
console.log('checkedColor.length: ', checkedColor.length)// i.e. (checkedType.length === 0 && checkedColor.length === 0) ? ..
///// This code I'm trying to filter stones using state/useEffect that has been recommended. /////
// useEffect(() => {
//   setStonesToShow(currentStones => {
//     console.log('currentStones in useEffect: ', currentStones)
//     return currentStones.filter((item) => true); // Use this filter to 'override' filter to show rendering functions work.

//     //return currentStones.filter(item => item.type === checkedType && item.color === checkedColor) // Need to fix this
//   })
// }, [checkedType, checkedColor])

return (
<section className="stone">
<StoneFilter
checkedType={checkedType}
setCheckedType={setCheckedType}
checkedColor={checkedColor}
setCheckedColor={setCheckedColor}
/>
<div className="stone__carousel">
{stonesToShow.map((stone) =>
<Stone
key={stone.id}
stone={stone}
/>
)}
</div>
</section>
)
}
export default StoneDisplay

这是包含我的复选框的组件。我不断回到这里,因为我相信我的问题可能来自于我如何处理/拯救这个州。但我无法确定如何/为什么。。

import React from 'react'
import StoneFilterListItem from '../StoneFilterListItem/StoneFilterListItem'
import checkboxesType from './checkboxesType'
import checkboxesColor from './checkboxesColor'
import './StoneFilter.css'
const StoneFilter = ({ checkedType, setCheckedType, checkedColor, setCheckedColor }) => {

const handleTypeChange = event => {
setCheckedType({
...checkedType,
[event.target.value]: event.target.checked
})
}
const handleColorChange = event => {
setCheckedColor({
...checkedColor,
[event.target.value]: event.target.checked
})
}

return (
<div className="stone__nav">
<h2 className="stone__nav-head">Type</h2>
<div className="stone__nav-list">
{checkboxesType.map(item => (
<label className="stone__nav-var" key={item.key}>
{item.value}
<StoneFilterListItem
id={item.id}
value={item.value}
checked={checkedType[item.value]}
onChange={handleTypeChange}
/>
<span className="checkmark"></span>
</label>
))}
</div>
<h2 className="stone__nav-head">Couleur</h2>
<div className="stone__nav-list">
{checkboxesColor.map(item => (
<label className="stone__nav-var" key={item.key}>
{item.value}
<StoneFilterListItem
id={item.id}
value={item.value}
checked={checkedColor[item.value]}
onChange={handleColorChange}
/>
<span className="checkmark"></span>
</label>
))}
</div>
</div>
)
}
export default StoneFilter

以下是我的每个复选框列表项的组件:

import React from 'react'

const StoneFilterListItem = ({ type = "checkbox", id, value, checked = false, onChange }) => {
console.log('StoneFilterListItem: ', id, value, checked)

return (
<input type={type} id={id} value={value} checked={checked} onChange={onChange} />
)
}
export default StoneFilterListItem

这是用于筛选类型的checkboxesType.js,chcekboxesColor,js类似,所以我不认为我也需要发布它。

const checkboxesType = [
{
id: "Marbre",
key: "checkbox1",
label: "marbre",
value: "Marbre"
},
{
id: "Granit",
key: "checkbox2",
label: "granit",
value: "Granit"
},
{
id: "Onyx",
key: "checkbox3",
label: "onyx",
value: "Onyx"
},
{
id: "Travertin",
key: "checkbox4",
label: "travertin",
value: "Travertin"
},
{
id: "Quartz",
key: "checkbox5",
label: "quartz",
value: "Quartz"
},
{
id: "Terrazzo",
key: "checkbox6",
label: "terrazzo",
value: "Terrazzo"      
}   
]
export default checkboxesType 

添加App.js只是以防万一:

import React, { useState, useEffect } from 'react'
import Header from '../Header/Header'
import NavBar from '../NavBar/NavBar'
import About from '../About/About'
import StoneDisplay from '../StoneDisplay/StoneDisplay'
import Contact from '../Contact/Contact'
/* import stoneService from '../../services/stones' */
import axios from 'axios'
import './App.css'
const App = () => {
const [stones, setStones] = useState([])
useEffect(() => {
console.log('effect');
axios
.get('http://localhost:3001/stones')
.then(response => {
console.log('promise fulfilled')
setStones(response.data)
})
}, [])
console.log('render', stones.length, 'stones')
return (
<div className="appContainer">
<Header />
<NavBar />
<About />
<StoneDisplay stones={stones} />
<Contact />
</div>
)
}
export default App

这是石阵。目前使用json服务器进行开发:

{
"stones": [
{
"id": 1,
"important": true,
"name": "Bianco Sivec",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/BiancoSivec1.jpg"
},
{
"id": 2,
"important": true,
"name": "Imperial White",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/ImperialWhite1.jpg"
},
{
"id": 3,
"important": true,
"name": "Fantasy White",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/FantasyWhite1.jpg"
},
{
"id": 4,
"important": true,
"name": "Infinito",
"type": "Marbre",
"color": "Blanc",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Infinito1.jpg"
},
{
"id": 5,
"important": true,
"name": "Fantasy Gold",
"type": "Marbre",
"color": "Beige",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/FatasyGold1.jpg"
},
{
"id": 6,
"important": true,
"name": "Labareda",
"type": "Quartz",
"color": "Multi",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Labareda1.jpg"
},
{
"id": 7,
"important": true,
"name": "Honey Blue",
"type": "Granit",
"color": "Bleu",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/HoneyBlue1.jpg"
},
{
"id": 8,
"important": true,
"name": "Black Taurus",
"type": "Granit",
"color": "Noir",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/BlackTaurus1.jpg"
},
{
"id": 9,
"important": true,
"name": "Lavender",
"type": "Onyx",
"color": "Bleu",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/Lavender1.jpg"
},
{
"id": 10,
"important": true,
"name": "Mercury Black",
"type": "Travertin",
"color": "Noir",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/MercuryBlack1.jpg"
},
{
"id": 11,
"important": true,
"name": "Mount Ranier",
"type": "Quartz",
"color": "Beige",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/MountRanier1.jpg"
},
{
"id": 12,
"important": true,
"name": "Red Multicolor",
"type": "Travertin",
"color": "Rouge",
"origin": "Macédoine",
"finish": "Poli",
"thickness": "3cm, 2cm",
"image": "assets/img/stone/RedMulticolor1.jpg"
}
]
}

对于我在这里做错的事情,任何帮助或指导都将不胜感激。

这是一个包含相关组件的代码沙盒:

https://codesandbox.io/s/cool-keldysh-627yx?file=/src/StoneDisplay.js

我遵循了下面给出的答案,并为stonesToShow创建了一个state实例(仍然在这里,只是注释掉了(。我一直遇到障碍,所以我回到了以前的状态,尝试整理过滤器,然后将重构到建议的实现中。

如果不查看您的详细实现,我认为您在这里错过了显而易见的东西:您的stonesToShow数组永远不会对初始渲染后所做的更改做出反应。这是因为你把它定义为";正常的";在分量CCD_ 2中可变;React";状态const [stonesToShow, setStonesToShow] = useState(...)

这里是一个非常基本的例子,它修改数组中的值,一次用useState,另一次用"0";正常的";组件中的变量:

https://codesandbox.io/s/floral-hooks-nsnvt?file=/src/App.tsx

当你点击";修改数组";按钮,您可以看到React不会基于对";正常变量";。你需要useState/useEffect

举个例子:

const StoneDisplay = ({ stones }) => {
const [stoneType, setStoneType] = useState({})
const [stoneColor, setStoneColor] = useState({})
const [stonesToShow, setStonesToShow] = useState(stones) // initialized from props
useEffect(() => {
setStonesToShow(currentStones => {
return currentStones.filter(item => item.type === stoneType.checked && stoneColor.checked)
})
}, [stoneType.checked, stoneColor.checked]) // re-filter the array when one of these changes
...

使用useEffect设置状态实际上会触发重新应答器。

最新更新