React中for循环无论数组长度仅执行一次 多选框操作异常求助
问题根因
校验函数逻辑错误
你写的verify函数在for循环的第一次迭代就会强制终止:如果数组第一个元素的id和传入的elem相等就返回true,否则直接返回false,完全不会遍历数组剩下的元素。这就是控制台永远只打印索引0、除了最后添加的元素(因为你用unshift插在数组头部,是第一个元素)之外都删不掉的核心原因。直接修改状态数组违反React不可变原则
你执行let newlist = filtergenres时,并没有生成新的数组,只是把newlist指向了原状态数组的引用,后续的splice、unshift操作都是直接修改原有state,会导致React无法正确检测状态变更,出现渲染不同步的问题。额外补充:React的状态更新是异步批量执行的,你在setFilterGenres之后立即打印filtergenres,拿到的永远是更新前的旧值,属于正常现象,要查看更新后的状态可以打印新生成的数组,或者通过useEffect监听filtergenres的变化来获取最新值。
修复方案
直接重构复选框切换逻辑,替换原有的verify函数和changeValue函数即可,代码如下:
import React, { useState, useEffect } from 'react'; import { Dialog, DialogTitle, DialogContent, makeStyles, ListItemSecondaryAction } from '@material-ui/core'; import { Button, ButtonToolbar } from 'react-bootstrap'; import Grid from '@material-ui/core/Grid'; import * as FaIcons from 'react-icons/fa'; import './FilterPopup.css' import { filterData } from './filterData'; import { genresData } from './genresData' export default function Filter(props) { const { title, children, openPopup, setOpenPopup, genres, setGenres } = props; const [filtergenres, setFilterGenres] = useState([]); function changeValue(elem) { // 先拷贝原数组,生成新的数组引用,符合不可变更新要求 const newList = [...filtergenres]; // 查找当前元素在数组中的索引 const existIndex = newList.findIndex(item => item.id === elem); if (existIndex > -1) { // 存在就删除对应位置的元素 newList.splice(existIndex, 1); } else { // 不存在就添加到头部 newList.unshift({ id: elem, value: elem }); } // 更新状态 setFilterGenres(newList); } return ( <Dialog open={openPopup} className='filterDialog' maxWidth="md"> <DialogTitle> <div className='popupTitle'> Filter </div> <Button className='popupCloseBtn' onClick={() => { setOpenPopup(false) }}> <FaIcons.FaTimes /> </Button> </DialogTitle> <DialogContent dividers> <form className='pop-up-forms'> <label className='popuppart'> Sort By: <select className='filter-sort'> {filterData.map((item, index) => { return ( <option key={index} value={item.value}>{item.title}</option> ) })} </select> <Button className='popupSearchSubmitBtn' onClick={() => { }}> submit </Button> </label> <label className='popuppart'> Include Adult: <input className='filterchkbox' name="isAdult" type="checkbox" /> </label> <label className='filterGenres'> Genres: <Grid container spacing={1} direction="row" justify="center" alignItems="center"> {genresData.map((item, index) => { return ( <Grid item key={index}> <label className='genresLabel'> {item.name} <input className='filterchkbox' name="genres" {/* 这里修正了之前所有分类复选框name都写成isAdult的笔误 */} type="checkbox" value={item.id} onClick={() => { changeValue(item.id) }} /> </label> </Grid> ) })} </Grid> </label> </form> </DialogContent> </Dialog > ) }
内容的提问来源于stack exchange,提问作者Ndifreke James Okpo
相关产品推荐
相关产品推荐

