Javascript 正在删除中的列表项,请保留旧项

Javascript 正在删除中的列表项,请保留旧项,javascript,reactjs,Javascript,Reactjs,我想从列表中删除所选项目 当我单击delete(删除)时,右项将从列表内容中删除,但在UI上,我始终会触发列表项 我似乎跟踪JSX键并显示最后的值 这里有一个 const Holidays=(道具)=>{ 控制台日志(道具); const[state,setState]=useState({…props}); useffect(()=>{ 设置状态(道具); console.log(状态); }, []); const addNewHoliday=()=>{ const obj={开始:“12/

我想从列表中删除所选项目

当我单击delete(删除)时,右项将从列表内容中删除,但在UI上,我始终会触发列表项

我似乎跟踪JSX
并显示最后的值

这里有一个

const Holidays=(道具)=>{
控制台日志(道具);
const[state,setState]=useState({…props});
useffect(()=>{
设置状态(道具);
console.log(状态);
}, []);
const addNewHoliday=()=>{
const obj={开始:“12/12”,结束:“12/13”};
setState(更新(状态,{daysoflist:{$push:[obj]}});
};
常数deleteHoliday=(i)=>{
const objects=state.daysOffList.filter((elm,index)=>index!=i);
log({objects});
setState(更新(状态,{daysoflist:{$set:objects}}));
console.log(state.daysOffList);
};
返回(
问题
您正在使用数组索引作为React键,并且正在变异基础数据数组。当您单击第二个条目将其删除时,第三个元素向前移动以填补空白,现在为刚刚删除的元素分配了React键。React使用该键帮助协调,如果该键保持稳定,React在重新提交UI时退出

您也不能在列队状态更新后立即控制台日志状态,并期望看到更新的状态

setState(update(state, { daysOffList: { $set: objects } }));
console.log(state.daysOffList);
React状态更新是异步的,在
渲染周期之间进行处理。上述更新可以并且将只记录当前渲染周期中的状态值,而不是排队等待下一个渲染周期的更新

解决方案 为每个开始/结束数据对象使用GUID。这是一个非常好的包,具有很好的唯一性保证,并且使用起来非常简单

import { v4 as uuidV4 } from 'uuid';

// generate unique id
uuidV4();
要具体解决代码中的问题,请执行以下操作:

  • id
    属性添加到数据中

     const daysOffList = [
       { id: uuidV4(), start: "12/12", end: "12/15" },
       { id: uuidV4(), start: "12/12", end: "12/17" },
       { id: uuidV4(), start: "12/12", end: "12/19" }
     ];
    
     ...
    
     const addNewHoliday = () => {
       const obj = {
         id: uuidV4(),
         start: "12/12",
         end: "12/13",
       };
       setState(update(state, { daysOffList: { $push: [obj] } }));
     };
    
  • 更新处理程序以使用要删除的id

     const deleteHoliday = (id) => {
       const objects = state.daysOffList.filter((elm) => elm.id !== id);
       setState(update(state, { daysOffList: { $set: objects } }));
     };
    
  • 使用element id属性作为React键

     {state.daysOffList?.map((elm, i) => {
       return (
         <Flex key={elm.id} gap="gap.small">
           ...
         </Flex>
       );
     })}
    
演示

注意:如果您不想(或不能)安装额外的第三方依赖项,那么您可以使用自己的id生成器。这将在紧要关头起作用,但您确实应该寻求真正经验证的解决方案

const genId = ((seed = 0) => () => seed++)();
genId(); // 0
genId(); // 1

问题是你正在使用数组中的索引作为键。这是。你对旧项目说什么,你的意思是你不需要jsx来再次渲染?我不明白,你能解释更多细节吗?plz:)为了确认@PatrickRoberts说的话,如果你改成
key={JSON.stringify(elm)}
您会发现正确的项目被删除。但是,对于“密钥”来说,这并不是一个好的长期解决方案我的意思是,如果我有A,B,C,我删除B,是我的数据,它会得到A,C,但在UI中它会显示A,B,如果我再次删除A,在UI中它会显示A,B,C,因为你使用数组索引作为React键,并改变底层数据,索引0和1仍然存在,并且没有改变,所以React bails会重新提交与之关联的JSX这些键。选择映射数据固有/唯一的react键。如果数据不具有此质量,请使用GUID属性扩充数据以用于此目的。
 {state.daysOffList?.map((elm, i) => {
   return (
     <Flex key={elm.id} gap="gap.small">
       ...
     </Flex>
   );
 })}
 <Button
   primary
   icon={<TrashCanIcon />}
   text
   onClick={() => deleteHoliday(elm.id)}
 />
 useEffect(() => {
   console.log(state.daysOffList);
 }, [state.daysOffList]);
const genId = ((seed = 0) => () => seed++)();
genId(); // 0
genId(); // 1