Простой способ проверить, существует ли массив объектов в массиве объектов перед установкой состояния React JS - PullRequest
1 голос
/ 25 сентября 2019

Рассмотрим следующее:

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

Где я делаю: [...this.state.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}, 
  ...
]

Я хотел бы сделать фильтр this.state.validations на основе сообщения и fieldId в validations и сказать:

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

Есть ли простой, не беспорядочный способ сделать это, где я мог бы использовать фильтр или что-то еще, чтобы циклически проверять состояния и проверки, сравнивая и fieldId и сообщение, и если это не таксуществует: добавить?

Ответы [ 5 ]

1 голос
/ 25 сентября 2019

Ну, во-первых, нам нужно что-то исправить.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 голос
/ 25 сентября 2019

Вы можете создать Set «ключей» из существующего массива проверок состояния, где каждый ключ является строкой вида 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);
1 голос
/ 25 сентября 2019

Вы можете проверить, существует ли каждая проверка, используя 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));
0 голосов
/ 25 сентября 2019

Решение довольно простое,

  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 

0 голосов
/ 25 сентября 2019

Один из лучших способов структурировать валидации как объект вместо массива

например,

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

С этой структурой вы можете ясно видеть с помощьюодин идентификатор поля, какие все проверки присутствуют.

Теперь, чтобы выяснить, происходит ли проверка уже в fieldId, U может сделать следующее:

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

таким образом, когда вам нужно прочитать все проверки для определенного fieldId, вы можете прямо сказать:

this.state.validations[fieldId]

вместо повторной фильтрации массива по fieldId.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...