Javascript 在设置状态之前,检查对象数组中是否存在对象数组的简单方法

Javascript 在设置状态之前,检查对象数组中是否存在对象数组的简单方法,javascript,arrays,reactjs,react-state-management,Javascript,Arrays,Reactjs,React State Management,考虑以下几点: this.setState({ validations: [...this.state.validations, ...validations] }, () => { // ... Do something }); 我正在执行的操作:[…this.state.validations,…validations]validations是一个对象数组 例如: // validation [{message: 'hello', isError: tru

考虑以下几点:

  this.setState({
    validations: [...this.state.validations, ...validations]
  }, () => {
    // ... Do something
  });
我正在执行的操作:
[…this.state.validations,…validations]
validations是一个对象数组

例如:

// validation
[{message: 'hello', isError: true, fieldId: 87}, ....] 
实际上,每次出现验证错误时,我们都会将一个对象数组设置为一个数组,如上面所示

问题是有时会添加重复的对象。我所说的复制是指消息部分,因此
this.state.validations
可能看起来像:

[
  {message: 'hello', isError: true, fieldId: 87}, 
  {message: 'hello', isError: true, fieldId: 87}, 
  {message: 'hello', isError: true, fieldId: 87}, 
  ...
]
我要做的是根据
validations
中的消息和字段ID筛选
此.state.validations
,并说:

 // If this message doesn't exist for this field id, set it.

有没有一种简单而不杂乱的方法,我可以使用过滤器之类的东西,要循环状态验证以及比较fieldId和message的验证,如果它不存在:添加?

您可以使用验证每个验证是否已经存在,如果它不存在,则只添加到状态验证

var状态验证=[
{消息:“你好”,isError:true,fieldId:87},
{消息:'hello',isError:true,fieldId:42},
{消息:'error',isError:true,fieldId:95},
];
var验证=[
{message:'hello',isError:true,fieldId:42},//已存在。
{message:'hello',isError:true,fieldId:101}//新项。
];
//检查每个验证是否已经存在,只有不存在时才添加。
validations.forEach(validation=>{
const found=stateValidations.find(item=>item.message==validation.message
&&item.fieldId==验证.fieldId);
如果(!找到){
//如果未找到,请添加验证。
stateValidations.push(验证);
}
});

log(JSON.stringify(stateValidations))将验证构造为对象而不是数组的更好方法之一

e、 g


验证:{
[fieldId1]:[{message:'hello',isError:true},{message:'bye',isError:true}],
[fieldId2]:[{message:'hello',isError:true}],
}

使用此结构,您可以通过一个字段Id清楚地看到所有验证都存在哪些内容

现在,要确定fieldId上是否已经进行了验证,您可以执行以下操作:

  this.setState({
    validations: [...this.state.validations, ...validations]
  }, () => {
    // ... Do something
  });

if(验证[fieldId].filter(v=>v.message=='your message')。长度==0){
这是我的国家({
验证:{
…验证,
[fieldId]:[…验证[fieldId],{message:'your message',isError:true}]
}
})
}

通过这种方式,当您需要读取特定fieldId上的所有验证时,您可以直接说:


this.state.validations[fieldId]


您可以从现有的状态验证数组中创建一组键,其中每个键都是
消息| fieldId
格式的字符串,而不是再次筛选fieldId上的数组。

。然后,您可以根据先前创建的集合中是否存在新验证消息的键,通过从
验证中过滤出元素来创建新数组:

const stateValidations=[
{消息:“你好”,isError:true,fieldId:87},
{消息:'world',iError:true,fieldId:87},
{消息:'hi',isError:true,fieldId:88}
];
常量验证=[
{消息:“你好”,isError:true,fieldId:87},
{消息:'there',isError:true,fieldId:88}
];
const messageKey=({message,fieldId})=>`${message}|${fieldId}`;
const existing=新集合(stateValidations.map(messageKey));
const res=[…stateValidations,…validations.filter(v=>!existing.has(messageKey(v)))];

控制台日志(res)首先,我们需要解决一些问题。setState是异步的,因此调用setState并传入一个依赖于前一个状态的值是一个潜在的陷阱

因此,与其这样做,不如:
this.setState({value:…this.state.value})

我们需要将setState与更新程序函数一起使用,如下所示:
this.setState(prevState=>({value:…prevState.value}))

接下来,让我们通过筛选新的验证来解决问题,方法是在prevState.validations中查找匹配项

    this.setState(prevState => {
      let toAdd = validations.filter(
        item =>
          undefined ===
          prevState.validations.find(
            prevItem => item.message === prevItem.message && item.fieldId === prevItem.fieldId
          )
      );
      return [...prevState.validations, ...toAdd];
    });

解决方案非常简单

  • 找出一个项目的独特之处
  • 在现有项目上循环并添加(如果不重复)。如果重复,请使用新项目,并缩短新阵列以提高性能
  • 添加所有剩余项目

  • 如果项目已存在,则必须将筛选条件更改为不包含该项目。现在情况正好相反。@Nikhil啊,是的!谢谢你抓住了!我已经更新了代码。对于未来的读者:这个解决方案展示了如何创建一个
    ,并使用它来过滤验证。这是执行简单任务的一种不同但迂回的方法,它涉及到创建
    集时不必要的内存分配。如果继续,那么最好将状态验证更改为
    而不是数组。@Nikhil我不知道为什么要使用术语“环岛”和“不必要”。这种方法有O(n+m)运行时间,折衷是为集合提供额外的空间,而使用
    find
    会导致O(nm)运行时间(尽管在实际情况下,对象的数量肯定不足以产生差异)。我也不确定将状态验证更改为<代码> SET>代码>。当我们考虑<代码> SETS.HASE()>代码>操作时,该方法具有<代码> O(n+m)< /代码>时间复杂度,为常数时间<代码> O(1)< /代码>。尽管通常是这样,ECMA规范要求实现是这样的,这使得您的时间复杂性
    O(mn)
    。您可以在where
    find()。此外,此解决方案需要为
    Set
    提供额外的空间。这就是使用这些术语的原因。我建议将状态验证更改为
    Set
    以减少检查f的代码行