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

Easy way to check if array of objects exists in array of objects before setting state React JS

考虑以下因素:

  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 中的消息和 fieldId 过滤 this.state.validations 并说:

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

有没有一种简单的方法可以做到这一点,我可以使用过滤器或其他东西来循环状态验证和比较 fieldId 和消息的验证,如果它不存在:添加它?

您可以使用 Array.find() 验证每个验证是否已存在,如果不存在则仅添加到状态验证。

var stateValidations = [
  {message: 'hello', isError: true, fieldId: 87}, 
  {message: 'hello', isError: true, fieldId: 42}, 
  {message: 'error', isError: true, fieldId: 95}, 
];

var validations = [
  {message: 'hello', isError: true, fieldId: 42}, // Already exists.
  {message: 'hello', isError: true, fieldId: 101} // New item.
];

// Check if each validation already exists, and only add if doesn't exist.
validations.forEach(validation => {
  const found = stateValidations.find(item => item.message === validation.message 
    && item.fieldId === validation.fieldId);

  if (!found) {
    // If not found, add validation.
    stateValidations.push(validation);
  }
});

console.log(JSON.stringify(stateValidations));

将验证结构化为对象而不是数组的更好方法之一

例如

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

通过这种结构,您可以通过一个字段 Id 清楚地看到所有验证都存在。

现在要查明是否已对 fieldId 进行验证,您可以执行以下操作:

if (validations[fieldId].filter(v => v.message === 'your message').length === 0) { this.setState({ validations: { ...validations, [fieldId]: [...validations[fieldId], { message: 'your message', isError: true }] } }) }

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

this.state.validations[fieldId]

而不是再次根据 fieldId 过滤数组。

您可以从现有的状态验证数组中创建 Set of "keys",其中每个键都是 message|fieldId 形式的字符串。然后,您可以根据新验证消息的键是否存在于先前创建的集合中,通过过滤掉 validations 中的元素来创建新数组:

const stateValidations = [
  {message: 'hello', isError: true, fieldId: 87},
  {message: 'world', isError: true, fieldId: 87},
  {message: 'hi', isError: true, fieldId: 88}
];
const validations = [
  {message: 'hello', isError: true, fieldId: 87},
  {message: 'there', isError: true, fieldId: 88}
];

const messageKey = ({message, fieldId}) => `${message}|${fieldId}`;
const existing = new Set(stateValidations.map(messageKey));

const res = [...stateValidations, ...validations.filter(v => !existing.has(messageKey(v)))];
console.log(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];
    });

解决方案非常简单,

  1. 找到使项目独一无二的原因
  2. 遍历现有项目,如果不重复则添加。如果重复使用新项目并缩短新数组以提高性能
  3. 添加所有剩余项目
const stateValidations = [
  {message: 'hello', isError: true, fieldId: 85},
  {message: 'world', isError: true, fieldId: 86},
  {message: 'hi', isError: true, fieldId: 88}
];
const validations = [
  {message: 'hello', isError: true, fieldId: 87},
  {message: 'there', isError: true, fieldId: 88}
];

let newValidations = stateValidations.reduce((acc, curr)=>{
  let haveNewvalidation = validations.findIndex((v)=>v.fieldId===curr.fieldId);
  if(haveNewvalidation !=-1){
    acc.push(validations[haveNewvalidation]);
    // this will improve findIndex performance
    validations.splice(haveNewvalidation,1);

  } else  {
    acc.push(curr);
  }
  return acc;
}, [])

// push remaining validations
newValidations.push(...validations)

console.log(newValidations)```

Demo: https://repl.it/@abhirathore2006/mergeTwoArrays