Как разбить на l oop используя состояние - PullRequest
0 голосов
/ 07 мая 2020

У меня есть код, как показано ниже. Мне нужно разбить l oop, когда найдено первое совпадение. Состояние

 const [isCodeValid, setIsCodeValid] = useState(false);
      for (let i = 0; i < properyIds.length; i++) {
        if (isCodeValid) {
          break; // this breaks it but had to click twice so state would update
        }
        if (!isCodeValid) {
          firestore().collection(`properties`)
            .doc(`${properyIds[i]}`)
            .collection('companies').get()
            .then(companies => {
              companies.forEach(company => {
                if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
                  console.log("should break here")
                  // updating state like this wont take effect right away
                  // it shows true on second time click. so user need to click twice right now. 
                  setIsCodeValid(true);   
                }
              });
            })
        }
      }

не обновляется сразу, поэтому if (!isCodeValid) работает только при втором щелчке.

Как только я нахожу совпадение, мне нужно обновить состояние или переменную, чтобы я мог сломать for l oop.

Я пытался использовать переменную, но ее значение также не менялось в условии final if. Интересно, в чем причина? кто-нибудь может объяснить?

Ответы [ 5 ]

2 голосов
/ 07 мая 2020

Вам следует попробовать переписать свой код так, чтобы вы всегда вызывали setIsCodeValid(value) один раз. В вашем случае он может вызываться несколько раз, и он может вообще не вызываться

 const [isCodeValid, setIsCodeValid] = useState(false);

 function checkForValidCode() {
    // map to an array of promises for companies[]
    const companiesPromises = properyIds.map(propertyId => 
          firestore()
            .collection(`properties`)
            .doc(propertyId)
            .collection('companies').get())

    Promise.all(companiesPromises)
        // flatten the 2d array to single array, re-create to JS array because of firestores internal types?
        .then(companiesArray => [...companiesArray].flatMap(v => v)) 
        // go through all companies to find a match
        .then(companies => 
            companies.find(
                company => _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
             ))
        .then(foundCompany => {
            // code is valid if we found a matching company
            setIsCodeValue(foundCompany !== undefined)
        })
 }
2 голосов
/ 07 мая 2020

Попробуйте что-то вроде этого:

import { useState } from 'react';

function YourComponent({ properyIds }) {
  const [isCodeValid, setIsCodeValid] = useState(false);

  async function handleSignupClick() {
    if (isCodeValid) {
      return;
    }

    for (let i = 0; i < properyIds.length; i++) {
      const companies = await firestore()
        .collection(`properties`)
        .doc(`${properyIds[i]}`)
        .collection('companies')
        .get();
      for (const company of companies.docs) {
        if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
          setIsCodeValid(true);
          return;
        }
      }
    }
  }

  return (<button onClick={handleSignupClick}>Sign Up</button>);
}

Если вы дождетесь этих проверок, это позволит вам последовательно выполнить l oop и выйти из него простым return, чего вы не можете сделать внутри обратного вызова. Обратите внимание: если это выполняет запросы к базе данных, вам, вероятно, следует показать ожидающую обратную связь, пока это происходит, чтобы пользователь знал, что щелчок что-то сделал.

Обновить :

Вы может захотеть провести все эти проверки параллельно, если это возможно, чтобы пользователю не пришлось ждать. Зависит от вашей ситуации. Вот как бы вы это сделали.

async function handleSignupClick() {
  if (isCodeValid) {
    return;
  }

  const allCompanies = await Promise.all(
    properyIds.map(id => firestore()
      .collection(`properties`)
      .doc(`${properyIds[i]}`)
      .collection('companies')
      .get()
    )
  );

  setIsCodeValid(
    allCompanies.some(companiesSnapshot => 
      companiesSnapshot.docs.some(company => 
        _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
      )
    )
  );
}
0 голосов
/ 07 мая 2020

Я устал ниже и у меня получилось сломать l oop.

Я объявил и попытался изменить эту переменную let codeValid, и она просто не обновляла свое значение при обнаружении совпадения. (не знаю почему)

Но внезапно я попробовал, и он просто сработал.

Я не менял никакого кода, кроме переменной.

   let codeValid = false;
      let userInformation = []
      for (let i = 0; i < properties.length; i++) {
        console.log("called")
        const companies = await firestore().collection(`properties`)
          .doc(`${properties[i].id}`)
          .collection('companies').get()
          .then(companies => {
            companies.forEach(company => {
              if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
                //     a += 1;
                codeValid = true;
                userInformation.registrationCode = registrationCode.toUpperCase();
                userInformation.companyName = company.data().companyName;
                userInformation.propertyName = properties[i].propertyName;
              }

            });
          })
        if (codeValid) {
          break;
        }
      }
0 голосов
/ 07 мая 2020

Используйте some :

companies.some(company => {
   return _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase());
});

Если some и forEach недоступны, тогда companies не массив, а объект, подобный массиву. Чтобы перебрать их, мы можем использовать for of l oop:

for (const company of companies){
   if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
      // do something
      break;
   }
}
0 голосов
/ 07 мая 2020

Можно не сломать после setIsCodeValid(true);?

...